diff --git a/main.go b/main.go index a246469..341281e 100644 --- a/main.go +++ b/main.go @@ -21,26 +21,32 @@ import ( ) 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 - results []DrsResults - 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 + location *time.Location ) -type DrsResults struct { - ClusterName string - DrsScore int32 - Vcenter string - NumVmsDrsBucket0To20 int32 - NumVmsDrsBucket21To40 int32 - NumVmsDrsBucket41To60 int32 - NumVmsDrsBucket61To80 int32 - NumVmsDrsBucket81To100 int32 +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) @@ -54,27 +60,90 @@ func query(t reflect.Type) { Scan(value) } +// Thanks chatgpt +// Refer also to https://github.com/vmware/govmomi/blob/v0.32.0/vim25/types/enum.go#L9704“ +func sharedBusToString(sharedBus types.VirtualSCSISharing) string { + switch sharedBus { + case types.VirtualSCSISharingNoSharing: + return "No Sharing" + case types.VirtualSCSISharingPhysicalSharing: + return "Physical" + case types.VirtualSCSISharingVirtualSharing: + return "Virtual" + default: + return "Unknown" + } +} + func getScsiBusSharingVMs(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) + // Get a view of all the VMs vms, err := m.CreateContainerView(ctx, client.ServiceContent.RootFolder, []string{"VirtualMachine"}, true) if err != nil { return err } defer vms.Destroy(ctx) - var vmList []mo.VirtualMachine + // Get a view of all the hosts + hs, err := m.CreateContainerView(ctx, client.ServiceContent.RootFolder, []string{"HostSystem"}, true) + if err != nil { + return err + } + defer hs.Destroy(ctx) + // Retrieve all the VMs + var vmList []mo.VirtualMachine err = vms.Retrieve(ctx, []string{"VirtualMachine"}, nil, &vmList) if err != nil { log.Printf("Error retrieving vm list : '%s'\n", err) return err } + // Retrieve all the hosts + var hsList []mo.HostSystem + err = hs.Retrieve(ctx, []string{"HostSystem"}, nil, &hsList) + if err != nil { + log.Printf("Error retrieving hostsystem list : '%s'\n", err) + return err + } + // Iterate through VMs and check for SCSI bus sharing for _, vm := range vmList { - fmt.Printf("vm: %s\n", vm.Name) + fmt.Printf("vm : %s [%s]\n", vm.Name, vm.Summary.Runtime.Host) + //fmt.Printf("vm parent: %v\n", vm.Parent) + + /* + // TODO : check for err + // Get the object for this VM + ref, _ := f.ObjectReference(ctx, vm.Entity().Self) + ovm, _ := ref.(*object.VirtualMachine) + + // Get the resource pool and the owner of it + pool, _ := ovm.ResourcePool(ctx) + owner, _ := pool.Owner(ctx) + fmt.Printf("owner: %v\n", owner) + */ + + // Determine cluster based on runtime host of VM + for _, host := range hsList { + if host.Reference() == *vm.Summary.Runtime.Host { + fmt.Printf("host %s matches with 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) + } + //fmt.Println(cluster.Name) + clusterName = cluster.Name + + } + } if len(vm.Config.Hardware.Device) > 0 { for _, device := range vm.Config.Hardware.Device { @@ -82,111 +151,23 @@ func getScsiBusSharingVMs(client *govmomi.Client) error { if scsi, ok := device.(types.BaseVirtualSCSIController); ok { fmt.Printf("scsi: %v\n", scsi) controller := scsi.GetVirtualSCSIController() + //fmt.Printf("controller: %s\n", device.GetVirtualDevice().DeviceInfo.GetDescription().Label) if controller.SharedBus != "noSharing" { - fmt.Printf("VM %s is using SCSI bus sharing mode: %v\n", vm.Name, controller.SharedBus) - } - } - } - } + fmt.Printf("VM %s is using SCSI bus sharing mode: %s\n", vm.Name, controller.SharedBus) - /* - // Retrieve VM's ConfigInfo - var configInfo types.VirtualMachineConfigInfo - err = property.DefaultCollector(client.Client).RetrieveOne(ctx, vm.Reference(), []string{"config"}, &configInfo) - if err != nil { - log.Fatal(err) - } - // Check if SCSI bus sharing is enabled - if configInfo != nil && configInfo.GetVmConfigInfo() != nil && configInfo.GetVmConfigInfo().GetHardware() != nil { - hardware := configInfo.GetVmConfigInfo().GetHardware() - if devices := hardware.GetDevice(); devices != nil { - for _, device := range devices { - if scsi, ok := device.(object.VirtualSCSIController); ok { - if scsi.SharedBus != nil && scsi.SharedBus.Value != "" { - fmt.Printf("VM %s is using SCSI bus sharing mode: %s\n", vm.Name, scsi.SharedBus.Value) - } - } + result := BusSharingResults{ + VmName: vm.Name, + ClusterName: clusterName, + ControllerName: device.GetVirtualDevice().DeviceInfo.GetDescription().Label, + SharingType: sharedBusToString(controller.SharedBus), } + busSharingResults = append(busSharingResults, result) + } } - */ - } - - return nil -} - -func getNumVmsPerDrsScoreBucket(client *govmomi.Client) error { - //properties := []string{"drsVmConfig.numVmPerDrsScoreBucket"} - ctx := context.Background() - m := view.NewManager(client.Client) - - clusters, err := m.CreateContainerView(ctx, client.ServiceContent.RootFolder, []string{"ClusterComputeResource"}, true) - if err != nil { - return err - } - defer clusters.Destroy(ctx) - - var clusterList []mo.ClusterComputeResource - - err = clusters.Retrieve(ctx, []string{"ClusterComputeResource"}, nil, &clusterList) - if err != nil { - log.Printf("Error retrieving cluster list : '%s'\n", err) - return err - } - - for _, cluster := range clusterList { - log.Printf("Cluster: %s\n", cluster.Name) - - pc := property.DefaultCollector(client.Client) - clusterProps := mo.ClusterComputeResource{} - - //err := pc.RetrieveOne(ctx, cluster.Reference(), properties, &clusterProps) - err := pc.RetrieveOne(ctx, cluster.Reference(), nil, &clusterProps) - if err != nil { - log.Printf("Error retrieving property : '%s'\n", err) - return err + } } - // Properties defined at https://vdc-download.vmware.com/vmwb-repository/dcr-public/bf660c0a-f060-46e8-a94d-4b5e6ffc77ad/208bc706-e281-49b6-a0ce-b402ec19ef82/SDK/vsphere-ws/docs/ReferenceGuide/vim.ClusterComputeResource.Summary.html - ccr := clusterProps.Summary.(*types.ClusterComputeResourceSummary) - /* - fmt.Printf("DRS Score: %v\n", ccr.DrsScore) - fmt.Printf("VMs in DRS Score Bucket 0%% to 20%% : %d\n", ccr.NumVmsPerDrsScoreBucket[0]) - fmt.Printf("VMs in DRS Score Bucket 21%% to 40%% : %d\n", ccr.NumVmsPerDrsScoreBucket[1]) - fmt.Printf("VMs in DRS Score Bucket 41%% to 60%% : %d\n", ccr.NumVmsPerDrsScoreBucket[2]) - fmt.Printf("VMs in DRS Score Bucket 61%% to 80%% : %d\n", ccr.NumVmsPerDrsScoreBucket[3]) - fmt.Printf("VMs in DRS Score Bucket 81%% to 100%% : %d\n", ccr.NumVmsPerDrsScoreBucket[4]) - */ - - // Create a new result - result := DrsResults{ - Vcenter: client.URL().Host, - ClusterName: cluster.Name, - DrsScore: ccr.DrsScore, - NumVmsDrsBucket0To20: ccr.NumVmsPerDrsScoreBucket[0], - NumVmsDrsBucket21To40: ccr.NumVmsPerDrsScoreBucket[1], - NumVmsDrsBucket41To60: ccr.NumVmsPerDrsScoreBucket[2], - NumVmsDrsBucket61To80: ccr.NumVmsPerDrsScoreBucket[3], - NumVmsDrsBucket81To100: ccr.NumVmsPerDrsScoreBucket[4], - } - // Append to list of all results - results = append(results, result) - - /* - // Print properties (fields) - objType := reflect.TypeOf(clusterProps) - for i := 0; i < objType.NumField(); i++ { - field := objType.Field(i) - fmt.Printf("Field %d: %s (Type: %s)\n", i, field.Name, field.Type) - } - - // Print methods - methods := reflect.TypeOf(clusterProps) - for i := 0; i < methods.NumMethod(); i++ { - method := methods.Method(i) - fmt.Printf("Method %d: %s\n", i, method.Name) - } - */ } return nil @@ -246,14 +227,6 @@ func main() { } defer c.Logout(ctx) - /* - err = getNumVmsPerDrsScoreBucket(c) - if err != nil { - log.Printf("Error retrieving NumVmsPerDrsScoreBucket: %s\n", err) - return - } - */ - err = getScsiBusSharingVMs(c) if err != nil { log.Printf("Error retrieving list of VMs with SCSI Bus Sharing : %s\n", err) @@ -261,8 +234,8 @@ func main() { } // Output final results in JSON - if len(results) > 0 { - j, _ := json.Marshal(results) + if len(busSharingResults) > 0 { + j, _ := json.Marshal(busSharingResults) fmt.Println(string(j)) } else { fmt.Println("{}")