Compare commits

...

24 Commits

Author SHA1 Message Date
Nathan Coad
2b989aeb7c tweak logging messages
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-30 09:48:32 +11:00
Nathan Coad
460178ef18 allow secrets via env variables
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-30 09:11:23 +11:00
c01000e7bd [ci skip] fix typo 2023-10-27 14:55:22 +11:00
c395cc79d2 missed one
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-27 12:23:42 +11:00
f6fd06a1b7 reduce debugging output
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-27 12:20:45 +11:00
1258a895cc reduce properties retrieved, try to reduce memory usage
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-27 12:16:27 +11:00
61ac749d86 remove extra logging
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-27 12:04:39 +11:00
a81f8e044c handle rdm disks
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-27 11:59:11 +11:00
497e74fae7 add multi writer table
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-27 11:04:35 +11:00
b7df8b46a4 turn off extra logging
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 17:03:49 +11:00
bcd2e37b8c try to avoid segv
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 16:52:26 +11:00
10c2173421 smarter err handling
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 16:43:02 +11:00
ac62e71236 more debugging
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 16:41:53 +11:00
0fcbed1465 re-use title from previous content
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 16:16:00 +11:00
220eca018c try calculating version number
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 15:41:28 +11:00
9741c91af2 try not to panic
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 15:28:21 +11:00
85a054fcc7 troubleshoot version reference
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 15:19:56 +11:00
1d1376ee5f define more properties of new confluence object
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 15:08:06 +11:00
f28958cdd0 try generating new confluence content object
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 14:56:08 +11:00
28c533a5ec really update content
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 14:46:41 +11:00
579b08162a bugfix
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 14:39:51 +11:00
8eb3aaf4ed try generating real table
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 14:32:01 +11:00
1d8ddb7aca test updating content
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 14:11:05 +11:00
3138c63e34 print user info
All checks were successful
continuous-integration/drone/push Build is passing
2023-10-26 13:34:35 +11:00
3 changed files with 373 additions and 109 deletions

3
go.mod
View File

@@ -5,6 +5,9 @@ go 1.21.0
require github.com/vmware/govmomi v0.32.0
require (
github.com/PuerkitoBio/goquery v1.8.1 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/magefile/mage v1.14.0 // indirect
github.com/virtomize/confluence-go-api v1.4.6 // indirect
golang.org/x/net v0.7.0 // indirect
)

35
go.sum
View File

@@ -1,3 +1,7 @@
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -17,5 +21,36 @@ github.com/virtomize/confluence-go-api v1.4.6 h1:yN1khm2tU0aFc7N7x58QQ+668rko77q
github.com/virtomize/confluence-go-api v1.4.6/go.mod h1:a96WPcok5g+7l5LC/ztcrp4cLmrIA1DHxxZSv/iqvsQ=
github.com/vmware/govmomi v0.32.0 h1:Rsdi/HAX5Ebf9Byp/FvBir4sfM7yP5DBUeRlbC6vLBo=
github.com/vmware/govmomi v0.32.0/go.mod h1:JA63Pg0SgQcSjk+LuPzjh3rJdcWBo/ZNCIwbb1qf2/0=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

362
main.go
View File

