From 497e74fae727a04ca5c0da61825b66e047c6f909 Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Fri, 27 Oct 2023 11:04:35 +1100 Subject: [PATCH] add multi writer table --- main.go | 284 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 173 insertions(+), 111 deletions(-) diff --git a/main.go b/main.go index 2eba836..ae4bd37 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,6 @@ import ( "log" "net/url" "os" - "reflect" "strings" "time" _ "time/tzdata" @@ -21,17 +20,19 @@ import ( "github.com/vmware/govmomi/vim25/types" "github.com/PuerkitoBio/goquery" + goconfluence "github.com/virtomize/confluence-go-api" ) var ( - c *govmomi.Client - ctx context.Context - cancel context.CancelFunc - sha1ver string // sha1 revision used to build the program - buildTime string // when the executable was built - busSharingResults []BusSharingResults - location *time.Location + c *govmomi.Client + ctx context.Context + cancel context.CancelFunc + 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 { @@ -41,26 +42,11 @@ type BusSharingResults struct { 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 @@ -78,14 +64,14 @@ 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("getScsiBusSharingVMs : Preparing views\n") + fmt.Printf("processVMs : Preparing views\n") // Get a view of all the VMs vms, err := m.CreateContainerView(ctx, client.ServiceContent.RootFolder, []string{"VirtualMachine"}, true) @@ -160,6 +146,7 @@ func getScsiBusSharingVMs(client *govmomi.Client) error { if 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) controller := scsi.GetVirtualSCSIController() @@ -177,6 +164,29 @@ 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 + sharingType := backing.(*types.VirtualDiskFlatVer2BackingInfo).Sharing + + if sharingType == "sharingMultiWriter" { + fmt.Printf("VM %s is using MultiWriter on disk %ss\n", vm.Name, diskLabel) + + result := MultiWriterResults{ + VmName: vm.Name, + ClusterName: clusterName, + DiskLabel: diskLabel, + SharingType: sharingType, + } + multiWriterResults = append(multiWriterResults, result) + } } } } @@ -212,7 +222,29 @@ func generateBusSharingTable() string { fmt.Printf("generateBusSharingTable : %s\n", htmlString) return htmlString +} +func generatMultiWriterTable() string { + // Define the HTML template + htmlTemplate := `{{range .}}{{end}}
Vm NameCluster NameDisk LabelSharing Type
{{.VmName}}{{.ClusterName}}{{.DiskLabel}}{{.SharingType}}
` + + // 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("generatMultiWriterTable : %s\n", htmlString) + + return htmlString } func updateHtml(htmlContent string, heading string, newTable string) string { @@ -251,6 +283,108 @@ func updateHtml(htmlContent string, heading string, newTable string) string { 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 := generatMultiWriterTable() + 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() { // Command line flags vURL := flag.String("url", "", "The URL of a vCenter server, eg https://server.domain.example/sdk") @@ -259,13 +393,12 @@ func main() { 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") - 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") + 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") - //vmName := flag.String("vmname", "example-vm", "The vm to query metrics") - //begin := flag.Duration("b", time.Hour, "Begin time") // default BeginTime is 1h ago + flag.Parse() if len(*vURL) == 0 { @@ -316,11 +449,11 @@ func main() { } defer c.Logout(ctx) - // Find scsi bus sharing VMs - err = getScsiBusSharingVMs(c) + // Find scsi bus sharing and multi writer VMs + err = processVMs(c) if err != nil { - log.Printf("Error retrieving list of VMs with SCSI Bus Sharing : %s\n", err) - return + log.Printf("Error processing list of VMs : %s\n", err) + os.Exit(1) } // Connect to confluence @@ -332,78 +465,7 @@ func main() { return } - // get current user information - /* - currentUser, err := api.CurrentUser() - if err != nil { - fmt.Println(err) - return - } - fmt.Printf("%+v\n", currentUser) - */ + updateConfluenceBusSharing(api, vCenterHostname, *cBusSharingId, *cSpaceKey) + updateConfluenceMultiWriter(api, vCenterHostname, *cMultiWriterId, *cSpaceKey) - // get content by content id - c, err := api.GetContentByID(*cPageId, goconfluence.ContentQuery{ - SpaceKey: *cSpaceKey, - 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) - - //dummyTable := "
VM NameCluster Name
VM1Cluster1
" - newTable := generateBusSharingTable() - newContent := updateHtml(c.Body.Storage.Value, vCenterHostname, newTable) - fmt.Printf("New Content: %v\n", newContent) - - data := &goconfluence.Content{ - ID: *cPageId, - Type: "page", - Title: c.Title, - Body: goconfluence.Body{ - Storage: goconfluence.Storage{ - Value: newContent, - Representation: "storage", - }, - }, - Version: &goconfluence.Version{ - Number: newVersion, - }, - Space: &goconfluence.Space{ - Key: *cSpaceKey, - }, - } - //c.Body.Storage.Value = newContent - 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) - - /* - err = getScsiBusSharingVMs(c) - if err != nil { - log.Printf("Error retrieving list of VMs with SCSI Bus Sharing : %s\n", err) - return - } - - // Output final results in JSON - if len(busSharingResults) > 0 { - j, _ := json.Marshal(busSharingResults) - fmt.Println(string(j)) - } else { - fmt.Println("{}") - } - */ }