package vcenter import ( "context" "fmt" "log" "log/slog" "net/url" "os" "github.com/vmware/govmomi" "github.com/vmware/govmomi/find" "github.com/vmware/govmomi/view" "github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/soap" "github.com/vmware/govmomi/vim25/types" ) type Vcenter struct { Logger *slog.Logger ctx context.Context client *govmomi.Client } type VmProperties struct { Vm mo.VirtualMachine Datacenter string } // New creates a new Vcenter with the given logger func New(logger *slog.Logger) *Vcenter { //ctx, cancel := context.WithCancel(context.Background()) //defer cancel() return &Vcenter{ Logger: logger, ctx: context.Background(), } } func (v *Vcenter) Login(vUrl string) error { var insecure bool insecureString := os.Getenv("VCENTER_INSECURE") username := os.Getenv("VCENTER_USERNAME") password := os.Getenv("VCENTER_PASSWORD") // Connect to vCenter u, err := soap.ParseURL(vUrl) if err != nil { log.Fatalf("Error parsing vCenter URL: %s", err) } u.User = url.UserPassword(username, password) /* c, err := govmomi.NewClient(ctx, u, insecure) if err != nil { log.Fatalf("Error connecting to vCenter: %s", err) } */ if insecureString == "true" { insecure = true } c, err := govmomi.NewClient(v.ctx, u, insecure) if err != nil { v.Logger.Error("Unable to connect to vCenter", "error", err) return fmt.Errorf("unable to connect to vCenter : %s", err) } //defer c.Logout(v.ctx) v.client = c v.Logger.Debug("successfully connected to vCenter", "url", vUrl, "username", username) return nil } func (v *Vcenter) Logout() error { return v.client.Logout(v.ctx) } func (v *Vcenter) FindVMByName(vmName string) ([]mo.VirtualMachine, error) { m := view.NewManager(v.client.Client) vms, err := m.CreateContainerView(v.ctx, v.client.ServiceContent.RootFolder, []string{"VirtualMachine"}, true) if err != nil { return nil, err } defer vms.Destroy(v.ctx) var matchingVMs []mo.VirtualMachine err = vms.Retrieve(v.ctx, []string{"VirtualMachine"}, []string{"name"}, &matchingVMs) if err != nil { return nil, err } // Temporarily just return all VMs //return matchingVMs, nil var result []mo.VirtualMachine for _, vm := range matchingVMs { if vm.Name == vmName { result = append(result, vm) } } return result, nil } func (v *Vcenter) FindVMByID(vmID string) (*VmProperties, error) { v.Logger.Debug("searching for vm id", "vm_id", vmID) finder := find.NewFinder(v.client.Client, true) // List all datacenters datacenters, err := finder.DatacenterList(v.ctx, "*") if err != nil { return nil, fmt.Errorf("failed to list datacenters: %w", err) } for _, dc := range datacenters { // Set the current datacenter finder.SetDatacenter(dc) // Create a ManagedObjectReference for the VM vmRef := types.ManagedObjectReference{ Type: "VirtualMachine", Value: vmID, } // Try to find the VM by ID in the current datacenter //vm, err := finder.ObjectReference(v.ctx, vmRef) var vm mo.VirtualMachine err := v.client.RetrieveOne(v.ctx, vmRef, []string{"config", "name"}, &vm) if err == nil { return &VmProperties{ Datacenter: dc.Name(), Vm: vm, }, nil } else if _, ok := err.(*find.NotFoundError); !ok { // If the error is not a NotFoundError, return it //return nil, fmt.Errorf("failed to retrieve VM with ID %s in datacenter %s: %w", vmID, dc.Name(), err) v.Logger.Debug("Couldn't find vm in datacenter", "vm_id", vmID, "datacenter_name", dc.Name()) } else if err != nil { return nil, fmt.Errorf("failed to retrieve VM: %w", err) } } return nil, fmt.Errorf("VM with ID %s not found in any datacenter", vmID) }