@@ -1,12 +1,15 @@
package main
import (
"bytes"
"context"
"flag"
"fmt"
"html/template"
"log"
"net/url"
"os"
"reflect"
"strings"
"time"
_ "time/tzdata"
@@ -16,6 +19,8 @@ import (
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"github.com/PuerkitoBio/goquery"
goconfluence "github.com/virtomize/confluence-go-api"
)
@@ -26,37 +31,22 @@ var (
sha1ver string // sha1 revision used to build the program
buildTime string // when the executable was built
busSharingResults []BusSharingResults
multiWriterResults []MultiWriterResults
location *time.Location
)
type BusSharingResults struct {
Vcenter string
VmName string
ClusterName string
ControllerName string
SharingType string
}
/*
const (
// The virtual disk is not shared.
VirtualDiskSharingSharingNone = VirtualDiskSharing("sharingNone")
// The virtual disk is shared between multiple virtual machines.
VirtualDiskSharingSharingMultiWriter = VirtualDiskSharing("sharingMultiWriter")
)
*/
// From https://stackoverflow.com/a/33769379
func Scan(d interface{}) {
v := reflect.ValueOf(d)
i := reflect.Indirect(v)
s := i.Type()
println(s.NumField()) // will print out 0, if you change Host to have 1 field, it prints out 1
}
func query(t reflect.Type) {
value := reflect.New(t).Interface()
Scan(value)
type MultiWriterResults struct {
VmName string
ClusterName string
DiskLabel string
SharingType string
}
// Thanks chatgpt
@@ -74,15 +64,16 @@ func sharedBusToString(sharedBus types.VirtualSCSISharing) string {
}
}
func getScsiBusSharingVMs(client *govmomi.Client) error {
func processVMs(client *govmomi.Client) error {
var clusterName string
ctx := context.Background()
m := view.NewManager(client.Client)
//f := find.NewFinder(client.Client, true)
pc := property.DefaultCollector(client.Client)
fmt.Printf("processVMs : Preparing views\n")
// Get a view of all the VMs
fmt.Printf("Getting VM listing\n")
vms, err := m.CreateContainerView(ctx, client.ServiceContent.RootFolder, []string{"VirtualMachine"}, true)
if err != nil {
return err
@@ -90,7 +81,6 @@ func getScsiBusSharingVMs(client *govmomi.Client) error {
defer vms.Destroy(ctx)
// Get a view of all the hosts
fmt.Printf("Getting host listing\n")
hs, err := m.CreateContainerView(ctx, client.ServiceContent.RootFolder, []string{"HostSystem"}, true)
if err != nil {
return err
@@ -98,8 +88,9 @@ func getScsiBusSharingVMs(client *govmomi.Client) error {
defer hs.Destroy(ctx)
// Retrieve all the VMs
fmt.Printf("Getting VM listing\n")
var vmList []mo.VirtualMachine
err = vms.Retrieve(ctx, []string{"VirtualMachine"}, nil, &vmList)
err = vms.Retrieve(ctx, []string{"VirtualMachine"}, []string{"summary", "config", "name"}, &vmList)
if err != nil {
log.Printf("Error retrieving vm list : '%s'\n", err)
return err
@@ -107,8 +98,9 @@ func getScsiBusSharingVMs(client *govmomi.Client) error {
fmt.Printf("Found %d VMs\n", len(vmList))
// Retrieve all the hosts
fmt.Printf("Getting host listing\n")
var hsList []mo.HostSystem
err = hs.Retrieve(ctx, []string{"HostSystem"}, nil, &hsList)
err = hs.Retrieve(ctx, []string{"HostSystem"}, []string{"name", "parent"}, &hsList)
if err != nil {
log.Printf("Error retrieving hostsystem list : '%s'\n", err)
return err
@@ -117,7 +109,7 @@ func getScsiBusSharingVMs(client *govmomi.Client) error {
// Iterate through VMs and check for SCSI bus sharing
for _, vm := range vmList {
fmt.Printf("vm : %s [%s]\n", vm.Name, vm.Summary.Runtime.Host)
//fmt.Printf("vm : %s [%s]\n", vm.Name, vm.Summary.Runtime.Host)
//fmt.Printf("vm parent: %v\n", vm.Parent)
/*
@@ -135,12 +127,14 @@ func getScsiBusSharingVMs(client *govmomi.Client) error {
// Determine cluster based on runtime host of VM based on https://github.com/vmware/govmomi/issues/1242#issuecomment-427671990
for _, host := range hsList {
if host.Reference() == *vm.Summary.Runtime.Host {
fmt.Printf("host %s matches with parent %s\n", host.Name, host.Parent)
//fmt.Printf("host %s matches, host parent %s\n", host.Name, host.Parent)
var cluster mo.ManagedEntity
err = pc.RetrieveOne(ctx, *host.Parent, []string{"name"}, &cluster)
if err != nil {
log.Fatal(err)
log.Printf("Error retrieving cluster object : '%s'\n", err)
clusterName = ""
break
}
//fmt.Println(cluster.Name)
clusterName = cluster.Name
@@ -148,16 +142,18 @@ func getScsiBusSharingVMs(client *govmomi.Client) error {
}
}
if len(vm.Config.Hardware.Device) > 0 {
if vm.Config != nil && len(vm.Config.Hardware.Device) > 0 {
for _, device := range vm.Config.Hardware.Device {
//fmt.Printf("device: %v\n", device)
//fmt.Println("Type of variable1:", reflect.TypeOf(device))
if scsi, ok := device.(types.BaseVirtualSCSIController); ok {
fmt.Printf("scsi: %v\n", scsi)
//fmt.Printf("scsi: %v\n", scsi)
controller := scsi.GetVirtualSCSIController()
//fmt.Printf("controller: %s\n", device.GetVirtualDevice().DeviceInfo.GetDescription().Label)
fmt.Printf("VM %s is using SCSI bus sharing mode: %s\n", vm.Name, string(controller.SharedBus))
//fmt.Printf("VM %s is using SCSI bus sharing mode: %s\n", vm.Name, string(controller.SharedBus))
if controller.SharedBus != "noSharing" {
fmt.Printf("VM %s is using SCSI bus sharing mode: %s\n", vm.Name, string(controller.SharedBus))
result := BusSharingResults{
VmName: vm.Name,
ClusterName: clusterName,
@@ -167,50 +163,289 @@ func getScsiBusSharingVMs(client *govmomi.Client) error {
busSharingResults = append(busSharingResults, result)
}
} else if vdisk, ok := device.(*types.VirtualDisk); ok {
//fmt.Printf("vdisk: %v\n", vdisk)
// See https://github.com/vmware/govmomi/blob/main/object/virtual_device_list_test.go for info
diskLabel := vdisk.VirtualDevice.DeviceInfo.GetDescription().Label
// See https://github.com/vmware/govmomi/blob/main/vim25/types/enum.go#L7538
// Sharing can be sharingNone or sharingMultiWriter
backing := vdisk.VirtualDevice.Backing
//fmt.Println("Type of backing:", reflect.TypeOf(backing))
// make sure we have a regular disk, not an RDM which has type VirtualDiskRawDiskMappingVer1BackingInfo
if info, ok := backing.(*types.VirtualDiskFlatVer2BackingInfo); ok {
sharingType := info.Sharing
if sharingType == "sharingMultiWriter" {
fmt.Printf("VM %s is using MultiWriter on disk %s\n", vm.Name, diskLabel)
result := MultiWriterResults{
VmName: vm.Name,
ClusterName: clusterName,
DiskLabel: diskLabel,
SharingType: sharingType,
}
multiWriterResults = append(multiWriterResults, result)
}
}
}
}
} else if vm.Config == nil {
fmt.Printf("vm %s has no config\n", vm.Name)
} else {
fmt.Printf("vm %s is something strange\n", vm.Name)
}
}
return nil
}
func main() {
// Command line flags
func generateBusSharingTable() string {
// Define the HTML template
htmlTemplate := `<table><tbody><tr><th>VM Name</th><th>Cluster Name</th><th>Controller Name</th><th>Sharing Type</th></tr>{{range .}}<tr><td>{{.VmName}}</td><td>{{.ClusterName}}</td><td>{{.ControllerName}}</td><td>{{.SharingType}}</td></tr>{{end}}</tbody></table>`
// Create a new template and parse the HTML template
tmpl := template.Must(template.New("table").Parse(htmlTemplate))
// Create a buffer to store the HTML output
var buf bytes.Buffer
// Execute the template with the results and write to the buffer
err := tmpl.Execute(&buf, busSharingResults)
if err != nil {
panic(err)
}
// Convert the buffer to a string
htmlString := buf.String()
fmt.Printf("generateBusSharingTable : %s\n", htmlString)
return htmlString
}
func generateMultiWriterTable() string {
// Define the HTML template
htmlTemplate := `<table><tbody><tr><th>VM Name</th><th>Cluster Name</th><th>Disk Label</th><th>Sharing Type</th></tr>{{range .}}<tr><td>{{.VmName}}</td><td>{{.ClusterName}}</td><td>{{.DiskLabel}}</td><td>{{.SharingType}}</td></tr>{{end}}</tbody></table>`
// Create a new template and parse the HTML template
tmpl := template.Must(template.New("table").Parse(htmlTemplate))
// Create a buffer to store the HTML output
var buf bytes.Buffer
// Execute the template with the results and write to the buffer
err := tmpl.Execute(&buf, multiWriterResults)
if err != nil {
panic(err)
}
// Convert the buffer to a string
htmlString := buf.String()
fmt.Printf("generateMultiWriterTable : %s\n", htmlString)
return htmlString
}
func updateHtml(htmlContent string, heading string, newTable string) string {
// Load the HTML content into a goquery document
doc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlContent))
if err != nil {
fmt.Println(err)
return htmlContent
}
// Find the h2 heading that matches our heading passed to the function
doc.Find("h2").Each(func(i int, s *goquery.Selection) {
if s.Text() == heading {
fmt.Printf("Found h2 element matching '%s'\n", heading)
// Find the table that follows this h2 heading
table := s.NextFiltered("table")
// Replace the table with a new table
newTable, _ := goquery.NewDocumentFromReader(strings.NewReader(newTable))
table.ReplaceWithSelection(newTable.Selection)
}
})
// Render the html
h, err := doc.Html()
if err != nil {
fmt.Println(err)
return htmlContent
}
// goquery produces implicit nodes when parsing the input html, remove them now
//fmt.Printf("updateHtml whole doc : %s\n", h)
h = strings.Replace(h, "<html><head></head><body>", "", -1)
h = strings.Replace(h, "</body></html>", "", -1)
return h
}
func updateConfluenceBusSharing(api *goconfluence.API, vCenterHostname string, pageId string, spaceKey string) {
// get content by content id
c, err := api.GetContentByID(pageId, goconfluence.ContentQuery{
SpaceKey: spaceKey,
Expand: []string{"body.storage", "version"},
})
if err != nil {
fmt.Println(err)
return
}
//fmt.Printf("%+v\n", c)
//fmt.Printf("Current version number : '%d'\n", c.Version.Number)
newVersion := c.Version.Number + 1
// Generate new content for confluence
//fmt.Printf("Current content: %s\n", c.Body.Storage.Value)
newTable := generateBusSharingTable()
newContent := updateHtml(c.Body.Storage.Value, vCenterHostname, newTable)
//fmt.Printf("New Content: %v\n", newContent)
data := &goconfluence.Content{
ID: pageId,
Type: "page",
Title: c.Title,
Body: goconfluence.Body{
Storage: goconfluence.Storage{
Value: newContent,
Representation: "storage",
},
},
Version: &goconfluence.Version{
Number: newVersion,
},
Space: &goconfluence.Space{
Key: spaceKey,
},
}
//fmt.Printf("confluence object : '%v'\n", data)
result, err := api.UpdateContent(data)
if err != nil {
fmt.Printf("Error updating content: %s\n", err)
return
}
fmt.Printf("result: %v\n", result)
}
func updateConfluenceMultiWriter(api *goconfluence.API, vCenterHostname string, pageId string, spaceKey string) {
// get content by content id
c, err := api.GetContentByID(pageId, goconfluence.ContentQuery{
SpaceKey: spaceKey,
Expand: []string{"body.storage", "version"},
})
if err != nil {
fmt.Println(err)
return
}
//fmt.Printf("%+v\n", c)
//fmt.Printf("Current version number : '%d'\n", c.Version.Number)
newVersion := c.Version.Number + 1
// Generate new content for confluence
//fmt.Printf("Current content: %s\n", c.Body.Storage.Value)
newTable := generateMultiWriterTable()
newContent := updateHtml(c.Body.Storage.Value, vCenterHostname, newTable)
//fmt.Printf("New Content: %v\n", newContent)
data := &goconfluence.Content{
ID: pageId,
Type: "page",
Title: c.Title,
Body: goconfluence.Body{
Storage: goconfluence.Storage{
Value: newContent,
Representation: "storage",
},
},
Version: &goconfluence.Version{
Number: newVersion,
},
Space: &goconfluence.Space{
Key: spaceKey,
},
}
//fmt.Printf("confluence object : '%v'\n", data)
result, err := api.UpdateContent(data)
if err != nil {
fmt.Printf("Error updating content: %s\n", err)
return
}
fmt.Printf("result: %v\n", result)
}
/*
func updateConfluencePage(api *goconfluence.API, vCenterHostname string, pageId string, spaceKey string, newContent string, newVersion int) {
}
*/
func main() {
var err error
// Command line flags
vURL := flag.String("url", "", "The URL of a vCenter server, eg https://server.domain.example/sdk")
vUser := flag.String("user", "", "The username to use when connecting to vCenter")
vPass := flag.String("password", "", "The password to use when connecting to vCenter")
vInsecure := flag.Bool("insecure", true, "Allow insecure connections to vCenter")
*/
vTZ := flag.String("tz", "Australia/Sydney", "The timezone to use when converting vCenter UTC times")
vTZ := flag.String("tz", "Australia/Sydney", "The timezone to use when converting vCenter UTC times")
cURL := flag.String("confluence-url", "https://confluence.yourdomain.com/wiki/rest/api", "The URL to your confluence rest API endpoint")
cToken := flag.String("confluence-token", "", "Your Confluence Personal Access Token")
cPageId := flag.String("confluence-pageid", "", "The page ID to update with the report")
//vmName := flag.String("vmname", "example-vm", "The vm to query metrics")
//begin := flag.Duration("b", time.Hour, "Begin time") // default BeginTime is 1h ago
cBusSharingId := flag.String("confluence-bussharing-pageid", "", "The page ID for the VMs with Bus Sharing report")
cMultiWriterId := flag.String("confluence-multiwriter-pageid", "", "The page ID for the VMs with MultiWriter report")
cSpaceKey := flag.String("confluence-spacekey", "HCS", "The confluence space key to use")
flag.Parse()
// Print logs to file
/*
f, err := os.OpenFile("log.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
defer f.Close()
log.SetOutput(f)
*/
log.Printf("Starting execution. Built on %s from sha1 %s\n", buildTime, sha1ver)
fmt.Printf("Starting execution. Built on %s from sha1 %s\n", buildTime, sha1ver)
if len(*vURL) == 0 {
panic("Unable to connect to empty vCenter URL")
}
// Look for credentials from environment variables
val, present := os.LookupEnv("VCENTER_USER")
if present {
fmt.Println("Loaded vcenter user from environment variable")
*vUser = val
}
val, present = os.LookupEnv("VCENTER_PASS")
if present {
fmt.Println("Loaded vcenter password from environment variable")
*vPass = val
}
val, present = os.LookupEnv("CONFLUENCE_TOKEN")
if present {
fmt.Println("Loaded confluence Personal Access Token from environment variable")
*cToken = val
}
// So we can convert vCenter UTC to our local timezone
log.Printf("Setting timezone to '%s'\n", *vTZ)
fmt.Printf("Setting timezone to '%s'\n", *vTZ)
location, err = time.LoadLocation(*vTZ)
if err != nil {
fmt.Fprintf(os.Stderr, "Error setting timezone to %s : %s\n", *vTZ, err)
os.Exit(1)
}
/*
u, err := url.Parse(*vURL)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing url %s : %s\n", *vURL, err)
@@ -221,8 +456,9 @@ func main() {
log.Printf("Updated vCenter URL to '%v'\n", u)
}
}
vCenterHostname := u.Host
log.Printf("Connecting to vCenter %s\n", u)
fmt.Printf("Connecting to vCenter %s\n", u)
u.User = url.UserPassword(*vUser, *vPass)
ctx, cancel = context.WithCancel(context.Background())
@@ -235,37 +471,27 @@ func main() {
os.Exit(1)
}
defer c.Logout(ctx)
*/
// Find scsi bus sharing and multi writer VMs
err = processVMs(c)
if err != nil {
fmt.Printf("Error processing list of VMs : %s\n", err)
os.Exit(1)
}
// Connect to confluence
if len(*cURL) > 0 && len(*cToken) > 0 {
fmt.Printf("Connecting to confluence %s\n", *cURL)
api, err := goconfluence.NewAPI(*cURL, "", *cToken)
if err != nil {
log.Fatal(err)
}
// get content by content id
c, err := api.GetContentByID(*cPageId, goconfluence.ContentQuery{
SpaceKey: "HCS",
Expand: []string{"body.storage", "version"},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", c)
/*
err = getScsiBusSharingVMs(c)
if err != nil {
log.Printf("Error retrieving list of VMs with SCSI Bus Sharing : %s\n", err)
fmt.Println(err)
return
}
// Output final results in JSON
if len(busSharingResults) > 0 {
j, _ := json.Marshal(busSharingResults)
fmt.Println(string(j))
updateConfluenceBusSharing(api, vCenterHostname, *cBusSharingId, *cSpaceKey)
updateConfluenceMultiWriter(api, vCenterHostname, *cMultiWriterId, *cSpaceKey)
} else {
fmt.Println("{}")
fmt.Println("Not updating confluence, no details provided")
}
*/
}