diff --git a/go.mod b/go.mod index 92f361af1c..4c3f8c5e98 100644 --- a/go.mod +++ b/go.mod @@ -86,7 +86,7 @@ require ( github.com/thedevsaddam/retry v0.0.0-20200324223450-9769a859cc6d github.com/ulikunitz/xz v0.5.11 github.com/vincent-petithory/dataurl v1.0.0 - github.com/vmware/govmomi v0.30.4 + github.com/vmware/govmomi v0.33.1 golang.org/x/crypto v0.14.0 golang.org/x/oauth2 v0.10.0 golang.org/x/sync v0.3.0 @@ -143,6 +143,7 @@ require ( github.com/coreos/vcontext v0.0.0-20230201181013-d72178a18687 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02 // indirect github.com/elliotwutingfeng/asciiset v0.0.0-20230602022725-51bbb787efab // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch/v5 v5.7.0 // indirect @@ -186,6 +187,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kr/fs v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/leodido/go-urn v1.2.3 // indirect github.com/mailru/easyjson v0.7.7 // indirect diff --git a/go.sum b/go.sum index 70a59231f2..8e8331402c 100644 --- a/go.sum +++ b/go.sum @@ -315,6 +315,8 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNE github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02 h1:tR3jsKPiO/mb6ntzk/dJlHZtm37CPfVp1C9KIo534+4= +github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02/go.mod h1:7NQ3kWOx2cZOSjtcveTa5nqupVr2s6/83sG+rTlI7uA= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= @@ -1184,8 +1186,8 @@ github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1 github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= -github.com/vmware/govmomi v0.30.4 h1:BCKLoTmiBYRuplv3GxKEMBLtBaJm8PA56vo9bddIpYQ= -github.com/vmware/govmomi v0.30.4/go.mod h1:F7adsVewLNHsW/IIm7ziFURaXDaHEwcc+ym4r3INMdY= +github.com/vmware/govmomi v0.33.1 h1:qS2VpEBd/WLbzLO5McI6h5o5zaKsrezUxRY5r9jkW8A= +github.com/vmware/govmomi v0.33.1/go.mod h1:QuzWGiEMA/FYlu5JXKjytiORQoxv2hTHdS2lWnIqKMM= github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk= github.com/vmware/vmw-ovflib v0.0.0-20170608004843-1f217b9dc714/go.mod h1:jiPk45kn7klhByRvUq5i2vo1RtHKBHj+iWGFpxbXuuI= github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= diff --git a/pkg/infrastructure/platform/platform.go b/pkg/infrastructure/platform/platform.go index 5b13bdc904..e904f99844 100644 --- a/pkg/infrastructure/platform/platform.go +++ b/pkg/infrastructure/platform/platform.go @@ -20,6 +20,7 @@ import ( "github.com/openshift/installer/pkg/terraform/stages/ovirt" "github.com/openshift/installer/pkg/terraform/stages/powervs" "github.com/openshift/installer/pkg/terraform/stages/vsphere" + alibabacloudtypes "github.com/openshift/installer/pkg/types/alibabacloud" awstypes "github.com/openshift/installer/pkg/types/aws" azuretypes "github.com/openshift/installer/pkg/types/azure" diff --git a/pkg/infrastructure/platform/platform_altinfra.go b/pkg/infrastructure/platform/platform_altinfra.go index b1b222e005..a6b884f355 100644 --- a/pkg/infrastructure/platform/platform_altinfra.go +++ b/pkg/infrastructure/platform/platform_altinfra.go @@ -7,6 +7,7 @@ import ( "fmt" "github.com/openshift/installer/pkg/infrastructure" + "github.com/openshift/installer/pkg/infrastructure/vsphere" awstypes "github.com/openshift/installer/pkg/types/aws" azuretypes "github.com/openshift/installer/pkg/types/azure" vspheretypes "github.com/openshift/installer/pkg/types/vsphere" @@ -22,8 +23,7 @@ func ProviderForPlatform(platform string) (infrastructure.Provider, error) { panic("not implemented") return nil, nil case vspheretypes.Name: - panic("not implemented") - return nil, nil + return vsphere.InitializeProvider(), nil } return nil, fmt.Errorf("platform %q is not supported in the altinfra Installer build", platform) } diff --git a/pkg/infrastructure/vsphere/vsphere.go b/pkg/infrastructure/vsphere/vsphere.go new file mode 100644 index 0000000000..ac412b7901 --- /dev/null +++ b/pkg/infrastructure/vsphere/vsphere.go @@ -0,0 +1,922 @@ +package vsphere + +import ( + "context" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/url" + "os" + "path" + "strings" + "time" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/vmware/govmomi" + "github.com/vmware/govmomi/find" + "github.com/vmware/govmomi/govc/importx" + "github.com/vmware/govmomi/nfc" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/ovf" + "github.com/vmware/govmomi/vapi/rest" + "github.com/vmware/govmomi/vapi/tags" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" + + machinev1beta1 "github.com/openshift/api/machine/v1beta1" + "github.com/openshift/installer/pkg/asset" + "github.com/openshift/installer/pkg/infrastructure" + "github.com/openshift/installer/pkg/tfvars" + "github.com/openshift/installer/pkg/tfvars/vsphere" + typesinstall "github.com/openshift/installer/pkg/types" + typesvsphere "github.com/openshift/installer/pkg/types/vsphere" +) + +const ( + guestInfoIgnitionData = "guestinfo.ignition.config.data" + guestInfoIgnitionEncoding = "guestinfo.ignition.config.data.encoding" + guestInfoHostname = "guestinfo.hostname" + guestInfoDomain = "guestinfo.domain" + guestInfoNetworkKargs = "guestinfo.afterburn.initrd.network-kargs" + stealClock = "stealclock.enable" +) + +type vCenterConnection struct { + Client *govmomi.Client + Finder *find.Finder + Context context.Context + RestClient *rest.Client + Logout func() error + + URI string + Username string + Password string +} + +// InfrastructureProvider implements the govmomi-based installation method for vSphere IPI. +type InfrastructureProvider struct{} + +// InitializeProvider implements the govmomi-based installation method for vSphere IPI. +func InitializeProvider() infrastructure.Provider { + return &InfrastructureProvider{} +} + +// Provision implements the govmomi-based installation virtual machine provisioning for vSphere IPI. +func (p *InfrastructureProvider) Provision(dir string, vars []*asset.File) ([]*asset.File, error) { + vsphereConfig, clusterConfig, err := getTerraformVars(dir, vars) + if err != nil { + return nil, err + } + err = provision(vsphereConfig, clusterConfig) + if err != nil { + return nil, err + } + return nil, nil +} + +func getTerraformVars(dir string, vars []*asset.File) (*vsphere.Config, *tfvars.Config, error) { + vsphereConfig := &vsphere.Config{} + clusterConfig := &tfvars.Config{} + + for _, v := range vars { + var err error + + filePath := path.Join(dir, v.Filename) + file, err := os.Open(filePath) + + if err != nil { + return nil, nil, err + } + + // decoder provides a rational error message if the json is screwed up. + // whereas Unmarshal does not + decoder := json.NewDecoder(file) + decoder.DisallowUnknownFields() + + if v.Filename == "terraform.tfvars.json" { + err = decoder.Decode(clusterConfig) + } + if v.Filename == "terraform.platform.auto.tfvars.json" { + err = decoder.Decode(vsphereConfig) + } + + if err != nil { + return nil, nil, err + } + } + return vsphereConfig, clusterConfig, nil +} + +func getAssetFilesFromDir(dir string) ([]*asset.File, error) { + var vars []*asset.File + files, err := os.ReadDir(dir) + if err != nil { + return nil, err + } + + for _, file := range files { + if !file.IsDir() { + if strings.Contains(file.Name(), "tfvars.json") { + vars = append(vars, &asset.File{Filename: file.Name()}) + } + } + } + return vars, nil +} + +// DestroyBootstrap implements the govmomi-based deletion of the bootstrap virtual machine for vSphere IPI. +func (p *InfrastructureProvider) DestroyBootstrap(dir string) error { + vars, err := getAssetFilesFromDir(dir) + if err != nil { + return err + } + + vsphereConfig, clusterConfig, err := getTerraformVars(dir, vars) + if err != nil { + return err + } + + vcenterConnectionMap, err := getvCenterConnections(vsphereConfig) + if err != nil { + return err + } + + for _, vconn := range vcenterConnectionMap { + for _, fd := range vsphereConfig.FailureDomainMap { + if vconn.URI == fd.Server { + bootstrapName := fmt.Sprintf("%s-bootstrap", clusterConfig.ClusterID) + + bootstrapPath := path.Join(fd.Topology.Folder, bootstrapName) + + dc, err := vconn.Finder.Datacenter(vconn.Context, fd.Topology.Datacenter) + + if err != nil { + return err + } + + vconn.Finder = vconn.Finder.SetDatacenter(dc) + + virtualMachines, err := vconn.Finder.VirtualMachineList(vconn.Context, bootstrapPath) + if err != nil { + return err + } + + for _, vm := range virtualMachines { + if vm.Name() == bootstrapName { + logrus.Debugf("Destroying bootstrap virtual machine: %s", bootstrapName) + task, err := vm.PowerOff(vconn.Context) + if err != nil { + return err + } + + err = task.Wait(vconn.Context) + if err != nil { + return err + } + + // We don't need to wait for the destroy to finish. + _, err = vm.Destroy(vconn.Context) + if err != nil { + return err + } + return nil + } + } + } + } + } + + return nil +} + +// ExtractHostAddresses is used for sdk (govmomi) vSphere IPI installations to determine the ip addresses for +// bootstrap and control plane nodes if possible. +func (p *InfrastructureProvider) ExtractHostAddresses(dir string, config *typesinstall.InstallConfig, ha *infrastructure.HostAddresses) error { + vars, err := getAssetFilesFromDir(dir) + if err != nil { + return err + } + + // there should be at least two terraform variable files there. + if len(vars) >= 2 { + vsphereConfig, clusterConfig, err := getTerraformVars(dir, vars) + + if err != nil { + return err + } + + vcenterConnectionMap, err := getvCenterConnections(vsphereConfig) + if err != nil { + return err + } + for _, vconn := range vcenterConnectionMap { + for _, fd := range config.Platform.VSphere.FailureDomains { // we mess with FailureDomains within vsphereConfig + if vconn.URI == fd.Server { + dc, err := vconn.Finder.Datacenter(vconn.Context, fd.Topology.Datacenter) + if err != nil { + return err + } + dcFolders, err := dc.Folders(vconn.Context) + if err != nil { + return err + } + + folderPath := fd.Topology.Folder + if !path.IsAbs(folderPath) { + // we futz with the folder path _somewhere_ + // probably because folder in terraform only takes -datacenter/vm/- <-- folder name + folderPath = fmt.Sprintf("%s*", path.Join(dcFolders.VmFolder.InventoryPath, fd.Topology.Folder, clusterConfig.ClusterID)) + } + + vms, err := vconn.Finder.VirtualMachineList(vconn.Context, folderPath) + if err != nil { + return err + } + + bootstrapName := fmt.Sprintf("%s-bootstrap", clusterConfig.ClusterID) + masterBaseName := fmt.Sprintf("%s-master", clusterConfig.ClusterID) + + for _, vm := range vms { + ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second) + defer cancel() + + ip, err := vm.WaitForIP(ctx, true) + if err != nil { + // we don't care about the context exceeding because maybe the node doesn't have an IP address + if !errors.Is(err, context.DeadlineExceeded) { + return err + } + } + + if ip != "" { + if strings.Contains(vm.Name(), bootstrapName) { + ha.Bootstrap = ip + } + if strings.Contains(vm.Name(), masterBaseName) { + ha.Masters = append(ha.Masters, ip) + } + } + } + } + } + } + } else { + return errors.Errorf("missing variable files to determine bootstrap and/or control plane ip addressing") + } + + return nil +} + +func getVCenterClient(uri, username, password string) (*vCenterConnection, error) { + logrus.Debugf("Connecting to vCenter: %s with username: %s", uri, username) + + ctx := context.Background() + + connection := &vCenterConnection{ + Context: ctx, + } + + u, err := soap.ParseURL(uri) + if err != nil { + return nil, err + } + connection.Username = username + connection.Password = password + connection.URI = uri + + u.User = url.UserPassword(username, password) + + c, err := govmomi.NewClient(ctx, u, true) + if err != nil { + return nil, err + } + connection.RestClient = rest.NewClient(c.Client) + err = connection.RestClient.Login(connection.Context, u.User) + if err != nil { + return nil, err + } + connection.Client = c + connection.Finder = find.NewFinder(connection.Client.Client) + connection.Logout = func() error { + err := connection.Client.Logout(connection.Context) + if err != nil { + return err + } + err = connection.RestClient.Logout(connection.Context) + if err != nil { + return err + } + return nil + } + return connection, nil +} + +func getvCenterConnections(vsphereConfig *vsphere.Config) (map[string]*vCenterConnection, error) { + vcenterConnectionMap := make(map[string]*vCenterConnection) + + for _, v := range vsphereConfig.VCenters { + tempvCenterConnection, err := getVCenterClient( + v.Server, + v.Username, + v.Password) + + if err != nil { + return nil, err + } + vcenterConnectionMap[v.Server] = tempvCenterConnection + } + + return vcenterConnectionMap, nil +} + +func provision(vsphereConfig *vsphere.Config, clusterConfig *tfvars.Config) error { + vmTemplateMap := make(map[string]*object.VirtualMachine) + tagMap := make(map[string]string) + + vcenterConnectionMap, err := getvCenterConnections(vsphereConfig) + if err != nil { + return err + } + + // each vcenter needs a tag and tag category + for _, v := range vcenterConnectionMap { + categoryID, err := createTagCategory(v, clusterConfig.ClusterID) + if err != nil { + return err + } + + tempTag, err := createTag(v, clusterConfig.ClusterID, categoryID) + if err != nil { + return err + } + + tagMap[v.URI] = tempTag + } + + for _, fd := range vsphereConfig.FailureDomainMap { + var vmName string + var vmTemplate *object.VirtualMachine + vcenterConnection := vcenterConnectionMap[fd.Server] + + dc, err := vcenterConnection.Finder.Datacenter(vcenterConnection.Context, fd.Topology.Datacenter) + if err != nil { + return err + } + dcFolders, err := dc.Folders(vcenterConnection.Context) + if err != nil { + return err + } + + folderPath := path.Join(dcFolders.VmFolder.InventoryPath, clusterConfig.ClusterID) + + // we must set the Folder to the infraId somewhere, we will need to remove that. + // if we are overwriting folderPath it needs to have a slash (path) + if strings.Contains(fd.Topology.Folder, "/") { + folderPath = fd.Topology.Folder + } + + folder, err := createFolder(folderPath, vcenterConnection) + if err != nil { + return err + } + + // Not entirely fond of this being the switch between using existing template + // and importing. I _think_ the better option would be to use the installConfig FailureDomain directly + // though I guess that isn't available. Maybe add a terrform variable parameter for an unmodified + // platform spec. + + if !path.IsAbs(fd.Topology.Template) { // scenario, if Template is just a name then upload + vmTemplate, err = importRhcosOva(vcenterConnection, folder, + vsphereConfig.OvaFilePath, clusterConfig.ClusterID, tagMap[fd.Server], string(vsphereConfig.DiskType), fd) + if err != nil { + return err + } + vmName, err = vmTemplate.ObjectName(vcenterConnection.Context) + + if err != nil { + return err + } + } else { // scenario, if Template is a full path use existing + vmTemplate, err = vcenterConnection.Finder.VirtualMachine(vcenterConnection.Context, fd.Topology.Template) + + if err != nil { + return err + } + // if we use pre-existing template the full path is provided in the machine. + vmName = vmTemplate.InventoryPath + } + vmTemplateMap[vmName] = vmTemplate + } + encodedMasterIgn := base64.StdEncoding.EncodeToString([]byte(clusterConfig.IgnitionMaster)) + encodedBootstrapIgn := base64.StdEncoding.EncodeToString([]byte(clusterConfig.IgnitionBootstrap)) + + bootstrap := true + + for i := 0; i < len(vsphereConfig.ControlPlanes); i++ { + var kargs string + cp := vsphereConfig.ControlPlanes[i] + vcenterConnection := vcenterConnectionMap[cp.Workspace.Server] + + vmName := fmt.Sprintf("%s-master-%d", clusterConfig.ClusterID, i) + + encodedIgnition := encodedMasterIgn + + if len(vsphereConfig.ControlPlaneNetworkKargs) > i { + kargs = vsphereConfig.ControlPlaneNetworkKargs[i] + } + + if bootstrap { + if i == 0 { + encodedIgnition = encodedBootstrapIgn + vmName = fmt.Sprintf("%s-bootstrap", clusterConfig.ClusterID) + kargs = vsphereConfig.BootStrapNetworkKargs + } + } + + task, err := clone(vcenterConnection, vmTemplateMap[cp.Template], cp, encodedIgnition, vmName, clusterConfig.ClusterDomain, kargs) + if err != nil { + return err + } + + taskInfo, err := task.WaitForResult(vcenterConnection.Context, nil) + if err != nil { + return err + } + + vmMoRef, ok := taskInfo.Result.(types.ManagedObjectReference) + if !ok { + return errors.New("unable to convert task info result into managed object reference") + } + vm := object.NewVirtualMachine(vcenterConnection.Client.Client, vmMoRef) + + err = attachTag(vcenterConnectionMap[cp.Workspace.Server], vmMoRef.Value, tagMap[cp.Workspace.Server]) + if err != nil { + return err + } + + datacenter, err := vcenterConnection.Finder.Datacenter(vcenterConnection.Context, cp.Workspace.Datacenter) + if err != nil { + return err + } + + task, err = datacenter.PowerOnVM(vcenterConnection.Context, []types.ManagedObjectReference{vm.Reference()}, &types.OptionValue{ + Key: string(types.ClusterPowerOnVmOptionOverrideAutomationLevel), + Value: string(types.DrsBehaviorFullyAutomated), + }) + if err != nil { + return err + } + + _, err = task.WaitForResult(vcenterConnection.Context, nil) + if err != nil { + return err + } + + if bootstrap { + if i == 0 { + bootstrap = false + i = -1 + } + } + } + + for _, v := range vcenterConnectionMap { + err := v.Logout() + if err != nil { + return err + } + } + return nil +} + +func createFolder(fullpath string, vconn *vCenterConnection) (*object.Folder, error) { + dir := path.Dir(fullpath) + base := path.Base(fullpath) + + folder, err := vconn.Finder.Folder(context.TODO(), fullpath) + + if folder == nil { + folder, err = vconn.Finder.Folder(context.TODO(), dir) + + var notFoundError *find.NotFoundError + if errors.As(err, ¬FoundError) { + folder, err = createFolder(dir, vconn) + if err != nil { + return folder, err + } + } + + if folder != nil { + logrus.Debugf("Creating vCenter folder: %s", base) + folder, err = folder.CreateFolder(context.TODO(), base) + if err != nil { + return folder, err + } + } + } + return folder, err +} + +func createTagCategory(vconn *vCenterConnection, clusterID string) (string, error) { + categoryName := fmt.Sprintf("openshift-%s", clusterID) + logrus.Debugf("Creating vCenter tag category: %s", categoryName) + + category := tags.Category{ + Name: categoryName, + Description: "Added by openshift-install do not remove", + Cardinality: "SINGLE", + AssociableTypes: []string{ + "urn:vim25:VirtualMachine", + "urn:vim25:ResourcePool", + "urn:vim25:Folder", + "urn:vim25:Datastore", + "urn:vim25:StoragePod", + }, + } + + return tags.NewManager(vconn.RestClient).CreateCategory(vconn.Context, &category) +} + +func createTag(vconn *vCenterConnection, clusterID, categoryID string) (string, error) { + logrus.Debugf("Creating vCenter tag: %s", clusterID) + + tag := tags.Tag{ + Description: "Added by openshift-install do not remove", + Name: clusterID, + CategoryID: categoryID, + } + + return tags.NewManager(vconn.RestClient).CreateTag(vconn.Context, &tag) +} + +func importRhcosOva(vconn *vCenterConnection, folder *object.Folder, cachedImage, clusterID, tagID, diskProvisioningType string, failureDomain typesvsphere.FailureDomain) (*object.VirtualMachine, error) { + name := fmt.Sprintf("%s-rhcos-%s-%s", clusterID, failureDomain.Region, failureDomain.Zone) + logrus.Debugf("Importing RHCOS OVA: %s", name) + + archive := &importx.ArchiveFlag{Archive: &importx.TapeArchive{Path: cachedImage}} + + ovfDescriptor, err := archive.ReadOvf("*.ovf") + if err != nil { + // Open the corrupt OVA file + f, ferr := os.Open(cachedImage) + if ferr != nil { + err = fmt.Errorf("%s, %w", err.Error(), ferr) + } + defer f.Close() + + // Get a sha256 on the corrupt OVA file + // and the size of the file + h := sha256.New() + written, cerr := io.Copy(h, f) + if cerr != nil { + err = fmt.Errorf("%s, %w", err.Error(), cerr) + } + + return nil, errors.Errorf("ova %s has a sha256 of %x and a size of %d bytes, failed to read the ovf descriptor %s", cachedImage, h.Sum(nil), written, err) + } + + ovfEnvelope, err := archive.ReadEnvelope(ovfDescriptor) + if err != nil { + return nil, errors.Errorf("failed to parse ovf: %s", err) + } + + // The RHCOS OVA only has one network defined by default + // The OVF envelope defines this. We need a 1:1 mapping + // between networks with the OVF and the host + if len(ovfEnvelope.Network.Networks) != 1 { + return nil, errors.Errorf("Expected the OVA to only have a single network adapter") + } + + cluster, err := vconn.Finder.ClusterComputeResource(vconn.Context, failureDomain.Topology.ComputeCluster) + + if err != nil { + return nil, err + } + clusterHostSystems, err := cluster.Hosts(vconn.Context) + + if err != nil { + return nil, err + } + resourcePool, err := vconn.Finder.ResourcePool(vconn.Context, failureDomain.Topology.ResourcePool) + if err != nil { + return nil, err + } + + networkPath := path.Join(cluster.InventoryPath, failureDomain.Topology.Networks[0]) + + networkRef, err := vconn.Finder.Network(vconn.Context, networkPath) + if err != nil { + return nil, err + } + datastore, err := vconn.Finder.Datastore(vconn.Context, failureDomain.Topology.Datastore) + if err != nil { + return nil, err + } + + // Create mapping between OVF and the network object + // found by Name + networkMappings := []types.OvfNetworkMapping{{ + Name: ovfEnvelope.Network.Networks[0].Name, + Network: networkRef.Reference(), + }} + + // This is a very minimal spec for importing an OVF. + cisp := types.OvfCreateImportSpecParams{ + EntityName: name, + NetworkMapping: networkMappings, + } + + m := ovf.NewManager(vconn.Client.Client) + spec, err := m.CreateImportSpec(vconn.Context, + string(ovfDescriptor), + resourcePool.Reference(), + datastore.Reference(), + cisp) + + if err != nil { + return nil, errors.Errorf("failed to create import spec: %s", err) + } + if spec.Error != nil { + return nil, errors.New(spec.Error[0].LocalizedMessage) + } + + hostSystem, err := findAvailableHostSystems(vconn, clusterHostSystems) + + if err != nil { + return nil, err + } + + lease, err := resourcePool.ImportVApp(vconn.Context, spec.ImportSpec, folder, hostSystem) + + if err != nil { + return nil, errors.Errorf("failed to import vapp: %s", err) + } + + info, err := lease.Wait(vconn.Context, spec.FileItem) + if err != nil { + return nil, errors.Errorf("failed to lease wait: %s", err) + } + + if err != nil { + return nil, errors.Errorf("failed to attach tag to virtual machine: %s", err) + } + + u := lease.StartUpdater(vconn.Context, info) + defer u.Done() + + for _, i := range info.Items { + // upload the vmdk to which ever host that was first + // available with the required network and datastore. + err = upload(vconn.Context, archive, lease, i) + if err != nil { + return nil, errors.Errorf("failed to upload: %s", err) + } + } + + err = lease.Complete(vconn.Context) + if err != nil { + return nil, errors.Errorf("failed to lease complete: %s", err) + } + + vm := object.NewVirtualMachine(vconn.Client.Client, info.Entity) + if vm == nil { + return nil, fmt.Errorf("error VirtualMachine not found, managed object id: %s", info.Entity.Value) + } + + err = vm.MarkAsTemplate(vconn.Context) + if err != nil { + return nil, errors.Errorf("failed to mark vm as template: %s", err) + } + err = attachTag(vconn, vm.Reference().Value, tagID) + if err != nil { + return nil, err + } + + return vm, nil +} + +func findAvailableHostSystems(vconn *vCenterConnection, clusterHostSystems []*object.HostSystem) (*object.HostSystem, error) { + logrus.Debug("Finding available ESXi hosts for OVA importing.") + var hostSystemManagedObject mo.HostSystem + for _, hostObj := range clusterHostSystems { + err := hostObj.Properties(vconn.Context, hostObj.Reference(), []string{"config.product", "network", "datastore", "runtime"}, &hostSystemManagedObject) + if err != nil { + return nil, err + } + if hostSystemManagedObject.Runtime.InMaintenanceMode { + continue + } + return hostObj, nil + } + return nil, errors.New("all hosts unavailable") +} + +// Used govc/importx/ovf.go as an example to implement +// resourceVspherePrivateImportOvaCreate and upload functions +// See: https://github.com/vmware/govmomi/blob/cc10a0758d5b4d4873388bcea417251d1ad03e42/govc/importx/ovf.go#L196-L324 +func upload(ctx context.Context, archive *importx.ArchiveFlag, lease *nfc.Lease, item nfc.FileItem) error { + file := item.Path + + f, size, err := archive.Open(file) + if err != nil { + return err + } + defer f.Close() + + opts := soap.Upload{ + ContentLength: size, + } + + return lease.Upload(ctx, item, f, opts) +} + +func attachTag(vconn *vCenterConnection, vmMoRefValue, tagID string) error { + logrus.Debugf("Attaching tag id: %s to virtual machine managed object id: %s", tagID, vmMoRefValue) + + tagManager := tags.NewManager(vconn.RestClient) + moRef := types.ManagedObjectReference{ + Value: vmMoRefValue, + Type: "VirtualMachine", + } + + err := tagManager.AttachTag(vconn.Context, tagID, moRef) + + if err != nil { + return err + } + return nil +} + +func getExtraConfig(vmName, clusterDomain, encodedIgnition, kargs string) []types.BaseOptionValue { + extraConfig := []types.BaseOptionValue{ + &types.OptionValue{ + Key: guestInfoIgnitionEncoding, + Value: "base64", + }, + &types.OptionValue{ + Key: guestInfoIgnitionData, + Value: encodedIgnition, + }, + &types.OptionValue{ + Key: guestInfoHostname, + Value: vmName, + }, + &types.OptionValue{ + Key: stealClock, + Value: "TRUE", + }, + &types.OptionValue{ + Key: guestInfoDomain, + Value: clusterDomain, + }, + } + + if kargs != "" { + extraConfig = append(extraConfig, &types.OptionValue{ + Key: guestInfoNetworkKargs, + Value: kargs, + }) + } + + return extraConfig +} + +func clone(vconn *vCenterConnection, vmTemplate *object.VirtualMachine, machineProviderSpec *machinev1beta1.VSphereMachineProviderSpec, encodedIgnition, vmName, clusterDomain, kargs string) (*object.Task, error) { + extraConfig := getExtraConfig(vmName, clusterDomain, encodedIgnition, kargs) + + var deviceSpecs []types.BaseVirtualDeviceConfigSpec + virtualDeviceList, err := vmTemplate.Device(vconn.Context) + if err != nil { + return nil, err + } + + diskSpec, err := getDiskSpec(virtualDeviceList, machineProviderSpec) + if err != nil { + return nil, err + } + deviceSpecs = append(deviceSpecs, diskSpec) + + networkDevices, err := getNetworkDevices(vconn, virtualDeviceList, machineProviderSpec) + if err != nil { + return nil, err + } + + deviceSpecs = append(deviceSpecs, networkDevices...) + + datastore, err := vconn.Finder.Datastore(vconn.Context, machineProviderSpec.Workspace.Datastore) + if err != nil { + return nil, err + } + folder, err := vconn.Finder.Folder(vconn.Context, machineProviderSpec.Workspace.Folder) + if err != nil { + return nil, err + } + resourcepool, err := vconn.Finder.ResourcePool(vconn.Context, machineProviderSpec.Workspace.ResourcePool) + if err != nil { + return nil, err + } + + diskUUIDEnabled := true + spec := types.VirtualMachineCloneSpec{ + Config: &types.VirtualMachineConfigSpec{ + Flags: &types.VirtualMachineFlagInfo{ + DiskUuidEnabled: &diskUUIDEnabled, + }, + ExtraConfig: extraConfig, + DeviceChange: deviceSpecs, + NumCPUs: machineProviderSpec.NumCPUs, + NumCoresPerSocket: machineProviderSpec.NumCoresPerSocket, + MemoryMB: machineProviderSpec.MemoryMiB, + }, + Location: types.VirtualMachineRelocateSpec{ + Datastore: types.NewReference(datastore.Reference()), + Folder: types.NewReference(folder.Reference()), + Pool: types.NewReference(resourcepool.Reference()), + }, + PowerOn: false, + } + + return vmTemplate.Clone(vconn.Context, folder, vmName, spec) +} + +func getDiskSpec(devices object.VirtualDeviceList, machineProviderSpec *machinev1beta1.VSphereMachineProviderSpec) (types.BaseVirtualDeviceConfigSpec, error) { + disks := devices.SelectByType((*types.VirtualDisk)(nil)) + + disk, ok := disks[0].(*types.VirtualDisk) + if !ok { + return nil, errors.New("unable to convert disks to VirtualDisk type") + } + cloneCapacityKB := int64(machineProviderSpec.DiskGiB) * 1024 * 1024 + disk.CapacityInKB = cloneCapacityKB + + return &types.VirtualDeviceConfigSpec{ + Operation: types.VirtualDeviceConfigSpecOperationEdit, + Device: disk, + }, nil +} + +func getNetworkDevices( + vconn *vCenterConnection, + devices object.VirtualDeviceList, + machineProviderSpec *machinev1beta1.VSphereMachineProviderSpec) ([]types.BaseVirtualDeviceConfigSpec, error) { + var networkDevices []types.BaseVirtualDeviceConfigSpec + + nics := devices.SelectByType(&types.VirtualEthernetCard{}) + + nic, ok := nics[0].(*types.VirtualVmxnet3) + if !ok { + return nil, errors.New("unable to convert nic to VirtualVmxnet3 type") + } + + // I am sure there is a better way to do this... + networkType := "Network" + if strings.Contains(machineProviderSpec.Network.Devices[0].NetworkName, "dv") { + networkType = "DistributedVirtualPortgroup" + } + networkObjRef := types.ManagedObjectReference{ + Value: machineProviderSpec.Network.Devices[0].NetworkName, + Type: networkType, + } + + // if this doesn't error with NotFoundError, then the NetworkName + // in the ManagedObjectReference is a Value string vs a path + networkObject, err := vconn.Finder.ObjectReference(vconn.Context, networkObjRef) + if err != nil { + return nil, err + } + + var backing types.BaseVirtualDeviceBackingInfo + + switch networkObject := networkObject.(type) { + case object.DistributedVirtualPortgroup: + backing, err = networkObject.EthernetCardBackingInfo(vconn.Context) + case object.Network: + backing, err = networkObject.EthernetCardBackingInfo(vconn.Context) + } + if err != nil { + return nil, err + } + + // These operations for network adapter is very similar to what govc does when cloning. + newNicDevice, err := object.EthernetCardTypes().CreateEthernetCard("vmxnet3", backing) + if err != nil { + return nil, err + } + card := newNicDevice.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() + card.Key = int32(1) + + card.MacAddress = "" + card.AddressType = string(types.VirtualEthernetCardMacTypeGenerated) + + nic.Backing = card.Backing + + networkDevices = append(networkDevices, &types.VirtualDeviceConfigSpec{ + Device: nic, + Operation: types.VirtualDeviceConfigSpecOperationEdit, + }) + return networkDevices, nil +} diff --git a/pkg/tfvars/tfvars.go b/pkg/tfvars/tfvars.go index 0ee415c935..83134c0ae2 100644 --- a/pkg/tfvars/tfvars.go +++ b/pkg/tfvars/tfvars.go @@ -9,7 +9,8 @@ import ( "github.com/pkg/errors" ) -type config struct { +// Config - provides platform generic cluster details to the infrastructure provider +type Config struct { ClusterID string `json:"cluster_id,omitempty"` ClusterDomain string `json:"cluster_domain,omitempty"` BaseDomain string `json:"base_domain,omitempty"` @@ -38,7 +39,7 @@ func TFVars(clusterID string, clusterDomain string, baseDomain string, machineV4 return nil, errors.Wrap(err, "failed to write bootstrap ignition") } - config := &config{ + config := &Config{ ClusterID: clusterID, ClusterDomain: strings.TrimSuffix(clusterDomain, "."), BaseDomain: strings.TrimSuffix(baseDomain, "."), diff --git a/pkg/tfvars/vsphere/vsphere.go b/pkg/tfvars/vsphere/vsphere.go index 0449770986..68a607ced6 100644 --- a/pkg/tfvars/vsphere/vsphere.go +++ b/pkg/tfvars/vsphere/vsphere.go @@ -22,7 +22,8 @@ type folder struct { Datacenter string `json:"vsphere_datacenter"` } -type config struct { +// Config provides vSphere platform specific configuration to the infrastructure provider +type Config struct { OvaFilePath string `json:"vsphere_ova_filepath"` DiskType vtypes.DiskType `json:"vsphere_disk_type"` VCenters map[string]vtypes.VCenter `json:"vsphere_vcenters"` @@ -67,7 +68,7 @@ func TFVars(sources TFVarsSources) ([]byte, error) { return nil, err } - cfg := &config{ + cfg := &Config{ OvaFilePath: cachedImage, DiskType: sources.DiskType, VCenters: vcenterZones, @@ -220,7 +221,7 @@ func constructKargsFromNetworkConfig(ipAddrs []string, nameservers []string, gat // processGuestNetworkConfiguration takes the config and sources data and generates the kernel arguments (kargs) // needed to boot RHCOS with static IP configurations. -func processGuestNetworkConfiguration(cfg *config, sources TFVarsSources) error { +func processGuestNetworkConfiguration(cfg *Config, sources TFVarsSources) error { platform := sources.InstallConfig.Config.Platform.VSphere // Generate bootstrap karg using vsphere platform info from install-config diff --git a/pkg/tfvars/vsphere/vsphere_test.go b/pkg/tfvars/vsphere/vsphere_test.go index bfb11fbbe1..3dbe8e446d 100644 --- a/pkg/tfvars/vsphere/vsphere_test.go +++ b/pkg/tfvars/vsphere/vsphere_test.go @@ -103,14 +103,14 @@ func createControlPlaneConfigs(ipTypes int64) []*v1beta1.VSphereMachineProviderS return machines } -func createVsphereConfig() *config { - return &config{} +func createVsphereConfig() *Config { + return &Config{} } func TestProcessGuestNetworkConfiguration(t *testing.T) { cases := []struct { name string - config *config + config *Config source TFVarsSources expectedBootKargs string expectedControlKargs []string diff --git a/vendor/github.com/dougm/pretty/.gitignore b/vendor/github.com/dougm/pretty/.gitignore new file mode 100644 index 0000000000..1f0a99f2f2 --- /dev/null +++ b/vendor/github.com/dougm/pretty/.gitignore @@ -0,0 +1,4 @@ +[568].out +_go* +_test* +_obj diff --git a/vendor/github.com/dougm/pretty/License b/vendor/github.com/dougm/pretty/License new file mode 100644 index 0000000000..05c783ccf6 --- /dev/null +++ b/vendor/github.com/dougm/pretty/License @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright 2012 Keith Rarick + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/dougm/pretty/Readme b/vendor/github.com/dougm/pretty/Readme new file mode 100644 index 0000000000..c589fc622b --- /dev/null +++ b/vendor/github.com/dougm/pretty/Readme @@ -0,0 +1,9 @@ +package pretty + + import "github.com/kr/pretty" + + Package pretty provides pretty-printing for Go values. + +Documentation + + http://godoc.org/github.com/kr/pretty diff --git a/vendor/github.com/dougm/pretty/diff.go b/vendor/github.com/dougm/pretty/diff.go new file mode 100644 index 0000000000..6aa7f743a2 --- /dev/null +++ b/vendor/github.com/dougm/pretty/diff.go @@ -0,0 +1,265 @@ +package pretty + +import ( + "fmt" + "io" + "reflect" +) + +type sbuf []string + +func (p *sbuf) Printf(format string, a ...interface{}) { + s := fmt.Sprintf(format, a...) + *p = append(*p, s) +} + +// Diff returns a slice where each element describes +// a difference between a and b. +func Diff(a, b interface{}) (desc []string) { + Pdiff((*sbuf)(&desc), a, b) + return desc +} + +// wprintfer calls Fprintf on w for each Printf call +// with a trailing newline. +type wprintfer struct{ w io.Writer } + +func (p *wprintfer) Printf(format string, a ...interface{}) { + fmt.Fprintf(p.w, format+"\n", a...) +} + +// Fdiff writes to w a description of the differences between a and b. +func Fdiff(w io.Writer, a, b interface{}) { + Pdiff(&wprintfer{w}, a, b) +} + +type Printfer interface { + Printf(format string, a ...interface{}) +} + +// Pdiff prints to p a description of the differences between a and b. +// It calls Printf once for each difference, with no trailing newline. +// The standard library log.Logger is a Printfer. +func Pdiff(p Printfer, a, b interface{}) { + diffPrinter{w: p}.diff(reflect.ValueOf(a), reflect.ValueOf(b)) +} + +type Logfer interface { + Logf(format string, a ...interface{}) +} + +// logprintfer calls Fprintf on w for each Printf call +// with a trailing newline. +type logprintfer struct{ l Logfer } + +func (p *logprintfer) Printf(format string, a ...interface{}) { + p.l.Logf(format, a...) +} + +// Ldiff prints to l a description of the differences between a and b. +// It calls Logf once for each difference, with no trailing newline. +// The standard library testing.T and testing.B are Logfers. +func Ldiff(l Logfer, a, b interface{}) { + Pdiff(&logprintfer{l}, a, b) +} + +type diffPrinter struct { + w Printfer + l string // label +} + +func (w diffPrinter) printf(f string, a ...interface{}) { + var l string + if w.l != "" { + l = w.l + ": " + } + w.w.Printf(l+f, a...) +} + +func (w diffPrinter) diff(av, bv reflect.Value) { + if !av.IsValid() && bv.IsValid() { + w.printf("nil != %# v", formatter{v: bv, quote: true}) + return + } + if av.IsValid() && !bv.IsValid() { + w.printf("%# v != nil", formatter{v: av, quote: true}) + return + } + if !av.IsValid() && !bv.IsValid() { + return + } + + at := av.Type() + bt := bv.Type() + if at != bt { + w.printf("%v != %v", at, bt) + return + } + + switch kind := at.Kind(); kind { + case reflect.Bool: + if a, b := av.Bool(), bv.Bool(); a != b { + w.printf("%v != %v", a, b) + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if a, b := av.Int(), bv.Int(); a != b { + w.printf("%d != %d", a, b) + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + if a, b := av.Uint(), bv.Uint(); a != b { + w.printf("%d != %d", a, b) + } + case reflect.Float32, reflect.Float64: + if a, b := av.Float(), bv.Float(); a != b { + w.printf("%v != %v", a, b) + } + case reflect.Complex64, reflect.Complex128: + if a, b := av.Complex(), bv.Complex(); a != b { + w.printf("%v != %v", a, b) + } + case reflect.Array: + n := av.Len() + for i := 0; i < n; i++ { + w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i)) + } + case reflect.Chan, reflect.Func, reflect.UnsafePointer: + if a, b := av.Pointer(), bv.Pointer(); a != b { + w.printf("%#x != %#x", a, b) + } + case reflect.Interface: + w.diff(av.Elem(), bv.Elem()) + case reflect.Map: + ak, both, bk := keyDiff(av.MapKeys(), bv.MapKeys()) + for _, k := range ak { + w := w.relabel(fmt.Sprintf("[%#v]", k)) + w.printf("%q != (missing)", av.MapIndex(k)) + } + for _, k := range both { + w := w.relabel(fmt.Sprintf("[%#v]", k)) + w.diff(av.MapIndex(k), bv.MapIndex(k)) + } + for _, k := range bk { + w := w.relabel(fmt.Sprintf("[%#v]", k)) + w.printf("(missing) != %q", bv.MapIndex(k)) + } + case reflect.Ptr: + switch { + case av.IsNil() && !bv.IsNil(): + w.printf("nil != %# v", formatter{v: bv, quote: true}) + case !av.IsNil() && bv.IsNil(): + w.printf("%# v != nil", formatter{v: av, quote: true}) + case !av.IsNil() && !bv.IsNil(): + w.diff(av.Elem(), bv.Elem()) + } + case reflect.Slice: + lenA := av.Len() + lenB := bv.Len() + if lenA != lenB { + w.printf("%s[%d] != %s[%d]", av.Type(), lenA, bv.Type(), lenB) + break + } + for i := 0; i < lenA; i++ { + w.relabel(fmt.Sprintf("[%d]", i)).diff(av.Index(i), bv.Index(i)) + } + case reflect.String: + if a, b := av.String(), bv.String(); a != b { + w.printf("%q != %q", a, b) + } + case reflect.Struct: + for i := 0; i < av.NumField(); i++ { + w.relabel(at.Field(i).Name).diff(av.Field(i), bv.Field(i)) + } + default: + panic("unknown reflect Kind: " + kind.String()) + } +} + +func (d diffPrinter) relabel(name string) (d1 diffPrinter) { + d1 = d + if d.l != "" && name[0] != '[' { + d1.l += "." + } + d1.l += name + return d1 +} + +// keyEqual compares a and b for equality. +// Both a and b must be valid map keys. +func keyEqual(av, bv reflect.Value) bool { + if !av.IsValid() && !bv.IsValid() { + return true + } + if !av.IsValid() || !bv.IsValid() || av.Type() != bv.Type() { + return false + } + switch kind := av.Kind(); kind { + case reflect.Bool: + a, b := av.Bool(), bv.Bool() + return a == b + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + a, b := av.Int(), bv.Int() + return a == b + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + a, b := av.Uint(), bv.Uint() + return a == b + case reflect.Float32, reflect.Float64: + a, b := av.Float(), bv.Float() + return a == b + case reflect.Complex64, reflect.Complex128: + a, b := av.Complex(), bv.Complex() + return a == b + case reflect.Array: + for i := 0; i < av.Len(); i++ { + if !keyEqual(av.Index(i), bv.Index(i)) { + return false + } + } + return true + case reflect.Chan, reflect.UnsafePointer, reflect.Ptr: + a, b := av.Pointer(), bv.Pointer() + return a == b + case reflect.Interface: + return keyEqual(av.Elem(), bv.Elem()) + case reflect.String: + a, b := av.String(), bv.String() + return a == b + case reflect.Struct: + for i := 0; i < av.NumField(); i++ { + if !keyEqual(av.Field(i), bv.Field(i)) { + return false + } + } + return true + default: + panic("invalid map key type " + av.Type().String()) + } +} + +func keyDiff(a, b []reflect.Value) (ak, both, bk []reflect.Value) { + for _, av := range a { + inBoth := false + for _, bv := range b { + if keyEqual(av, bv) { + inBoth = true + both = append(both, av) + break + } + } + if !inBoth { + ak = append(ak, av) + } + } + for _, bv := range b { + inBoth := false + for _, av := range a { + if keyEqual(av, bv) { + inBoth = true + break + } + } + if !inBoth { + bk = append(bk, bv) + } + } + return +} diff --git a/vendor/github.com/dougm/pretty/formatter.go b/vendor/github.com/dougm/pretty/formatter.go new file mode 100644 index 0000000000..4941b0cf43 --- /dev/null +++ b/vendor/github.com/dougm/pretty/formatter.go @@ -0,0 +1,358 @@ +package pretty + +import ( + "fmt" + "io" + "reflect" + "strconv" + "text/tabwriter" + "time" + + "github.com/kr/text" +) + +var ( + timeType = reflect.TypeOf(time.Time{}) +) + +type formatter struct { + v reflect.Value + force bool + quote bool +} + +// Formatter makes a wrapper, f, that will format x as go source with line +// breaks and tabs. Object f responds to the "%v" formatting verb when both the +// "#" and " " (space) flags are set, for example: +// +// fmt.Sprintf("%# v", Formatter(x)) +// +// If one of these two flags is not set, or any other verb is used, f will +// format x according to the usual rules of package fmt. +// In particular, if x satisfies fmt.Formatter, then x.Format will be called. +func Formatter(x interface{}) (f fmt.Formatter) { + return formatter{v: reflect.ValueOf(x), quote: true} +} + +func (fo formatter) String() string { + return fmt.Sprint(fo.v.Interface()) // unwrap it +} + +func (fo formatter) passThrough(f fmt.State, c rune) { + s := "%" + for i := 0; i < 128; i++ { + if f.Flag(i) { + s += string(i) + } + } + if w, ok := f.Width(); ok { + s += fmt.Sprintf("%d", w) + } + if p, ok := f.Precision(); ok { + s += fmt.Sprintf(".%d", p) + } + s += string(c) + fmt.Fprintf(f, s, fo.v.Interface()) +} + +func (fo formatter) Format(f fmt.State, c rune) { + if fo.force || c == 'v' && f.Flag('#') && f.Flag(' ') { + w := tabwriter.NewWriter(f, 4, 4, 1, ' ', 0) + p := &printer{tw: w, Writer: w, visited: make(map[visit]int)} + p.printValue(fo.v, true, fo.quote) + w.Flush() + return + } + fo.passThrough(f, c) +} + +type printer struct { + io.Writer + tw *tabwriter.Writer + visited map[visit]int + depth int +} + +func (p *printer) indent() *printer { + q := *p + q.tw = tabwriter.NewWriter(p.Writer, 4, 4, 1, ' ', 0) + q.Writer = text.NewIndentWriter(q.tw, []byte{'\t'}) + return &q +} + +func (p *printer) printInline(v reflect.Value, x interface{}, showType bool) { + if showType { + io.WriteString(p, v.Type().String()) + fmt.Fprintf(p, "(%#v)", x) + } else { + fmt.Fprintf(p, "%#v", x) + } +} + +// printValue must keep track of already-printed pointer values to avoid +// infinite recursion. +type visit struct { + v uintptr + typ reflect.Type +} + +func (p *printer) printValue(v reflect.Value, showType, quote bool) { + if p.depth > 10 { + io.WriteString(p, "!%v(DEPTH EXCEEDED)") + return + } + + switch v.Kind() { + case reflect.Bool: + p.printInline(v, v.Bool(), showType) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p.printInline(v, v.Int(), showType) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p.printInline(v, v.Uint(), showType) + case reflect.Float32, reflect.Float64: + p.printInline(v, v.Float(), showType) + case reflect.Complex64, reflect.Complex128: + fmt.Fprintf(p, "%#v", v.Complex()) + case reflect.String: + p.fmtString(v.String(), quote) + case reflect.Map: + t := v.Type() + if showType { + io.WriteString(p, t.String()) + } + writeByte(p, '{') + if nonzero(v) { + expand := !canInline(v.Type()) + pp := p + if expand { + writeByte(p, '\n') + pp = p.indent() + } + keys := v.MapKeys() + for i := 0; i < v.Len(); i++ { + showTypeInStruct := true + k := keys[i] + mv := v.MapIndex(k) + pp.printValue(k, false, true) + writeByte(pp, ':') + if expand { + writeByte(pp, '\t') + } + showTypeInStruct = t.Elem().Kind() == reflect.Interface + pp.printValue(mv, showTypeInStruct, true) + if expand { + io.WriteString(pp, ",\n") + } else if i < v.Len()-1 { + io.WriteString(pp, ", ") + } + } + if expand { + pp.tw.Flush() + } + } + writeByte(p, '}') + case reflect.Struct: + t := v.Type() + if t == timeType { + io.WriteString(p, "time.Now()") + break + } + + if v.CanAddr() { + addr := v.UnsafeAddr() + vis := visit{addr, t} + if vd, ok := p.visited[vis]; ok && vd < p.depth { + p.fmtString(t.String()+"{(CYCLIC REFERENCE)}", false) + break // don't print v again + } + p.visited[vis] = p.depth + } + + if showType { + io.WriteString(p, t.String()) + } + writeByte(p, '{') + if nonzero(v) { + expand := !canInline(v.Type()) + pp := p + if expand { + writeByte(p, '\n') + pp = p.indent() + } + for i := 0; i < v.NumField(); i++ { + showTypeInStruct := true + if f := t.Field(i); f.Name != "" { + if f.Name == "DynamicData" { + continue + } + io.WriteString(pp, f.Name) + writeByte(pp, ':') + if expand { + writeByte(pp, '\t') + } + showTypeInStruct = labelType(f.Type) + } + pp.printValue(getField(v, i), showTypeInStruct, true) + if expand { + io.WriteString(pp, ",\n") + } else if i < v.NumField()-1 { + io.WriteString(pp, ", ") + } + } + if expand { + pp.tw.Flush() + } + } + writeByte(p, '}') + case reflect.Interface: + switch e := v.Elem(); { + case e.Kind() == reflect.Invalid: + io.WriteString(p, "nil") + case e.IsValid(): + pp := *p + pp.depth++ + pp.printValue(e, showType, true) + default: + io.WriteString(p, v.Type().String()) + io.WriteString(p, "(nil)") + } + case reflect.Array, reflect.Slice: + t := v.Type() + if showType { + io.WriteString(p, t.String()) + } + if v.Kind() == reflect.Slice && v.IsNil() && showType { + io.WriteString(p, "(nil)") + break + } + if v.Kind() == reflect.Slice && v.IsNil() { + io.WriteString(p, "nil") + break + } + if !showType { + // we always want the type for slices + io.WriteString(p, t.String()) + } + writeByte(p, '{') + expand := !canInline(v.Type()) + pp := p + if expand { + writeByte(p, '\n') + pp = p.indent() + } + for i := 0; i < v.Len(); i++ { + showTypeInSlice := t.Elem().Kind() == reflect.Interface + pp.printValue(v.Index(i), showTypeInSlice, true) + if expand { + io.WriteString(pp, ",\n") + } else if i < v.Len()-1 { + io.WriteString(pp, ", ") + } + } + if expand { + pp.tw.Flush() + } + writeByte(p, '}') + case reflect.Ptr: + e := v.Elem() + if !e.IsValid() { + writeByte(p, '(') + io.WriteString(p, v.Type().String()) + io.WriteString(p, ")(nil)") + } else { + switch e.Kind() { + case reflect.Bool: + io.WriteString(p, fmt.Sprintf("types.NewBool(%v)", e.Bool())) + case reflect.Int32: + io.WriteString(p, fmt.Sprintf("types.NewInt32(%v)", e.Int())) + case reflect.Int64: + io.WriteString(p, fmt.Sprintf("types.NewInt64(%v)", e.Int())) + default: + if e.Kind() == reflect.Struct && e.Type() == timeType { + io.WriteString(p, "types.NewTime(time.Now())") + } else { + pp := *p + pp.depth++ + writeByte(pp, '&') + pp.printValue(e, true, true) + } + } + } + case reflect.Chan: + x := v.Pointer() + if showType { + writeByte(p, '(') + io.WriteString(p, v.Type().String()) + fmt.Fprintf(p, ")(%#v)", x) + } else { + fmt.Fprintf(p, "%#v", x) + } + case reflect.Func: + io.WriteString(p, v.Type().String()) + io.WriteString(p, " {...}") + case reflect.UnsafePointer: + p.printInline(v, v.Pointer(), showType) + case reflect.Invalid: + io.WriteString(p, "nil") + } +} + +func canInline(t reflect.Type) bool { + switch t.Kind() { + case reflect.Map: + return !canExpand(t.Elem()) + case reflect.Struct: + for i := 0; i < t.NumField(); i++ { + if canExpand(t.Field(i).Type) { + return false + } + } + return true + case reflect.Interface: + return false + case reflect.Array, reflect.Slice: + return !canExpand(t.Elem()) + case reflect.Ptr: + return false + case reflect.Chan, reflect.Func, reflect.UnsafePointer: + return false + } + return true +} + +func canExpand(t reflect.Type) bool { + switch t.Kind() { + case reflect.Map, reflect.Struct, + reflect.Interface, reflect.Array, reflect.Slice, + reflect.Ptr: + return true + } + return false +} + +func labelType(t reflect.Type) bool { + switch t.Kind() { + case reflect.Interface, reflect.Struct: + return true + } + return false +} + +func (p *printer) fmtString(s string, quote bool) { + if quote { + s = strconv.Quote(s) + } + io.WriteString(p, s) +} + +func writeByte(w io.Writer, b byte) { + w.Write([]byte{b}) +} + +func getField(v reflect.Value, i int) reflect.Value { + val := v.Field(i) + if val.Kind() == reflect.Interface && !val.IsNil() { + val = val.Elem() + } + return val +} diff --git a/vendor/github.com/dougm/pretty/pretty.go b/vendor/github.com/dougm/pretty/pretty.go new file mode 100644 index 0000000000..49423ec7f5 --- /dev/null +++ b/vendor/github.com/dougm/pretty/pretty.go @@ -0,0 +1,108 @@ +// Package pretty provides pretty-printing for Go values. This is +// useful during debugging, to avoid wrapping long output lines in +// the terminal. +// +// It provides a function, Formatter, that can be used with any +// function that accepts a format string. It also provides +// convenience wrappers for functions in packages fmt and log. +package pretty + +import ( + "fmt" + "io" + "log" + "reflect" +) + +// Errorf is a convenience wrapper for fmt.Errorf. +// +// Calling Errorf(f, x, y) is equivalent to +// fmt.Errorf(f, Formatter(x), Formatter(y)). +func Errorf(format string, a ...interface{}) error { + return fmt.Errorf(format, wrap(a, false)...) +} + +// Fprintf is a convenience wrapper for fmt.Fprintf. +// +// Calling Fprintf(w, f, x, y) is equivalent to +// fmt.Fprintf(w, f, Formatter(x), Formatter(y)). +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error error) { + return fmt.Fprintf(w, format, wrap(a, false)...) +} + +// Log is a convenience wrapper for log.Printf. +// +// Calling Log(x, y) is equivalent to +// log.Print(Formatter(x), Formatter(y)), but each operand is +// formatted with "%# v". +func Log(a ...interface{}) { + log.Print(wrap(a, true)...) +} + +// Logf is a convenience wrapper for log.Printf. +// +// Calling Logf(f, x, y) is equivalent to +// log.Printf(f, Formatter(x), Formatter(y)). +func Logf(format string, a ...interface{}) { + log.Printf(format, wrap(a, false)...) +} + +// Logln is a convenience wrapper for log.Printf. +// +// Calling Logln(x, y) is equivalent to +// log.Println(Formatter(x), Formatter(y)), but each operand is +// formatted with "%# v". +func Logln(a ...interface{}) { + log.Println(wrap(a, true)...) +} + +// Print pretty-prints its operands and writes to standard output. +// +// Calling Print(x, y) is equivalent to +// fmt.Print(Formatter(x), Formatter(y)), but each operand is +// formatted with "%# v". +func Print(a ...interface{}) (n int, errno error) { + return fmt.Print(wrap(a, true)...) +} + +// Printf is a convenience wrapper for fmt.Printf. +// +// Calling Printf(f, x, y) is equivalent to +// fmt.Printf(f, Formatter(x), Formatter(y)). +func Printf(format string, a ...interface{}) (n int, errno error) { + return fmt.Printf(format, wrap(a, false)...) +} + +// Println pretty-prints its operands and writes to standard output. +// +// Calling Print(x, y) is equivalent to +// fmt.Println(Formatter(x), Formatter(y)), but each operand is +// formatted with "%# v". +func Println(a ...interface{}) (n int, errno error) { + return fmt.Println(wrap(a, true)...) +} + +// Sprint is a convenience wrapper for fmt.Sprintf. +// +// Calling Sprint(x, y) is equivalent to +// fmt.Sprint(Formatter(x), Formatter(y)), but each operand is +// formatted with "%# v". +func Sprint(a ...interface{}) string { + return fmt.Sprint(wrap(a, true)...) +} + +// Sprintf is a convenience wrapper for fmt.Sprintf. +// +// Calling Sprintf(f, x, y) is equivalent to +// fmt.Sprintf(f, Formatter(x), Formatter(y)). +func Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, wrap(a, false)...) +} + +func wrap(a []interface{}, force bool) []interface{} { + w := make([]interface{}, len(a)) + for i, x := range a { + w[i] = formatter{v: reflect.ValueOf(x), force: force} + } + return w +} diff --git a/vendor/github.com/dougm/pretty/zero.go b/vendor/github.com/dougm/pretty/zero.go new file mode 100644 index 0000000000..abb5b6fc14 --- /dev/null +++ b/vendor/github.com/dougm/pretty/zero.go @@ -0,0 +1,41 @@ +package pretty + +import ( + "reflect" +) + +func nonzero(v reflect.Value) bool { + switch v.Kind() { + case reflect.Bool: + return v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() != 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() != 0 + case reflect.Float32, reflect.Float64: + return v.Float() != 0 + case reflect.Complex64, reflect.Complex128: + return v.Complex() != complex(0, 0) + case reflect.String: + return v.String() != "" + case reflect.Struct: + for i := 0; i < v.NumField(); i++ { + if nonzero(getField(v, i)) { + return true + } + } + return false + case reflect.Array: + for i := 0; i < v.Len(); i++ { + if nonzero(v.Index(i)) { + return true + } + } + return false + case reflect.Map, reflect.Interface, reflect.Slice, reflect.Ptr, reflect.Chan, reflect.Func: + return !v.IsNil() + case reflect.UnsafePointer: + return v.Pointer() != 0 + } + return true +} diff --git a/vendor/github.com/kr/text/License b/vendor/github.com/kr/text/License new file mode 100644 index 0000000000..480a328059 --- /dev/null +++ b/vendor/github.com/kr/text/License @@ -0,0 +1,19 @@ +Copyright 2012 Keith Rarick + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/kr/text/Readme b/vendor/github.com/kr/text/Readme new file mode 100644 index 0000000000..7e6e7c0687 --- /dev/null +++ b/vendor/github.com/kr/text/Readme @@ -0,0 +1,3 @@ +This is a Go package for manipulating paragraphs of text. + +See http://go.pkgdoc.org/github.com/kr/text for full documentation. diff --git a/vendor/github.com/kr/text/doc.go b/vendor/github.com/kr/text/doc.go new file mode 100644 index 0000000000..cf4c198f95 --- /dev/null +++ b/vendor/github.com/kr/text/doc.go @@ -0,0 +1,3 @@ +// Package text provides rudimentary functions for manipulating text in +// paragraphs. +package text diff --git a/vendor/github.com/kr/text/indent.go b/vendor/github.com/kr/text/indent.go new file mode 100644 index 0000000000..4ebac45c09 --- /dev/null +++ b/vendor/github.com/kr/text/indent.go @@ -0,0 +1,74 @@ +package text + +import ( + "io" +) + +// Indent inserts prefix at the beginning of each non-empty line of s. The +// end-of-line marker is NL. +func Indent(s, prefix string) string { + return string(IndentBytes([]byte(s), []byte(prefix))) +} + +// IndentBytes inserts prefix at the beginning of each non-empty line of b. +// The end-of-line marker is NL. +func IndentBytes(b, prefix []byte) []byte { + var res []byte + bol := true + for _, c := range b { + if bol && c != '\n' { + res = append(res, prefix...) + } + res = append(res, c) + bol = c == '\n' + } + return res +} + +// Writer indents each line of its input. +type indentWriter struct { + w io.Writer + bol bool + pre [][]byte + sel int + off int +} + +// NewIndentWriter makes a new write filter that indents the input +// lines. Each line is prefixed in order with the corresponding +// element of pre. If there are more lines than elements, the last +// element of pre is repeated for each subsequent line. +func NewIndentWriter(w io.Writer, pre ...[]byte) io.Writer { + return &indentWriter{ + w: w, + pre: pre, + bol: true, + } +} + +// The only errors returned are from the underlying indentWriter. +func (w *indentWriter) Write(p []byte) (n int, err error) { + for _, c := range p { + if w.bol { + var i int + i, err = w.w.Write(w.pre[w.sel][w.off:]) + w.off += i + if err != nil { + return n, err + } + } + _, err = w.w.Write([]byte{c}) + if err != nil { + return n, err + } + n++ + w.bol = c == '\n' + if w.bol { + w.off = 0 + if w.sel < len(w.pre)-1 { + w.sel++ + } + } + } + return n, nil +} diff --git a/vendor/github.com/kr/text/wrap.go b/vendor/github.com/kr/text/wrap.go new file mode 100644 index 0000000000..b09bb03736 --- /dev/null +++ b/vendor/github.com/kr/text/wrap.go @@ -0,0 +1,86 @@ +package text + +import ( + "bytes" + "math" +) + +var ( + nl = []byte{'\n'} + sp = []byte{' '} +) + +const defaultPenalty = 1e5 + +// Wrap wraps s into a paragraph of lines of length lim, with minimal +// raggedness. +func Wrap(s string, lim int) string { + return string(WrapBytes([]byte(s), lim)) +} + +// WrapBytes wraps b into a paragraph of lines of length lim, with minimal +// raggedness. +func WrapBytes(b []byte, lim int) []byte { + words := bytes.Split(bytes.Replace(bytes.TrimSpace(b), nl, sp, -1), sp) + var lines [][]byte + for _, line := range WrapWords(words, 1, lim, defaultPenalty) { + lines = append(lines, bytes.Join(line, sp)) + } + return bytes.Join(lines, nl) +} + +// WrapWords is the low-level line-breaking algorithm, useful if you need more +// control over the details of the text wrapping process. For most uses, either +// Wrap or WrapBytes will be sufficient and more convenient. +// +// WrapWords splits a list of words into lines with minimal "raggedness", +// treating each byte as one unit, accounting for spc units between adjacent +// words on each line, and attempting to limit lines to lim units. Raggedness +// is the total error over all lines, where error is the square of the +// difference of the length of the line and lim. Too-long lines (which only +// happen when a single word is longer than lim units) have pen penalty units +// added to the error. +func WrapWords(words [][]byte, spc, lim, pen int) [][][]byte { + n := len(words) + + length := make([][]int, n) + for i := 0; i < n; i++ { + length[i] = make([]int, n) + length[i][i] = len(words[i]) + for j := i + 1; j < n; j++ { + length[i][j] = length[i][j-1] + spc + len(words[j]) + } + } + + nbrk := make([]int, n) + cost := make([]int, n) + for i := range cost { + cost[i] = math.MaxInt32 + } + for i := n - 1; i >= 0; i-- { + if length[i][n-1] <= lim || i == n-1 { + cost[i] = 0 + nbrk[i] = n + } else { + for j := i + 1; j < n; j++ { + d := lim - length[i][j-1] + c := d*d + cost[j] + if length[i][j-1] > lim { + c += pen // too-long lines get a worse penalty + } + if c < cost[i] { + cost[i] = c + nbrk[i] = j + } + } + } + } + + var lines [][][]byte + i := 0 + for i < n { + lines = append(lines, words[i:nbrk[i]]) + i = nbrk[i] + } + return lines +} diff --git a/vendor/github.com/vmware/govmomi/.golangci.yml b/vendor/github.com/vmware/govmomi/.golangci.yml index d6392fb948..25242dcaf5 100644 --- a/vendor/github.com/vmware/govmomi/.golangci.yml +++ b/vendor/github.com/vmware/govmomi/.golangci.yml @@ -14,5 +14,6 @@ linters-settings: run: timeout: 6m skip-dirs: + - vim25/json - vim25/xml - cns/types diff --git a/vendor/github.com/vmware/govmomi/.goreleaser.yml b/vendor/github.com/vmware/govmomi/.goreleaser.yml index 69b80be383..5da5cd64ef 100644 --- a/vendor/github.com/vmware/govmomi/.goreleaser.yml +++ b/vendor/github.com/vmware/govmomi/.goreleaser.yml @@ -34,13 +34,12 @@ archives: - id: govcbuild builds: - govc - name_template: "govc_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" - replacements: &replacements - darwin: Darwin - linux: Linux - windows: Windows - freebsd: FreeBSD - amd64: x86_64 + name_template: >- + govc_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} format_overrides: &overrides - goos: windows format: zip @@ -52,8 +51,12 @@ archives: - id: vcsimbuild builds: - vcsim - name_template: "vcsim_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" - replacements: *replacements + name_template: >- + vcsim_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} format_overrides: *overrides files: *extrafiles @@ -77,7 +80,7 @@ brews: - name: govc ids: - govcbuild - tap: + repository: owner: govmomi name: homebrew-tap # TODO: create token in specified tap repo, add as secret to govmomi repo and reference in release workflow @@ -88,7 +91,7 @@ brews: name: Alfred the Narwhal email: cna-alfred@vmware.com folder: Formula - homepage: "https://github.com/vmware/govmomi/blob/master/govc/README.md" + homepage: "https://github.com/vmware/govmomi/blob/main/govc/README.md" description: "govc is a vSphere CLI built on top of govmomi." test: | system "#{bin}/govc version" @@ -97,7 +100,7 @@ brews: - name: vcsim ids: - vcsimbuild - tap: + repository: owner: govmomi name: homebrew-tap # TODO: create token in specified tap repo, add as secret to govmomi repo and reference in release workflow @@ -108,7 +111,7 @@ brews: name: Alfred the Narwhal email: cna-alfred@vmware.com folder: Formula - homepage: "https://github.com/vmware/govmomi/blob/master/vcsim/README.md" + homepage: "https://github.com/vmware/govmomi/blob/main/vcsim/README.md" description: "vcsim is a vSphere API simulator built on top of govmomi." test: | system "#{bin}/vcsim -h" diff --git a/vendor/github.com/vmware/govmomi/CHANGELOG.md b/vendor/github.com/vmware/govmomi/CHANGELOG.md index 974881f989..f0e5da70d4 100644 --- a/vendor/github.com/vmware/govmomi/CHANGELOG.md +++ b/vendor/github.com/vmware/govmomi/CHANGELOG.md @@ -1,4 +1,112 @@ + +## [Release v0.30.0](https://github.com/vmware/govmomi/compare/v0.29.0...v0.30.0) + +> Release Date: 2022-12-12 + +### 🐞 Fix + +- [1ad33d48] Heal the broken Namespace API +- [22c48147] Update $mktemp to support macOS +- [05b0b08c] DialTLSContext / Go 1.18+ CertificateVerify support + +### 💫 API Changes + +- [58f4112b] Update types to vSphere 8.0 GA +- [ba206c5b] add Content Library security compliance support +- [4c24f821] Add SRIOV device names +- [642156dd] Adds vSphere 7.0u1-u3 support to namespace-management (Tanzu) + +### 💫 `govc` (CLI) + +- [60a18c56] about.cert was not respecting -k +- [15d1181d] bash completion improvements +- [0dbf717b] Add sso.lpp.info and sso.lpp.update commands +- [fe87cff9] host.info: use writer instead of os.stdout +- [a7196e41] host.info: use writer instead of os.stdout +- [3d6de9da] fix host.esxcli runtime error occurred when no arguments specified +- [8c7ba5ef] Add feature in sso.group.ls to list groups using FindGroupsInGroup method +- [dc3e1d79] Add feature sso.group.lsgroups using FindGroupsInGroup method +- [bf991e6e] add event key for json and plain text output +- [2017e846] Support creating content libraries with security policies + +### 💫 `vcsim` (Simulator) + +- [86f9d42a] Update test keys to be RSA 2048 +- [cedf695b] Fix duplicated name check in CloneVM_Task +- [8f4da558] add QueryNetworkHint support for LLDP and CDP details +- [1cab3254] Fix RetrieveProperties path validation to avoid panic +- [7f42a1d2] use node id for ServiceContent.InstanceUuid +- [03319493] Fix snapshot tasks to update rootSnapshot +- [b6ebcb6b] Fix disk capacity validation in ConfigureDevices +- [61032a23] Fix StorageIOAllocationInfo of VirtualDisk +- [cbfe0c93] support disconnect/reconnect host +- [b44828a4] Fix datastore freespace changed by ReconfigVM_Task + +### 📃 Documentation + +- [813a5d88] update `README.md` + +### 🧹 Chore + +- [eabc29ba] Update version.go for v0.30.0 + +### ⚠️ BREAKING + +### 📖 Commits + +- [eabc29ba] chore: Update version.go for v0.30.0 +- [1c919824] Update CONTRIBUTORS for release +- [1ad33d48] fix: Heal the broken Namespace API +- [22c48147] fix: Update $mktemp to support macOS +- [05b0b08c] fix: DialTLSContext / Go 1.18+ CertificateVerify support +- [86f9d42a] vcsim: Update test keys to be RSA 2048 +- [60a18c56] govc: about.cert was not respecting -k +- [58f4112b] api: Update types to vSphere 8.0 GA +- [15d1181d] govc: bash completion improvements +- [c018f078] perms on template files +- [813a5d88] docs: update `README.md` +- [0dbf717b] govc: Add sso.lpp.info and sso.lpp.update commands +- [fe87cff9] govc: host.info: use writer instead of os.stdout +- [a7196e41] govc: host.info: use writer instead of os.stdout +- [ba206c5b] api: add Content Library security compliance support +- [cedf695b] vcsim: Fix duplicated name check in CloneVM_Task +- [8f4da558] vcsim: add QueryNetworkHint support for LLDP and CDP details +- [3b2816ac] Add optional recommRequired PlaceVmsXCluster req arguments +- [f975908a] build(deps): bump andstor/file-existence-action from 1 to 2 +- [1373b80f] build(deps): bump chuhlomin/render-template from 1.5 to 1.6 +- [dc55a27e] build(deps): bump nokogiri from 1.13.6 to 1.13.9 in /gen +- [63980ff2] Fix: use latestPages in task HistoryCollector +- [3d6de9da] govc: fix host.esxcli runtime error occurred when no arguments specified +- [1e9eed94] Update list of projects using govmomi +- [7f4d115c] fixup! api: Add SRIOV device names +- [8f1dc575] Add API cnsreconfigpolicy bindings and static check fixes to cns/client_test.go +- [bf68e8f0] fixup! api: Add SRIOV device names +- [4c24f821] api: Add SRIOV device names +- [c1bb56db] Updated USAGE.md +- [aca677ad] build(deps): bump actions/stale from 5 to 6 +- [1cab3254] vcsim: Fix RetrieveProperties path validation to avoid panic +- [65a6f6bc] Address review comments +- [99d12605] correct new lines in group.ls +- [4d9f6e01] correct new lines in USAGE.md +- [e5bee862] move FindUsersInGroup to users.ls +- [8c7ba5ef] govc: Add feature in sso.group.ls to list groups using FindGroupsInGroup method +- [ee332ae7] Add new query selection parameters to be used for QueryAllVolume/QueryVolumeAsync API +- [dc3e1d79] govc: Add feature sso.group.lsgroups using FindGroupsInGroup method +- [201ae28f] Add common stub for hgfs for non-linux env +- [7f42a1d2] vcsim: use node id for ServiceContent.InstanceUuid +- [76e99b00] Boilerplate check requires a date range in the license. +- [bf991e6e] govc: add event key for json and plain text output +- [4a29caee] add OpenBSD build constraint +- [81bc76bc] toolbbox: add hgfs OpenBSD stub +- [03319493] vcsim: Fix snapshot tasks to update rootSnapshot +- [b6ebcb6b] vcsim: Fix disk capacity validation in ConfigureDevices +- [2017e846] govc: Support creating content libraries with security policies +- [642156dd] api: Adds vSphere 7.0u1-u3 support to namespace-management (Tanzu) +- [61032a23] vcsim: Fix StorageIOAllocationInfo of VirtualDisk +- [cbfe0c93] vcsim: support disconnect/reconnect host +- [b44828a4] vcsim: Fix datastore freespace changed by ReconfigVM_Task + ## [Release v0.29.0](https://github.com/vmware/govmomi/compare/v0.28.0...v0.29.0) diff --git a/vendor/github.com/vmware/govmomi/CONTRIBUTING.md b/vendor/github.com/vmware/govmomi/CONTRIBUTING.md index c6d69e5467..038e5321b7 100644 --- a/vendor/github.com/vmware/govmomi/CONTRIBUTING.md +++ b/vendor/github.com/vmware/govmomi/CONTRIBUTING.md @@ -41,7 +41,7 @@ and **supported prefixes**, e.g. `govc: `. ### Example 1 - Fix a Bug in `govmomi` ```bash -git checkout -b issue- vmware/master +git checkout -b issue- main git add git commit -m "fix: ..." -m "Closes: #" git push $USER issue- @@ -50,7 +50,7 @@ git push $USER issue- ### Example 2 - Add a new (non-breaking) API to `govmomi` ```bash -git checkout -b issue- vmware/master +git checkout -b issue- main git add git commit -m "Add API ..." -m "Closes: #" git push $USER issue- @@ -59,7 +59,7 @@ git push $USER issue- ### Example 3 - Add a Feature to `govc` ```bash -git checkout -b issue- vmware/master +git checkout -b issue- main git add git commit -m "govc: Add feature ..." -m "Closes: #" git push $USER issue- @@ -70,7 +70,7 @@ To register the new `govc` command package, add a blank `_` import to `govmomi/g ### Example 4 - Fix a Bug in `vcsim` ```bash -git checkout -b issue- vmware/master +git checkout -b issue- main git add git commit -m "vcsim: Fix ..." -m "Closes: #" git push $USER issue- @@ -87,7 +87,7 @@ Thus these details should be stated at the body of the commit message. Multi-line strings are supported. ```bash -git checkout -b issue- vmware/master +git checkout -b issue- main git add cat << EOF | git commit -F - Add ctx to funcXYZ @@ -103,13 +103,13 @@ git push $USER issue- ### Stay in sync with Upstream -When your branch gets out of sync with the vmware/master branch, use the +When your branch gets out of sync with the main branch, use the following to update (rebase): ```bash git checkout issue- git fetch -a -git rebase vmware/master +git rebase main git push --force-with-lease $USER issue- ``` @@ -139,7 +139,7 @@ Once the review is complete, squash and push your final commit(s): ```bash # squash all commits into one # --autosquash will automatically detect and merge fixup commits -git rebase -i --autosquash vmware/master +git rebase -i --autosquash main git push --force-with-lease $USER issue- ``` diff --git a/vendor/github.com/vmware/govmomi/CONTRIBUTORS b/vendor/github.com/vmware/govmomi/CONTRIBUTORS index ef8c56de8b..406173b84c 100644 --- a/vendor/github.com/vmware/govmomi/CONTRIBUTORS +++ b/vendor/github.com/vmware/govmomi/CONTRIBUTORS @@ -9,6 +9,7 @@ Adam Chalkley Adam Fowler Adam Shannon Akanksha Panse +akutz Al Biheiri Alessandro Cortiana Alex @@ -52,7 +53,6 @@ Brian Rak brian57860 Bruce Downs Bryan Venteicher -Cédric Blomart Cheng Cheng Chethan Venkatesh Choudhury Sarada Prasanna Nanda @@ -61,6 +61,7 @@ Christian Höltje Clint Greenwood cpiment CuiHaozhi +Cédric Blomart Dan Ilan Dan Norris Daniel Frederick Crisman @@ -104,6 +105,7 @@ Gavrie Philipson George Hicken Gerrit Renker gthombare +Hakan Halil HakanSunay Hasan Mahmood Haydon Ryan @@ -123,9 +125,9 @@ Jeremy Canady jeremy-clerc Jiatong Wang jingyizPensando -João Pereira Jonas Ausevicius Jorge Sevilla +João Pereira Julien PILLON Justin J. Novack kayrus @@ -140,6 +142,7 @@ Louie Jiang Luther Monson Madanagopal Arunachalam makelarisjr <8687447+makelarisjr@users.noreply.github.com> +Manuel Grandeit maplain Marc Carmier Marcus Tan @@ -164,6 +167,7 @@ Mike Schinkel Mincho Tonev mingwei Nicolas Lamirault +nikhaild <84156354+nikhaild@users.noreply.github.com> Nikhil Kathare Nikhil R Deshpande Nikolas Grottendieck @@ -226,6 +230,7 @@ Tjeu Kayim <15987676+TjeuKayim@users.noreply.github.com> Toomas Pelberg Trevor Dawe tshihad +Ueli Banholzer Uwe Bessle Vadim Egorov Vikram Krishnamurthy @@ -245,6 +250,7 @@ Yi Jiang yiyingy ykakarap Yogesh Sobale <6104071+ysobale@users.noreply.github.com> +Your Name Yue Yin Yun Zhou Yuya Kusakabe diff --git a/vendor/github.com/vmware/govmomi/Makefile b/vendor/github.com/vmware/govmomi/Makefile index 1a89322a32..0f31649af8 100644 --- a/vendor/github.com/vmware/govmomi/Makefile +++ b/vendor/github.com/vmware/govmomi/Makefile @@ -58,7 +58,7 @@ lint-go: $(GOLANGCI_LINT) ## Lint codebase $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_FLAGS) .PHONY: lint-go-full -lint-go-full: GOLANGCI_LINT_FLAGS = --fast=false +lint-go-full: GOLANGCI_LINT_FLAGS = --fast=false --max-same-issues=200 lint-go-full: lint-go ## Run slower linters to detect possible issues .PHONY: fix @@ -107,6 +107,10 @@ doc: install doc: ## Generates govc USAGE.md ./govc/usage.sh > ./govc/USAGE.md +.PHONY: generate-types +generate-types: ## Generate the types + $(MAKE) -C ./gen/ $@ + ## -------------------------------------- ## Tests @@ -132,7 +136,7 @@ endif .PHONY: go-test go-test: ## Runs go unit tests with race detector enabled - GORACE=$(GORACE) $(GO) test \ + GORACE=$(GORACE) CGO_ENABLED=1 $(GO) test \ -count $(TEST_COUNT) \ -race \ -timeout $(TEST_TIMEOUT) \ @@ -143,16 +147,7 @@ go-test: ## Runs go unit tests with race detector enabled govc-test: install govc-test: ## Runs govc bats tests ./govc/test/images/update.sh - (cd govc/test && ./vendor/github.com/sstephenson/bats/libexec/bats -t .) - -.PHONY: govc-test-sso -govc-test-sso: install - ./govc/test/images/update.sh - (cd govc/test && SSO_BATS=1 ./vendor/github.com/sstephenson/bats/libexec/bats -t sso.bats) - -.PHONY: govc-test-sso-assert-cert -govc-test-sso-assert-cert: - SSO_BATS_ASSERT_CERT=1 $(MAKE) govc-test-sso + (cd govc/test && ./vendor/github.com/bats-core/bats-core/bin/bats -t .) .PHONY: test test: go-test govc-test ## Runs go-test and govc-test diff --git a/vendor/github.com/vmware/govmomi/README.md b/vendor/github.com/vmware/govmomi/README.md index 60a18d6e12..73975150c8 100644 --- a/vendor/github.com/vmware/govmomi/README.md +++ b/vendor/github.com/vmware/govmomi/README.md @@ -65,6 +65,7 @@ Refer to the [CHANGELOG][govmomi-changelog] for version to version changes. * [Kubernetes vSphere Cloud Provider][project-k8s-cloud-provider] * [Kubernetes Cluster API][project-k8s-cluster-api] * [OPS][project-nanovms-ops] +* [OpenTelemetry Collector Contrib][opentelemetry-collector-contrib] * [Packer Plugin for VMware vSphere][project-hashicorp-packer-plugin-vsphere] * [Rancher][project-rancher] * [Terraform Provider for VMware vSphere][project-hashicorp-terraform-provider-vsphere] @@ -102,6 +103,7 @@ Follows pyvmomi and rbvmomi: language prefix + the vSphere acronym "VM Object Ma [go-reference]: https://pkg.go.dev/github.com/vmware/govmomi [go-report-card]: https://goreportcard.com/report/github.com/vmware/govmomi [go-version]: https://github.com/vmware/govmomi +[opentelemetry-collector-contrib]: https://github.com/open-telemetry/opentelemetry-collector-contrib [project-docker-linuxKit]: https://github.com/linuxkit/linuxkit/tree/master/src/cmd/linuxkit [project-elastic-agent]: https://github.com/elastic/integrations/tree/main/packages/vsphere [project-gru]: https://github.com/dnaeon/gru diff --git a/vendor/github.com/vmware/govmomi/RELEASE.md b/vendor/github.com/vmware/govmomi/RELEASE.md index 1a12c0640b..3c0965a831 100644 --- a/vendor/github.com/vmware/govmomi/RELEASE.md +++ b/vendor/github.com/vmware/govmomi/RELEASE.md @@ -18,7 +18,7 @@ uses [`goreleaser`](http://goreleaser.com/) and automatically creates/pushes: - Docker images for `vmware/govc` and `vmware/vcsim` to Docker Hub - Source code -Starting with release tag `v0.29.0`, releases are not tagged on the `master` +Starting with release tag `v0.29.0`, releases are not tagged on the `main` branch anymore but a dedicated release branch, for example `release-0.29`. This process has already been followed for patch releases and back-ports. @@ -37,15 +37,15 @@ which can be done through the Github UI or `git` CLI. This guide describes the CLI process. -### Verify `master` branch is up to date with the remote +### Verify `main` branch is up to date with the remote ```console -git checkout master +git checkout main git fetch -avp -git diff master origin/master +git diff main origin/main # if your local and remote branches diverge run -git pull origin/master +git pull origin/main ``` > **Warning** @@ -57,7 +57,7 @@ git pull origin/master ### Create a release branch For new releases, create a release branch from the most recent commit in -`master`, e.g. `release-0.30`. +`main`, e.g. `release-0.30`. ```console export RELEASE_BRANCH=release-0.30 @@ -106,7 +106,7 @@ navigate to `Actions -> Workflows -> Release`. Click `Run Workflow` which opens a dropdown list. -Select the new/updated branch, e.g. `release-0.30`, i.e. **not** the `master` +Select the new/updated branch, e.g. `release-0.30`, i.e. **not** the `main` branch. Specify a semantic `tag` to associate with the release, e.g. `v0.30.0`. @@ -124,7 +124,7 @@ Click `Run Workflow` to kick off the workflow. After successful completion and if the newly created `tag` is the **latest** (semantic version sorted) tag in the repository, a PR is automatically opened -against the `master` branch to update the `CHANGELOG`. Please review and merge +against the `main` branch to update the `CHANGELOG`. Please review and merge accordingly. ## Creating a release before Version `v0.29.0` @@ -133,15 +133,15 @@ The release process before `v0.29.0` differs since it's based on manually creating and pushing tags. Here, on every new tag matching `v*` pushed to the repository a Github Action Release Workflow is executed. -### Verify `master` branch is up to date with the remote +### Verify `main` branch is up to date with the remote ```console -git checkout master +git checkout main git fetch -avp -git diff master origin/master +git diff main origin/main # if your local and remote branches diverge run -git pull origin/master +git pull origin/main ``` > **Warning** diff --git a/vendor/github.com/vmware/govmomi/USAGE.md b/vendor/github.com/vmware/govmomi/USAGE.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/vmware/govmomi/client.go b/vendor/github.com/vmware/govmomi/client.go index ad49fe6bf7..5becedd489 100644 --- a/vendor/github.com/vmware/govmomi/client.go +++ b/vendor/github.com/vmware/govmomi/client.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. +Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -19,7 +19,7 @@ This package is the root package of the govmomi library. The library is structured as follows: -Package vim25 +# Package vim25 The minimal usable functionality is available through the vim25 package. It contains subpackages that contain generated types, managed objects, and all @@ -30,25 +30,25 @@ The vim25 package itself contains a client structure that is passed around throughout the entire library. It abstracts a session and its immutable state. See the vim25 package for more information. -Package session +# Package session The session package contains an abstraction for the session manager that allows a user to login and logout. It also provides access to the current session (i.e. to determine if the user is in fact logged in) -Package object +# Package object The object package contains wrappers for a selection of managed objects. The constructors of these objects all take a *vim25.Client, which they pass along to derived objects, if applicable. -Package govc +# Package govc The govc package contains the govc CLI. The code in this tree is not intended to be used as a library. Any functionality that govc contains that _could_ be used as a library function but isn't, _should_ live in a root level package. -Other packages +# Other packages Other packages, such as "event", "guest", or "license", provide wrappers for the respective subsystems. They are typically not needed in normal workflows so diff --git a/vendor/github.com/vmware/govmomi/cns/.gitignore b/vendor/github.com/vmware/govmomi/cns/.gitignore new file mode 100644 index 0000000000..dc43ac9d6e --- /dev/null +++ b/vendor/github.com/vmware/govmomi/cns/.gitignore @@ -0,0 +1 @@ +.soap/ \ No newline at end of file diff --git a/vendor/github.com/vmware/govmomi/cns/client.go b/vendor/github.com/vmware/govmomi/cns/client.go new file mode 100644 index 0000000000..a526ff46f9 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/cns/client.go @@ -0,0 +1,305 @@ +/* +Copyright (c) 2019 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cns + +import ( + "context" + + "github.com/vmware/govmomi/cns/methods" + cnstypes "github.com/vmware/govmomi/cns/types" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/soap" + vimtypes "github.com/vmware/govmomi/vim25/types" +) + +// Namespace and Path constants +const ( + Namespace = "vsan" + Path = "/vsanHealth" +) + +const ( + ReleaseVSAN67u3 = "vSAN 6.7U3" + ReleaseVSAN70 = "7.0" + ReleaseVSAN70u1 = "vSAN 7.0U1" +) + +var ( + CnsVolumeManagerInstance = vimtypes.ManagedObjectReference{ + Type: "CnsVolumeManager", + Value: "cns-volume-manager", + } + CnsDebugManagerInstance = vimtypes.ManagedObjectReference{ + Type: "CnsDebugManager", + Value: "cns-debug-manager", + } +) + +type Client struct { + *soap.Client + + RoundTripper soap.RoundTripper + + vim25Client *vim25.Client +} + +// NewClient creates a new CNS client +func NewClient(ctx context.Context, c *vim25.Client) (*Client, error) { + sc := c.Client.NewServiceClient(Path, Namespace) + sc.Namespace = c.Namespace + sc.Version = c.Version + return &Client{sc, sc, c}, nil +} + +// RoundTrip dispatches to the RoundTripper field. +func (c *Client) RoundTrip(ctx context.Context, req, res soap.HasFault) error { + return c.RoundTripper.RoundTrip(ctx, req, res) +} + +// CreateVolume calls the CNS create API. +func (c *Client) CreateVolume(ctx context.Context, createSpecList []cnstypes.CnsVolumeCreateSpec) (*object.Task, error) { + createSpecList = dropUnknownCreateSpecElements(c, createSpecList) + req := cnstypes.CnsCreateVolume{ + This: CnsVolumeManagerInstance, + CreateSpecs: createSpecList, + } + res, err := methods.CnsCreateVolume(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// UpdateVolumeMetadata calls the CNS CnsUpdateVolumeMetadata API with UpdateSpecs specified in the argument +func (c *Client) UpdateVolumeMetadata(ctx context.Context, updateSpecList []cnstypes.CnsVolumeMetadataUpdateSpec) (*object.Task, error) { + updateSpecList = dropUnknownVolumeMetadataUpdateSpecElements(c, updateSpecList) + req := cnstypes.CnsUpdateVolumeMetadata{ + This: CnsVolumeManagerInstance, + UpdateSpecs: updateSpecList, + } + res, err := methods.CnsUpdateVolumeMetadata(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// DeleteVolume calls the CNS delete API. +func (c *Client) DeleteVolume(ctx context.Context, volumeIDList []cnstypes.CnsVolumeId, deleteDisk bool) (*object.Task, error) { + req := cnstypes.CnsDeleteVolume{ + This: CnsVolumeManagerInstance, + VolumeIds: volumeIDList, + DeleteDisk: deleteDisk, + } + res, err := methods.CnsDeleteVolume(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// ExtendVolume calls the CNS Extend API. +func (c *Client) ExtendVolume(ctx context.Context, extendSpecList []cnstypes.CnsVolumeExtendSpec) (*object.Task, error) { + req := cnstypes.CnsExtendVolume{ + This: CnsVolumeManagerInstance, + ExtendSpecs: extendSpecList, + } + res, err := methods.CnsExtendVolume(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// AttachVolume calls the CNS Attach API. +func (c *Client) AttachVolume(ctx context.Context, attachSpecList []cnstypes.CnsVolumeAttachDetachSpec) (*object.Task, error) { + req := cnstypes.CnsAttachVolume{ + This: CnsVolumeManagerInstance, + AttachSpecs: attachSpecList, + } + res, err := methods.CnsAttachVolume(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// DetachVolume calls the CNS Detach API. +func (c *Client) DetachVolume(ctx context.Context, detachSpecList []cnstypes.CnsVolumeAttachDetachSpec) (*object.Task, error) { + req := cnstypes.CnsDetachVolume{ + This: CnsVolumeManagerInstance, + DetachSpecs: detachSpecList, + } + res, err := methods.CnsDetachVolume(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// QueryVolume calls the CNS QueryVolume API. +func (c *Client) QueryVolume(ctx context.Context, queryFilter cnstypes.CnsQueryFilter) (*cnstypes.CnsQueryResult, error) { + req := cnstypes.CnsQueryVolume{ + This: CnsVolumeManagerInstance, + Filter: queryFilter, + } + res, err := methods.CnsQueryVolume(ctx, c, &req) + if err != nil { + return nil, err + } + return &res.Returnval, nil +} + +// QueryVolumeInfo calls the CNS QueryVolumeInfo API and return a task, from which we can extract VolumeInfo +// containing VStorageObject +func (c *Client) QueryVolumeInfo(ctx context.Context, volumeIDList []cnstypes.CnsVolumeId) (*object.Task, error) { + req := cnstypes.CnsQueryVolumeInfo{ + This: CnsVolumeManagerInstance, + VolumeIds: volumeIDList, + } + res, err := methods.CnsQueryVolumeInfo(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// QueryAllVolume calls the CNS QueryAllVolume API. +func (c *Client) QueryAllVolume(ctx context.Context, queryFilter cnstypes.CnsQueryFilter, querySelection cnstypes.CnsQuerySelection) (*cnstypes.CnsQueryResult, error) { + req := cnstypes.CnsQueryAllVolume{ + This: CnsVolumeManagerInstance, + Filter: queryFilter, + Selection: querySelection, + } + res, err := methods.CnsQueryAllVolume(ctx, c, &req) + if err != nil { + return nil, err + } + return &res.Returnval, nil +} + +// QueryVolumeAsync calls the CNS QueryAsync API and return a task, from which we can extract CnsQueryResult +func (c *Client) QueryVolumeAsync(ctx context.Context, queryFilter cnstypes.CnsQueryFilter, querySelection *cnstypes.CnsQuerySelection) (*object.Task, error) { + req := cnstypes.CnsQueryAsync{ + This: CnsVolumeManagerInstance, + Filter: queryFilter, + Selection: querySelection, + } + res, err := methods.CnsQueryAsync(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// RelocateVolume calls the CNS Relocate API. +func (c *Client) RelocateVolume(ctx context.Context, relocateSpecs ...cnstypes.BaseCnsVolumeRelocateSpec) (*object.Task, error) { + req := cnstypes.CnsRelocateVolume{ + This: CnsVolumeManagerInstance, + RelocateSpecs: relocateSpecs, + } + res, err := methods.CnsRelocateVolume(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// ConfigureVolumeACLs calls the CNS Configure ACL API. +func (c *Client) ConfigureVolumeACLs(ctx context.Context, aclConfigSpecs ...cnstypes.CnsVolumeACLConfigureSpec) (*object.Task, error) { + req := cnstypes.CnsConfigureVolumeACLs{ + This: CnsVolumeManagerInstance, + ACLConfigSpecs: aclConfigSpecs, + } + res, err := methods.CnsConfigureVolumeACLs(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// CreateSnapshots calls the CNS CreateSnapshots API + +func (c *Client) CreateSnapshots(ctx context.Context, snapshotCreateSpecList []cnstypes.CnsSnapshotCreateSpec) (*object.Task, error) { + req := cnstypes.CnsCreateSnapshots{ + This: CnsVolumeManagerInstance, + SnapshotSpecs: snapshotCreateSpecList, + } + res, err := methods.CnsCreateSnapshots(ctx, c, &req) + if err != nil { + return nil, err + } + + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// DeleteSnapshots calls the CNS DeleteSnapshots API +func (c *Client) DeleteSnapshots(ctx context.Context, snapshotDeleteSpecList []cnstypes.CnsSnapshotDeleteSpec) (*object.Task, error) { + req := cnstypes.CnsDeleteSnapshots{ + This: CnsVolumeManagerInstance, + SnapshotDeleteSpecs: snapshotDeleteSpecList, + } + res, err := methods.CnsDeleteSnapshots(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// QuerySnapshots calls the CNS QuerySnapshots API +func (c *Client) QuerySnapshots(ctx context.Context, snapshotQueryFilter cnstypes.CnsSnapshotQueryFilter) (*object.Task, error) { + req := cnstypes.CnsQuerySnapshots{ + This: CnsVolumeManagerInstance, + SnapshotQueryFilter: snapshotQueryFilter, + } + res, err := methods.CnsQuerySnapshots(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// ReconfigVolumePolicy calls the CnsReconfigVolumePolicy API +func (c *Client) ReconfigVolumePolicy(ctx context.Context, PolicyReconfigSpecs []cnstypes.CnsVolumePolicyReconfigSpec) (*object.Task, error) { + req := cnstypes.CnsReconfigVolumePolicy{ + This: CnsVolumeManagerInstance, + VolumePolicyReconfigSpecs: PolicyReconfigSpecs, + } + res, err := methods.CnsReconfigVolumePolicy(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} + +// SyncDatastore calls the CnsSyncDatastore API +// Note: To be used only by VMware's internal support tools. +// This API triggers a manual sync of internal CNS and FCD DBs which otherwise happens periodially, +// with fullsync it forces synchronization of complete tables. +func (c *Client) SyncDatastore(ctx context.Context, dsURL string, fullSync bool) (*object.Task, error) { + req := cnstypes.CnsSyncDatastore{ + This: CnsDebugManagerInstance, + DatastoreUrl: dsURL, + FullSync: &fullSync, + } + res, err := methods.CnsSyncDatastore(ctx, c, &req) + if err != nil { + return nil, err + } + return object.NewTask(c.vim25Client, res.Returnval), nil +} diff --git a/vendor/github.com/vmware/govmomi/cns/cns_util.go b/vendor/github.com/vmware/govmomi/cns/cns_util.go new file mode 100644 index 0000000000..d8d8b09df2 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/cns/cns_util.go @@ -0,0 +1,180 @@ +/* +Copyright (c) 2019 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cns + +import ( + "context" + "errors" + + cnstypes "github.com/vmware/govmomi/cns/types" + "github.com/vmware/govmomi/object" + vim25types "github.com/vmware/govmomi/vim25/types" +) + +// GetTaskInfo gets the task info given a task +func GetTaskInfo(ctx context.Context, task *object.Task) (*vim25types.TaskInfo, error) { + taskInfo, err := task.WaitForResult(ctx, nil) + if err != nil { + return nil, err + } + return taskInfo, nil +} + +// GetQuerySnapshotsTaskResult gets the task result of QuerySnapshots given a task info +func GetQuerySnapshotsTaskResult(ctx context.Context, taskInfo *vim25types.TaskInfo) (*cnstypes.CnsSnapshotQueryResult, error) { + if taskInfo == nil { + return nil, errors.New("TaskInfo is empty") + } + if taskInfo.Result != nil { + snapshotQueryResult := taskInfo.Result.(cnstypes.CnsSnapshotQueryResult) + if &snapshotQueryResult == nil { + return nil, errors.New("Cannot get SnapshotQueryResult") + } + return &snapshotQueryResult, nil + } + return nil, errors.New("TaskInfo result is empty") +} + +// GetTaskResult gets the task result given a task info +func GetTaskResult(ctx context.Context, taskInfo *vim25types.TaskInfo) (cnstypes.BaseCnsVolumeOperationResult, error) { + if taskInfo == nil { + return nil, errors.New("TaskInfo is empty") + } + if taskInfo.Result != nil { + volumeOperationBatchResult := taskInfo.Result.(cnstypes.CnsVolumeOperationBatchResult) + if &volumeOperationBatchResult == nil || + volumeOperationBatchResult.VolumeResults == nil || + len(volumeOperationBatchResult.VolumeResults) == 0 { + return nil, errors.New("Cannot get VolumeOperationResult") + } + return volumeOperationBatchResult.VolumeResults[0], nil + } + return nil, errors.New("TaskInfo result is empty") +} + +// GetTaskResultArray gets the task result array for a specified task info +func GetTaskResultArray(ctx context.Context, taskInfo *vim25types.TaskInfo) ([]cnstypes.BaseCnsVolumeOperationResult, error) { + if taskInfo == nil { + return nil, errors.New("TaskInfo is empty") + } + if taskInfo.Result != nil { + volumeOperationBatchResult := taskInfo.Result.(cnstypes.CnsVolumeOperationBatchResult) + if &volumeOperationBatchResult == nil || + volumeOperationBatchResult.VolumeResults == nil || + len(volumeOperationBatchResult.VolumeResults) == 0 { + return nil, errors.New("Cannot get VolumeOperationResult") + } + return volumeOperationBatchResult.VolumeResults, nil + } + return nil, errors.New("TaskInfo result is empty") +} + +// dropUnknownCreateSpecElements helps drop newly added elements in the CnsVolumeCreateSpec, which are not known to the prior vSphere releases +func dropUnknownCreateSpecElements(c *Client, createSpecList []cnstypes.CnsVolumeCreateSpec) []cnstypes.CnsVolumeCreateSpec { + updatedcreateSpecList := make([]cnstypes.CnsVolumeCreateSpec, 0, len(createSpecList)) + switch c.Version { + case ReleaseVSAN67u3: + // Dropping optional fields not known to vSAN 6.7U3 + for _, createSpec := range createSpecList { + createSpec.Metadata.ContainerCluster.ClusterFlavor = "" + createSpec.Metadata.ContainerCluster.ClusterDistribution = "" + createSpec.Metadata.ContainerClusterArray = nil + var updatedEntityMetadata []cnstypes.BaseCnsEntityMetadata + for _, entityMetadata := range createSpec.Metadata.EntityMetadata { + k8sEntityMetadata := interface{}(entityMetadata).(*cnstypes.CnsKubernetesEntityMetadata) + k8sEntityMetadata.ClusterID = "" + k8sEntityMetadata.ReferredEntity = nil + updatedEntityMetadata = append(updatedEntityMetadata, cnstypes.BaseCnsEntityMetadata(k8sEntityMetadata)) + } + createSpec.Metadata.EntityMetadata = updatedEntityMetadata + _, ok := createSpec.BackingObjectDetails.(*cnstypes.CnsBlockBackingDetails) + if ok { + createSpec.BackingObjectDetails.(*cnstypes.CnsBlockBackingDetails).BackingDiskUrlPath = "" + } + updatedcreateSpecList = append(updatedcreateSpecList, createSpec) + } + createSpecList = updatedcreateSpecList + case ReleaseVSAN70: + // Dropping optional fields not known to vSAN 7.0 + for _, createSpec := range createSpecList { + createSpec.Metadata.ContainerCluster.ClusterDistribution = "" + var updatedContainerClusterArray []cnstypes.CnsContainerCluster + for _, containerCluster := range createSpec.Metadata.ContainerClusterArray { + containerCluster.ClusterDistribution = "" + updatedContainerClusterArray = append(updatedContainerClusterArray, containerCluster) + } + createSpec.Metadata.ContainerClusterArray = updatedContainerClusterArray + _, ok := createSpec.BackingObjectDetails.(*cnstypes.CnsBlockBackingDetails) + if ok { + createSpec.BackingObjectDetails.(*cnstypes.CnsBlockBackingDetails).BackingDiskUrlPath = "" + } + updatedcreateSpecList = append(updatedcreateSpecList, createSpec) + } + createSpecList = updatedcreateSpecList + case ReleaseVSAN70u1: + // Dropping optional fields not known to vSAN 7.0U1 + for _, createSpec := range createSpecList { + createSpec.Metadata.ContainerCluster.ClusterDistribution = "" + var updatedContainerClusterArray []cnstypes.CnsContainerCluster + for _, containerCluster := range createSpec.Metadata.ContainerClusterArray { + containerCluster.ClusterDistribution = "" + updatedContainerClusterArray = append(updatedContainerClusterArray, containerCluster) + } + createSpec.Metadata.ContainerClusterArray = updatedContainerClusterArray + updatedcreateSpecList = append(updatedcreateSpecList, createSpec) + } + createSpecList = updatedcreateSpecList + } + return createSpecList +} + +// dropUnknownVolumeMetadataUpdateSpecElements helps drop newly added elements in the CnsVolumeMetadataUpdateSpec, which are not known to the prior vSphere releases +func dropUnknownVolumeMetadataUpdateSpecElements(c *Client, updateSpecList []cnstypes.CnsVolumeMetadataUpdateSpec) []cnstypes.CnsVolumeMetadataUpdateSpec { + // Dropping optional fields not known to vSAN 6.7U3 + if c.Version == ReleaseVSAN67u3 { + updatedUpdateSpecList := make([]cnstypes.CnsVolumeMetadataUpdateSpec, 0, len(updateSpecList)) + for _, updateSpec := range updateSpecList { + updateSpec.Metadata.ContainerCluster.ClusterFlavor = "" + updateSpec.Metadata.ContainerCluster.ClusterDistribution = "" + var updatedEntityMetadata []cnstypes.BaseCnsEntityMetadata + for _, entityMetadata := range updateSpec.Metadata.EntityMetadata { + k8sEntityMetadata := interface{}(entityMetadata).(*cnstypes.CnsKubernetesEntityMetadata) + k8sEntityMetadata.ClusterID = "" + k8sEntityMetadata.ReferredEntity = nil + updatedEntityMetadata = append(updatedEntityMetadata, cnstypes.BaseCnsEntityMetadata(k8sEntityMetadata)) + } + updateSpec.Metadata.ContainerClusterArray = nil + updateSpec.Metadata.EntityMetadata = updatedEntityMetadata + updatedUpdateSpecList = append(updatedUpdateSpecList, updateSpec) + } + updateSpecList = updatedUpdateSpecList + } else if c.Version == ReleaseVSAN70 || c.Version == ReleaseVSAN70u1 { + updatedUpdateSpecList := make([]cnstypes.CnsVolumeMetadataUpdateSpec, 0, len(updateSpecList)) + for _, updateSpec := range updateSpecList { + updateSpec.Metadata.ContainerCluster.ClusterDistribution = "" + var updatedContainerClusterArray []cnstypes.CnsContainerCluster + for _, containerCluster := range updateSpec.Metadata.ContainerClusterArray { + containerCluster.ClusterDistribution = "" + updatedContainerClusterArray = append(updatedContainerClusterArray, containerCluster) + } + updateSpec.Metadata.ContainerClusterArray = updatedContainerClusterArray + updatedUpdateSpecList = append(updatedUpdateSpecList, updateSpec) + } + updateSpecList = updatedUpdateSpecList + } + return updateSpecList +} diff --git a/vendor/github.com/vmware/govmomi/cns/methods/methods.go b/vendor/github.com/vmware/govmomi/cns/methods/methods.go new file mode 100644 index 0000000000..da9318cac0 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/cns/methods/methods.go @@ -0,0 +1,369 @@ +/* +Copyright (c) 2019 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package methods + +import ( + "context" + + "github.com/vmware/govmomi/cns/types" + "github.com/vmware/govmomi/vim25/soap" +) + +type CnsCreateVolumeBody struct { + Req *types.CnsCreateVolume `xml:"urn:vsan CnsCreateVolume,omitempty"` + Res *types.CnsCreateVolumeResponse `xml:"urn:vsan CnsCreateVolumeResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsCreateVolumeBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsCreateVolume(ctx context.Context, r soap.RoundTripper, req *types.CnsCreateVolume) (*types.CnsCreateVolumeResponse, error) { + var reqBody, resBody CnsCreateVolumeBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsUpdateVolumeBody struct { + Req *types.CnsUpdateVolumeMetadata `xml:"urn:vsan CnsUpdateVolumeMetadata,omitempty"` + Res *types.CnsUpdateVolumeMetadataResponse `xml:"urn:vsan CnsUpdateVolumeMetadataResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsUpdateVolumeBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsUpdateVolumeMetadata(ctx context.Context, r soap.RoundTripper, req *types.CnsUpdateVolumeMetadata) (*types.CnsUpdateVolumeMetadataResponse, error) { + var reqBody, resBody CnsUpdateVolumeBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsDeleteVolumeBody struct { + Req *types.CnsDeleteVolume `xml:"urn:vsan CnsDeleteVolume,omitempty"` + Res *types.CnsDeleteVolumeResponse `xml:"urn:vsan CnsDeleteVolumeResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsDeleteVolumeBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsDeleteVolume(ctx context.Context, r soap.RoundTripper, req *types.CnsDeleteVolume) (*types.CnsDeleteVolumeResponse, error) { + var reqBody, resBody CnsDeleteVolumeBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsExtendVolumeBody struct { + Req *types.CnsExtendVolume `xml:"urn:vsan CnsExtendVolume,omitempty"` + Res *types.CnsExtendVolumeResponse `xml:"urn:vsan CnsExtendVolumeResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsExtendVolumeBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsExtendVolume(ctx context.Context, r soap.RoundTripper, req *types.CnsExtendVolume) (*types.CnsExtendVolumeResponse, error) { + var reqBody, resBody CnsExtendVolumeBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsAttachVolumeBody struct { + Req *types.CnsAttachVolume `xml:"urn:vsan CnsAttachVolume,omitempty"` + Res *types.CnsAttachVolumeResponse `xml:"urn:vsan CnsAttachVolumeResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsAttachVolumeBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsAttachVolume(ctx context.Context, r soap.RoundTripper, req *types.CnsAttachVolume) (*types.CnsAttachVolumeResponse, error) { + var reqBody, resBody CnsAttachVolumeBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsDetachVolumeBody struct { + Req *types.CnsDetachVolume `xml:"urn:vsan CnsDetachVolume,omitempty"` + Res *types.CnsDetachVolumeResponse `xml:"urn:vsan CnsDetachVolumeResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsDetachVolumeBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsDetachVolume(ctx context.Context, r soap.RoundTripper, req *types.CnsDetachVolume) (*types.CnsDetachVolumeResponse, error) { + var reqBody, resBody CnsDetachVolumeBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsQueryVolumeBody struct { + Req *types.CnsQueryVolume `xml:"urn:vsan CnsQueryVolume,omitempty"` + Res *types.CnsQueryVolumeResponse `xml:"urn:vsan CnsQueryVolumeResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsQueryVolumeBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsQueryVolume(ctx context.Context, r soap.RoundTripper, req *types.CnsQueryVolume) (*types.CnsQueryVolumeResponse, error) { + var reqBody, resBody CnsQueryVolumeBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsQueryVolumeInfoBody struct { + Req *types.CnsQueryVolumeInfo `xml:"urn:vsan CnsQueryVolumeInfo,omitempty"` + Res *types.CnsQueryVolumeInfoResponse `xml:"urn:vsan CnsQueryVolumeInfoResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsQueryVolumeInfoBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsQueryVolumeInfo(ctx context.Context, r soap.RoundTripper, req *types.CnsQueryVolumeInfo) (*types.CnsQueryVolumeInfoResponse, error) { + var reqBody, resBody CnsQueryVolumeInfoBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsQueryAllVolumeBody struct { + Req *types.CnsQueryAllVolume `xml:"urn:vsan CnsQueryAllVolume,omitempty"` + Res *types.CnsQueryAllVolumeResponse `xml:"urn:vsan CnsQueryAllVolumeResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsQueryAllVolumeBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsQueryAllVolume(ctx context.Context, r soap.RoundTripper, req *types.CnsQueryAllVolume) (*types.CnsQueryAllVolumeResponse, error) { + var reqBody, resBody CnsQueryAllVolumeBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsRelocateVolumeBody struct { + Req *types.CnsRelocateVolume `xml:"urn:vsan CnsRelocateVolume,omitempty"` + Res *types.CnsRelocateVolumeResponse `xml:"urn:vsan CnsRelocateVolumeResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsRelocateVolumeBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsRelocateVolume(ctx context.Context, r soap.RoundTripper, req *types.CnsRelocateVolume) (*types.CnsRelocateVolumeResponse, error) { + var reqBody, resBody CnsRelocateVolumeBody + reqBody.Req = req + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsConfigureVolumeACLsBody struct { + Req *types.CnsConfigureVolumeACLs `xml:"urn:vsan CnsConfigureVolumeACLs,omitempty"` + Res *types.CnsConfigureVolumeACLsResponse `xml:"urn:vsan CnsConfigureVolumeACLsResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsConfigureVolumeACLsBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsConfigureVolumeACLs(ctx context.Context, r soap.RoundTripper, req *types.CnsConfigureVolumeACLs) (*types.CnsConfigureVolumeACLsResponse, error) { + var reqBody, resBody CnsConfigureVolumeACLsBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsQueryAsyncBody struct { + Req *types.CnsQueryAsync `xml:"urn:vsan CnsQueryAsync,omitempty"` + Res *types.CnsQueryAsyncResponse `xml:"urn:vsan CnsQueryAsyncResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsQueryAsyncBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsQueryAsync(ctx context.Context, r soap.RoundTripper, req *types.CnsQueryAsync) (*types.CnsQueryAsyncResponse, error) { + var reqBody, resBody CnsQueryAsyncBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +// CNS CreateSnapshots API + +type CnsCreateSnapshotsBody struct { + Req *types.CnsCreateSnapshots `xml:"urn:vsan CnsCreateSnapshots,omitempty"` + Res *types.CnsCreateSnapshotsResponse `xml:"urn:vsan CnsCreateSnapshotsResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsCreateSnapshotsBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsCreateSnapshots(ctx context.Context, r soap.RoundTripper, req *types.CnsCreateSnapshots) (*types.CnsCreateSnapshotsResponse, error) { + var reqBody, resBody CnsCreateSnapshotsBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +// CNS DeleteSnapshot API + +type CnsDeleteSnapshotBody struct { + Req *types.CnsDeleteSnapshots `xml:"urn:vsan CnsDeleteSnapshots,omitempty"` + Res *types.CnsDeleteSnapshotsResponse `xml:"urn:vsan CnsDeleteSnapshotsResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsDeleteSnapshotBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsDeleteSnapshots(ctx context.Context, r soap.RoundTripper, req *types.CnsDeleteSnapshots) (*types.CnsDeleteSnapshotsResponse, error) { + var reqBody, resBody CnsDeleteSnapshotBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +// CNS QuerySnapshots API + +type CnsQuerySnapshotsBody struct { + Req *types.CnsQuerySnapshots `xml:"urn:vsan CnsQuerySnapshots,omitempty"` + Res *types.CnsQuerySnapshotsResponse `xml:"urn:vsan CnsQuerySnapshotsResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsQuerySnapshotsBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsQuerySnapshots(ctx context.Context, r soap.RoundTripper, req *types.CnsQuerySnapshots) (*types.CnsQuerySnapshotsResponse, error) { + var reqBody, resBody CnsQuerySnapshotsBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsReconfigVolumePolicyBody struct { + Req *types.CnsReconfigVolumePolicy `xml:"urn:vsan CnsReconfigVolumePolicy,omitempty"` + Res *types.CnsReconfigVolumePolicyResponse `xml:"urn:vsan CnsReconfigVolumePolicyResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsReconfigVolumePolicyBody) Fault() *soap.Fault { return b.Fault_ } + +func CnsReconfigVolumePolicy(ctx context.Context, r soap.RoundTripper, req *types.CnsReconfigVolumePolicy) (*types.CnsReconfigVolumePolicyResponse, error) { + var reqBody, resBody CnsReconfigVolumePolicyBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} + +type CnsSyncDatastoreBody struct { + Req *types.CnsSyncDatastore `xml:"urn:vsan CnsSyncDatastore,omitempty"` + Res *types.CnsSyncDatastoreResponse `xml:"urn:vsan CnsSyncDatastoreResponse,omitempty"` + Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"` +} + +func (b *CnsSyncDatastoreBody) Fault() *soap.Fault { return b.Fault_ } + +// Note: To be used only by VMware's internal support tools. +func CnsSyncDatastore(ctx context.Context, r soap.RoundTripper, req *types.CnsSyncDatastore) (*types.CnsSyncDatastoreResponse, error) { + var reqBody, resBody CnsSyncDatastoreBody + + reqBody.Req = req + + if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil { + return nil, err + } + + return resBody.Res, nil +} diff --git a/vendor/github.com/vmware/govmomi/cns/types/enum.go b/vendor/github.com/vmware/govmomi/cns/types/enum.go new file mode 100644 index 0000000000..09186eea49 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/cns/types/enum.go @@ -0,0 +1,99 @@ +/* +Copyright (c) 2019 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package types + +import ( + "reflect" + + "github.com/vmware/govmomi/vim25/types" +) + +type CnsVolumeType string + +const ( + CnsVolumeTypeBlock = CnsVolumeType("BLOCK") + CnsVolumeTypeFile = CnsVolumeType("FILE") +) + +func init() { + types.Add("CnsVolumeType", reflect.TypeOf((*CnsVolumeType)(nil)).Elem()) +} + +type CnsClusterFlavor string + +const ( + CnsClusterFlavorVanilla = CnsClusterFlavor("VANILLA") + CnsClusterFlavorWorkload = CnsClusterFlavor("WORKLOAD") + CnsClusterFlavorGuest = CnsClusterFlavor("GUEST_CLUSTER") + CnsClusterFlavorUnknown = CnsClusterFlavor("ClusterFlavor_Unknown") +) + +func init() { + types.Add("CnsClusterFlavor", reflect.TypeOf((*CnsClusterFlavor)(nil)).Elem()) +} + +type QuerySelectionNameType string + +const ( + QuerySelectionNameTypeVolumeType = QuerySelectionNameType("VOLUME_TYPE") + QuerySelectionNameTypeVolumeName = QuerySelectionNameType("VOLUME_NAME") + QuerySelectionNameTypeBackingObjectDetails = QuerySelectionNameType("BACKING_OBJECT_DETAILS") + QuerySelectionNameTypeComplianceStatus = QuerySelectionNameType("COMPLIANCE_STATUS") + QuerySelectionNameTypeDataStoreAccessibility = QuerySelectionNameType("DATASTORE_ACCESSIBILITY_STATUS") + QuerySelectionNameTypeHealthStatus = QuerySelectionNameType("HEALTH_STATUS") + QuerySelectionNameTypeDataStoreUrl = QuerySelectionNameType("DATASTORE_URL") + QuerySelectionNameTypePolicyId = QuerySelectionNameType("POLICY_ID") +) + +func init() { + types.Add("QuerySelectionNameType", reflect.TypeOf((*QuerySelectionNameType)(nil)).Elem()) +} + +type CnsClusterType string + +const ( + CnsClusterTypeKubernetes = CnsClusterType("KUBERNETES") +) + +func init() { + types.Add("CnsClusterType", reflect.TypeOf((*CnsClusterType)(nil)).Elem()) +} + +type CnsKubernetesEntityType string + +const ( + CnsKubernetesEntityTypePVC = CnsKubernetesEntityType("PERSISTENT_VOLUME_CLAIM") + CnsKubernetesEntityTypePV = CnsKubernetesEntityType("PERSISTENT_VOLUME") + CnsKubernetesEntityTypePOD = CnsKubernetesEntityType("POD") +) + +type CnsQuerySelectionNameType string + +const ( + CnsQuerySelectionName_VOLUME_NAME = CnsQuerySelectionNameType("VOLUME_NAME") + CnsQuerySelectionName_VOLUME_TYPE = CnsQuerySelectionNameType("VOLUME_TYPE") + CnsQuerySelectionName_BACKING_OBJECT_DETAILS = CnsQuerySelectionNameType("BACKING_OBJECT_DETAILS") + CnsQuerySelectionName_COMPLIANCE_STATUS = CnsQuerySelectionNameType("COMPLIANCE_STATUS") + CnsQuerySelectionName_DATASTORE_ACCESSIBILITY_STATUS = CnsQuerySelectionNameType("DATASTORE_ACCESSIBILITY_STATUS") + CnsQuerySelectionName_HEALTH_STATUS = CnsQuerySelectionNameType("HEALTH_STATUS") + CnsQuerySelectionName_DATASTORE_URL = CnsQuerySelectionNameType("DATASTORE_URL") + CnsQuerySelectionName_POLICY_ID = CnsQuerySelectionNameType("POLICY_ID") +) + +func init() { + types.Add("CnsKubernetesEntityType", reflect.TypeOf((*CnsKubernetesEntityType)(nil)).Elem()) +} diff --git a/vendor/github.com/vmware/govmomi/cns/types/if.go b/vendor/github.com/vmware/govmomi/cns/types/if.go new file mode 100644 index 0000000000..42a70ec73f --- /dev/null +++ b/vendor/github.com/vmware/govmomi/cns/types/if.go @@ -0,0 +1,117 @@ +/* +Copyright (c) 2019 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package types + +import ( + "reflect" + + "github.com/vmware/govmomi/vim25/types" +) + +func (b *CnsFault) GetCnsFault() *CnsFault { + return b +} + +type BaseCnsFault interface { + GetCnsFault() *CnsFault +} + +func init() { + types.Add("BaseCnsFault", reflect.TypeOf((*CnsFault)(nil)).Elem()) +} + +func (b *CnsAlreadyRegisteredFault) GetCnsAlreadyRegisteredFault() *CnsAlreadyRegisteredFault { + return b +} + +type BaseCnsAlreadyRegisteredFault interface { + GetCnsAlreadyRegisteredFault() *CnsAlreadyRegisteredFault +} + +func init() { + types.Add("BaseCnsAlreadyRegisteredFault", reflect.TypeOf((*CnsAlreadyRegisteredFault)(nil)).Elem()) +} + +func (b *CnsBackingObjectDetails) GetCnsBackingObjectDetails() *CnsBackingObjectDetails { return b } + +type BaseCnsBackingObjectDetails interface { + GetCnsBackingObjectDetails() *CnsBackingObjectDetails +} + +func init() { + types.Add("BaseCnsBackingObjectDetails", reflect.TypeOf((*CnsBackingObjectDetails)(nil)).Elem()) +} + +func (b *CnsBaseCreateSpec) GetCnsBaseCreateSpec() *CnsBaseCreateSpec { return b } + +type BaseCnsBaseCreateSpec interface { + GetCnsBaseCreateSpec() *CnsBaseCreateSpec +} + +func init() { + types.Add("BaseCnsBaseCreateSpec", reflect.TypeOf((*CnsBaseCreateSpec)(nil)).Elem()) +} + +type BaseCnsVolumeRelocateSpec interface { + GetCnsVolumeRelocateSpec() CnsVolumeRelocateSpec +} + +func (s CnsVolumeRelocateSpec) GetCnsVolumeRelocateSpec() CnsVolumeRelocateSpec { return s } + +func init() { + types.Add("BaseCnsVolumeRelocateSpec", reflect.TypeOf((*CnsVolumeRelocateSpec)(nil)).Elem()) +} + +func (b *CnsEntityMetadata) GetCnsEntityMetadata() *CnsEntityMetadata { return b } + +type BaseCnsEntityMetadata interface { + GetCnsEntityMetadata() *CnsEntityMetadata +} + +func init() { + types.Add("BaseCnsEntityMetadata", reflect.TypeOf((*CnsEntityMetadata)(nil)).Elem()) +} + +func (b *CnsVolumeInfo) GetCnsVolumeInfo() *CnsVolumeInfo { return b } + +type BaseCnsVolumeInfo interface { + GetCnsVolumeInfo() *CnsVolumeInfo +} + +func init() { + types.Add("BaseCnsVolumeInfo", reflect.TypeOf((*CnsVolumeInfo)(nil)).Elem()) +} + +func (b *CnsVolumeOperationResult) GetCnsVolumeOperationResult() *CnsVolumeOperationResult { return b } + +type BaseCnsVolumeOperationResult interface { + GetCnsVolumeOperationResult() *CnsVolumeOperationResult +} + +func init() { + types.Add("BaseCnsVolumeOperationResult", reflect.TypeOf((*CnsVolumeOperationResult)(nil)).Elem()) +} + +func (b *CnsVolumeSource) GetCnsVolumeSource() *CnsVolumeSource { return b } + +type BaseCnsVolumeSource interface { + GetCnsVolumeSource() *CnsVolumeSource +} + +func init() { + types.Add("BaseCnsVolumeSource", reflect.TypeOf((*CnsVolumeSource)(nil)).Elem()) +} diff --git a/vendor/github.com/vmware/govmomi/cns/types/types.go b/vendor/github.com/vmware/govmomi/cns/types/types.go new file mode 100644 index 0000000000..d493e99c59 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/cns/types/types.go @@ -0,0 +1,931 @@ +/* +Copyright (c) 2019 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package types + +import ( + "reflect" + "time" + + "github.com/vmware/govmomi/vim25/types" + vsanfstypes "github.com/vmware/govmomi/vsan/vsanfs/types" +) + +type CnsCreateVolumeRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + CreateSpecs []CnsVolumeCreateSpec `xml:"createSpecs,omitempty"` +} + +func init() { + types.Add("CnsCreateVolumeRequestType", reflect.TypeOf((*CnsCreateVolumeRequestType)(nil)).Elem()) +} + +type CnsCreateVolume CnsCreateVolumeRequestType + +func init() { + types.Add("CnsCreateVolume", reflect.TypeOf((*CnsCreateVolume)(nil)).Elem()) +} + +type CnsCreateVolumeResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsEntityMetadata struct { + types.DynamicData + + EntityName string `xml:"entityName"` + Labels []types.KeyValue `xml:"labels,omitempty"` + Delete bool `xml:"delete,omitempty"` + ClusterID string `xml:"clusterId,omitempty"` +} + +func init() { + types.Add("CnsEntityMetadata", reflect.TypeOf((*CnsEntityMetadata)(nil)).Elem()) +} + +type CnsKubernetesEntityReference struct { + EntityType string `xml:"entityType"` + EntityName string `xml:"entityName"` + Namespace string `xml:"namespace,omitempty"` + ClusterID string `xml:"clusterId,omitempty"` +} + +type CnsKubernetesEntityMetadata struct { + CnsEntityMetadata + + EntityType string `xml:"entityType"` + Namespace string `xml:"namespace,omitempty"` + ReferredEntity []CnsKubernetesEntityReference `xml:"referredEntity,omitempty"` +} + +func init() { + types.Add("CnsKubernetesEntityMetadata", reflect.TypeOf((*CnsKubernetesEntityMetadata)(nil)).Elem()) +} + +type CnsVolumeMetadata struct { + types.DynamicData + + ContainerCluster CnsContainerCluster `xml:"containerCluster"` + EntityMetadata []BaseCnsEntityMetadata `xml:"entityMetadata,typeattr,omitempty"` + ContainerClusterArray []CnsContainerCluster `xml:"containerClusterArray,omitempty"` +} + +func init() { + types.Add("CnsVolumeMetadata", reflect.TypeOf((*CnsVolumeMetadata)(nil)).Elem()) +} + +type CnsVolumeCreateSpec struct { + types.DynamicData + Name string `xml:"name"` + VolumeType string `xml:"volumeType"` + Datastores []types.ManagedObjectReference `xml:"datastores,omitempty"` + Metadata CnsVolumeMetadata `xml:"metadata,omitempty"` + BackingObjectDetails BaseCnsBackingObjectDetails `xml:"backingObjectDetails,typeattr"` + Profile []types.BaseVirtualMachineProfileSpec `xml:"profile,omitempty,typeattr"` + CreateSpec BaseCnsBaseCreateSpec `xml:"createSpec,omitempty,typeattr"` + VolumeSource BaseCnsVolumeSource `xml:"volumeSource,omitempty,typeattr"` +} + +func init() { + types.Add("CnsVolumeCreateSpec", reflect.TypeOf((*CnsVolumeCreateSpec)(nil)).Elem()) +} + +type CnsUpdateVolumeMetadataRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + UpdateSpecs []CnsVolumeMetadataUpdateSpec `xml:"updateSpecs,omitempty"` +} + +func init() { + types.Add("CnsUpdateVolumeMetadataRequestType", reflect.TypeOf((*CnsUpdateVolumeMetadataRequestType)(nil)).Elem()) +} + +type CnsUpdateVolumeMetadata CnsUpdateVolumeMetadataRequestType + +func init() { + types.Add("CnsUpdateVolumeMetadata", reflect.TypeOf((*CnsUpdateVolumeMetadata)(nil)).Elem()) +} + +type CnsUpdateVolumeMetadataResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsVolumeMetadataUpdateSpec struct { + types.DynamicData + + VolumeId CnsVolumeId `xml:"volumeId"` + Metadata CnsVolumeMetadata `xml:"metadata,omitempty"` +} + +func init() { + types.Add("CnsVolumeMetadataUpdateSpec", reflect.TypeOf((*CnsVolumeMetadataUpdateSpec)(nil)).Elem()) +} + +type CnsDeleteVolumeRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + VolumeIds []CnsVolumeId `xml:"volumeIds"` + DeleteDisk bool `xml:"deleteDisk"` +} + +func init() { + types.Add("CnsDeleteVolumeRequestType", reflect.TypeOf((*CnsDeleteVolumeRequestType)(nil)).Elem()) +} + +type CnsDeleteVolume CnsDeleteVolumeRequestType + +func init() { + types.Add("CnsDeleteVolume", reflect.TypeOf((*CnsDeleteVolume)(nil)).Elem()) +} + +type CnsDeleteVolumeResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsExtendVolumeRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + ExtendSpecs []CnsVolumeExtendSpec `xml:"extendSpecs,omitempty"` +} + +func init() { + types.Add("CnsExtendVolumeRequestType", reflect.TypeOf((*CnsExtendVolumeRequestType)(nil)).Elem()) +} + +type CnsExtendVolume CnsExtendVolumeRequestType + +func init() { + types.Add("CnsExtendVolume", reflect.TypeOf((*CnsExtendVolume)(nil)).Elem()) +} + +type CnsExtendVolumeResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsVolumeExtendSpec struct { + types.DynamicData + + VolumeId CnsVolumeId `xml:"volumeId"` + CapacityInMb int64 `xml:"capacityInMb"` +} + +func init() { + types.Add("CnsVolumeExtendSpec", reflect.TypeOf((*CnsVolumeExtendSpec)(nil)).Elem()) +} + +type CnsAttachVolumeRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + AttachSpecs []CnsVolumeAttachDetachSpec `xml:"attachSpecs,omitempty"` +} + +func init() { + types.Add("CnsAttachVolumeRequestType", reflect.TypeOf((*CnsAttachVolumeRequestType)(nil)).Elem()) +} + +type CnsAttachVolume CnsAttachVolumeRequestType + +func init() { + types.Add("CnsAttachVolume", reflect.TypeOf((*CnsAttachVolume)(nil)).Elem()) +} + +type CnsAttachVolumeResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsDetachVolumeRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + DetachSpecs []CnsVolumeAttachDetachSpec `xml:"detachSpecs,omitempty"` +} + +func init() { + types.Add("CnsDetachVolumeRequestType", reflect.TypeOf((*CnsDetachVolumeRequestType)(nil)).Elem()) +} + +type CnsDetachVolume CnsDetachVolumeRequestType + +func init() { + types.Add("CnsDetachVolume", reflect.TypeOf((*CnsDetachVolume)(nil)).Elem()) +} + +type CnsDetachVolumeResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsVolumeAttachDetachSpec struct { + types.DynamicData + + VolumeId CnsVolumeId `xml:"volumeId"` + Vm types.ManagedObjectReference `xml:"vm"` +} + +func init() { + types.Add("CnsVolumeAttachDetachSpec", reflect.TypeOf((*CnsVolumeAttachDetachSpec)(nil)).Elem()) +} + +type CnsQueryVolume CnsQueryVolumeRequestType + +func init() { + types.Add("CnsQueryVolume", reflect.TypeOf((*CnsQueryVolume)(nil)).Elem()) +} + +type CnsQueryVolumeRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + Filter CnsQueryFilter `xml:"filter"` +} + +func init() { + types.Add("CnsQueryVolumeRequestType", reflect.TypeOf((*CnsQueryVolumeRequestType)(nil)).Elem()) +} + +type CnsQueryVolumeResponse struct { + Returnval CnsQueryResult `xml:"returnval"` +} + +type CnsQueryVolumeInfo CnsQueryVolumeInfoRequestType + +func init() { + types.Add("CnsQueryVolumeInfo", reflect.TypeOf((*CnsQueryVolumeInfo)(nil)).Elem()) +} + +type CnsQueryVolumeInfoRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + VolumeIds []CnsVolumeId `xml:"volumes"` +} + +type CnsQueryVolumeInfoResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsQueryAllVolume CnsQueryAllVolumeRequestType + +func init() { + types.Add("CnsQueryAllVolume", reflect.TypeOf((*CnsQueryAllVolume)(nil)).Elem()) +} + +type CnsQueryAllVolumeRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + Filter CnsQueryFilter `xml:"filter"` + Selection CnsQuerySelection `xml:"selection"` +} + +func init() { + types.Add("CnsQueryAllVolumeRequestType", reflect.TypeOf((*CnsQueryVolumeRequestType)(nil)).Elem()) +} + +type CnsQueryAllVolumeResponse struct { + Returnval CnsQueryResult `xml:"returnval"` +} + +type CnsContainerCluster struct { + types.DynamicData + + ClusterType string `xml:"clusterType"` + ClusterId string `xml:"clusterId"` + VSphereUser string `xml:"vSphereUser"` + ClusterFlavor string `xml:"clusterFlavor,omitempty"` + ClusterDistribution string `xml:"clusterDistribution,omitempty"` +} + +func init() { + types.Add("CnsContainerCluster", reflect.TypeOf((*CnsContainerCluster)(nil)).Elem()) +} + +type CnsVolume struct { + types.DynamicData + + VolumeId CnsVolumeId `xml:"volumeId"` + DatastoreUrl string `xml:"datastoreUrl,omitempty"` + Name string `xml:"name,omitempty"` + VolumeType string `xml:"volumeType,omitempty"` + StoragePolicyId string `xml:"storagePolicyId,omitempty"` + Metadata CnsVolumeMetadata `xml:"metadata,omitempty"` + BackingObjectDetails BaseCnsBackingObjectDetails `xml:"backingObjectDetails,omitempty"` + ComplianceStatus string `xml:"complianceStatus,omitempty"` + DatastoreAccessibilityStatus string `xml:"datastoreAccessibilityStatus,omitempty"` + HealthStatus string `xml:"healthStatus,omitempty"` +} + +func init() { + types.Add("CnsVolume", reflect.TypeOf((*CnsVolume)(nil)).Elem()) +} + +type CnsVolumeOperationResult struct { + types.DynamicData + + VolumeId CnsVolumeId `xml:"volumeId,omitempty"` + Fault *types.LocalizedMethodFault `xml:"fault,omitempty"` +} + +func init() { + types.Add("CnsVolumeOperationResult", reflect.TypeOf((*CnsVolumeOperationResult)(nil)).Elem()) +} + +type CnsVolumeOperationBatchResult struct { + types.DynamicData + + VolumeResults []BaseCnsVolumeOperationResult `xml:"volumeResults,omitempty,typeattr"` +} + +func init() { + types.Add("CnsVolumeOperationBatchResult", reflect.TypeOf((*CnsVolumeOperationBatchResult)(nil)).Elem()) +} + +type CnsPlacementResult struct { + Datastore types.ManagedObjectReference `xml:"datastore,omitempty"` + PlacementFaults []*types.LocalizedMethodFault `xml:"placementFaults,omitempty"` +} + +func init() { + types.Add("CnsPlacementResult", reflect.TypeOf((*CnsPlacementResult)(nil)).Elem()) +} + +type CnsVolumeCreateResult struct { + CnsVolumeOperationResult + Name string `xml:"name,omitempty"` + PlacementResults []CnsPlacementResult `xml:"placementResults,omitempty"` +} + +func init() { + types.Add("CnsVolumeCreateResult", reflect.TypeOf((*CnsVolumeCreateResult)(nil)).Elem()) +} + +type CnsVolumeAttachResult struct { + CnsVolumeOperationResult + + DiskUUID string `xml:"diskUUID,omitempty"` +} + +func init() { + types.Add("CnsVolumeAttachResult", reflect.TypeOf((*CnsVolumeAttachResult)(nil)).Elem()) +} + +type CnsVolumeId struct { + types.DynamicData + + Id string `xml:"id"` +} + +func init() { + types.Add("CnsVolumeId", reflect.TypeOf((*CnsVolumeId)(nil)).Elem()) +} + +type CnsBackingObjectDetails struct { + types.DynamicData + + CapacityInMb int64 `xml:"capacityInMb,omitempty"` +} + +func init() { + types.Add("CnsBackingObjectDetails", reflect.TypeOf((*CnsBackingObjectDetails)(nil)).Elem()) +} + +type CnsBlockBackingDetails struct { + CnsBackingObjectDetails + + BackingDiskId string `xml:"backingDiskId,omitempty"` + BackingDiskUrlPath string `xml:"backingDiskUrlPath,omitempty"` + BackingDiskObjectId string `xml:"backingDiskObjectId,omitempty"` +} + +func init() { + types.Add("CnsBlockBackingDetails", reflect.TypeOf((*CnsBlockBackingDetails)(nil)).Elem()) +} + +type CnsFileBackingDetails struct { + CnsBackingObjectDetails + + BackingFileId string `xml:"backingFileId,omitempty"` +} + +func init() { + types.Add("CnsFileBackingDetails", reflect.TypeOf((*CnsFileBackingDetails)(nil)).Elem()) +} + +type CnsVsanFileShareBackingDetails struct { + CnsFileBackingDetails + + Name string `xml:"name,omitempty"` + AccessPoints []types.KeyValue `xml:"accessPoints,omitempty"` +} + +func init() { + types.Add("CnsVsanFileShareBackingDetails", reflect.TypeOf((*CnsVsanFileShareBackingDetails)(nil)).Elem()) +} + +type CnsBaseCreateSpec struct { + types.DynamicData +} + +func init() { + types.Add("CnsBaseCreateSpec", reflect.TypeOf((*CnsBaseCreateSpec)(nil)).Elem()) +} + +type CnsFileCreateSpec struct { + CnsBaseCreateSpec +} + +func init() { + types.Add("CnsFileCreateSpec", reflect.TypeOf((*CnsFileCreateSpec)(nil)).Elem()) +} + +type CnsVSANFileCreateSpec struct { + CnsFileCreateSpec + SoftQuotaInMb int64 `xml:"softQuotaInMb,omitempty"` + Permission []vsanfstypes.VsanFileShareNetPermission `xml:"permission,omitempty,typeattr"` +} + +func init() { + types.Add("CnsVSANFileCreateSpec", reflect.TypeOf((*CnsVSANFileCreateSpec)(nil)).Elem()) +} + +type CnsQueryFilter struct { + types.DynamicData + + VolumeIds []CnsVolumeId `xml:"volumeIds,omitempty"` + Names []string `xml:"names,omitempty"` + ContainerClusterIds []string `xml:"containerClusterIds,omitempty"` + StoragePolicyId string `xml:"storagePolicyId,omitempty"` + Datastores []types.ManagedObjectReference `xml:"datastores,omitempty"` + Labels []types.KeyValue `xml:"labels,omitempty"` + ComplianceStatus string `xml:"complianceStatus,omitempty"` + DatastoreAccessibilityStatus string `xml:"datastoreAccessibilityStatus,omitempty"` + Cursor *CnsCursor `xml:"cursor,omitempty"` + HealthStatus string `xml:"healthStatus,omitempty"` +} + +func init() { + types.Add("CnsQueryFilter", reflect.TypeOf((*CnsQueryFilter)(nil)).Elem()) +} + +type CnsQuerySelection struct { + types.DynamicData + + Names []string `xml:"names,omitempty"` +} + +type CnsQueryResult struct { + types.DynamicData + + Volumes []CnsVolume `xml:"volumes,omitempty"` + Cursor CnsCursor `xml:"cursor"` +} + +func init() { + types.Add("CnsQueryResult", reflect.TypeOf((*CnsQueryResult)(nil)).Elem()) +} + +type CnsVolumeInfo struct { + types.DynamicData +} + +func init() { + types.Add("CnsVolumeInfo", reflect.TypeOf((*CnsVolumeInfo)(nil)).Elem()) +} + +type CnsBlockVolumeInfo struct { + CnsVolumeInfo + + VStorageObject types.VStorageObject `xml:"vStorageObject"` +} + +func init() { + types.Add("CnsBlockVolumeInfo", reflect.TypeOf((*CnsBlockVolumeInfo)(nil)).Elem()) +} + +type CnsQueryVolumeInfoResult struct { + CnsVolumeOperationResult + + VolumeInfo BaseCnsVolumeInfo `xml:"volumeInfo,typeattr,omitempty"` +} + +func init() { + types.Add("CnsQueryVolumeInfoResult", reflect.TypeOf((*CnsQueryVolumeInfoResult)(nil)).Elem()) +} + +type CnsRelocateVolumeRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + RelocateSpecs []BaseCnsVolumeRelocateSpec `xml:"relocateSpecs,typeattr"` +} + +func init() { + types.Add("CnsRelocateVolumeRequestType", reflect.TypeOf((*CnsRelocateVolumeRequestType)(nil)).Elem()) +} + +type CnsRelocateVolume CnsRelocateVolumeRequestType + +func init() { + types.Add("CnsRelocateVolume", reflect.TypeOf((*CnsRelocateVolume)(nil)).Elem()) +} + +type CnsRelocateVolumeResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsVolumeRelocateSpec struct { + types.DynamicData + + VolumeId CnsVolumeId `xml:"volumeId"` + Datastore types.ManagedObjectReference `xml:"datastore"` + Profile []types.BaseVirtualMachineProfileSpec `xml:"profile,omitempty,typeattr"` +} + +func init() { + types.Add("CnsVolumeRelocateSpec", reflect.TypeOf((*CnsVolumeRelocateSpec)(nil)).Elem()) +} + +type CnsBlockVolumeRelocateSpec struct { + CnsVolumeRelocateSpec +} + +func NewCnsBlockVolumeRelocateSpec(volumeId string, datastore types.ManagedObjectReference, profile ...types.BaseVirtualMachineProfileSpec) CnsBlockVolumeRelocateSpec { + cnsVolumeID := CnsVolumeId{ + Id: volumeId, + } + volumeSpec := CnsVolumeRelocateSpec{ + VolumeId: cnsVolumeID, + Datastore: datastore, + Profile: profile, + } + blockVolSpec := CnsBlockVolumeRelocateSpec{ + CnsVolumeRelocateSpec: volumeSpec, + } + return blockVolSpec +} + +func init() { + types.Add("CnsBlockVolumeRelocateSpec", reflect.TypeOf((*CnsBlockVolumeRelocateSpec)(nil)).Elem()) +} + +type CnsCursor struct { + types.DynamicData + + Offset int64 `xml:"offset"` + Limit int64 `xml:"limit"` + TotalRecords int64 `xml:"totalRecords,omitempty"` +} + +func init() { + types.Add("CnsCursor", reflect.TypeOf((*CnsCursor)(nil)).Elem()) +} + +type CnsFault struct { + types.BaseMethodFault `xml:"fault,typeattr"` + + Reason string `xml:"reason,omitempty"` +} + +func init() { + types.Add("CnsFault", reflect.TypeOf((*CnsFault)(nil)).Elem()) +} + +type CnsVolumeNotFoundFault struct { + CnsFault + + VolumeId CnsVolumeId `xml:"volumeId"` +} + +func init() { + types.Add("CnsVolumeNotFoundFault", reflect.TypeOf((*CnsVolumeNotFoundFault)(nil)).Elem()) +} + +type CnsAlreadyRegisteredFault struct { + CnsFault `xml:"fault,typeattr"` + + VolumeId CnsVolumeId `xml:"volumeId,omitempty"` +} + +func init() { + types.Add("CnsAlreadyRegisteredFault", reflect.TypeOf((*CnsAlreadyRegisteredFault)(nil)).Elem()) +} + +type CnsSnapshotNotFoundFault struct { + CnsFault + + VolumeId CnsVolumeId `xml:"volumeId,omitempty"` + SnapshotId CnsSnapshotId `xml:"snapshotId"` +} + +func init() { + types.Add("CnsSnapshotNotFoundFault", reflect.TypeOf((*CnsSnapshotNotFoundFault)(nil)).Elem()) +} + +type CnsConfigureVolumeACLs CnsConfigureVolumeACLsRequestType + +func init() { + types.Add("vsan:CnsConfigureVolumeACLs", reflect.TypeOf((*CnsConfigureVolumeACLs)(nil)).Elem()) +} + +type CnsConfigureVolumeACLsRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + ACLConfigSpecs []CnsVolumeACLConfigureSpec `xml:"ACLConfigSpecs"` +} + +func init() { + types.Add("vsan:CnsConfigureVolumeACLsRequestType", reflect.TypeOf((*CnsConfigureVolumeACLsRequestType)(nil)).Elem()) +} + +type CnsConfigureVolumeACLsResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsVolumeACLConfigureSpec struct { + types.DynamicData + + VolumeId CnsVolumeId `xml:"volumeId"` + AccessControlSpecList []CnsNFSAccessControlSpec `xml:"accessControlSpecList,typeattr"` +} + +type CnsNFSAccessControlSpec struct { + types.DynamicData + Permission []vsanfstypes.VsanFileShareNetPermission `xml:"netPermission,omitempty,typeattr"` + Delete bool `xml:"delete,omitempty"` +} + +func init() { + types.Add("CnsNFSAccessControlSpec", reflect.TypeOf((*CnsNFSAccessControlSpec)(nil)).Elem()) +} + +type CnsQueryAsync CnsQueryAsyncRequestType + +func init() { + types.Add("CnsQueryAsync", reflect.TypeOf((*CnsQueryAsync)(nil)).Elem()) +} + +type CnsQueryAsyncRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + Filter CnsQueryFilter `xml:"filter"` + Selection *CnsQuerySelection `xml:"selection,omitempty"` +} + +func init() { + types.Add("CnsQueryAsyncRequestType", reflect.TypeOf((*CnsQueryAsyncRequestType)(nil)).Elem()) +} + +type CnsQueryAsyncResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsAsyncQueryResult struct { + CnsVolumeOperationResult + + QueryResult CnsQueryResult `xml:"queryResult,omitempty"` +} + +func init() { + types.Add("CnsAsyncQueryResult", reflect.TypeOf((*CnsAsyncQueryResult)(nil)).Elem()) +} + +// Cns Snapshot Types + +type CnsCreateSnapshotsRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + SnapshotSpecs []CnsSnapshotCreateSpec `xml:"snapshotSpecs,omitempty"` +} + +func init() { + types.Add("CnsCreateSnapshotsRequestType", reflect.TypeOf((*CnsCreateSnapshotsRequestType)(nil)).Elem()) +} + +type CnsCreateSnapshots CnsCreateSnapshotsRequestType + +func init() { + types.Add("CnsCreateSnapshots", reflect.TypeOf((*CnsCreateSnapshots)(nil)).Elem()) +} + +type CnsCreateSnapshotsResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsSnapshotCreateSpec struct { + types.DynamicData + + VolumeId CnsVolumeId `xml:"volumeId"` + Description string `xml:"description"` +} + +func init() { + types.Add("CnsSnapshotCreateSpec", reflect.TypeOf((*CnsSnapshotCreateSpec)(nil)).Elem()) +} + +type CnsDeleteSnapshotsRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + SnapshotDeleteSpecs []CnsSnapshotDeleteSpec `xml:"snapshotDeleteSpecs,omitempty"` +} + +func init() { + types.Add("CnsDeleteSnapshotsRequestType", reflect.TypeOf((*CnsDeleteSnapshotsRequestType)(nil)).Elem()) +} + +type CnsDeleteSnapshots CnsDeleteSnapshotsRequestType + +func init() { + types.Add("CnsDeleteSnapshots", reflect.TypeOf((*CnsDeleteSnapshots)(nil)).Elem()) +} + +type CnsDeleteSnapshotsResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsSnapshotId struct { + types.DynamicData + + Id string `xml:"id"` +} + +func init() { + types.Add("CnsSnapshotId", reflect.TypeOf((*CnsSnapshotId)(nil)).Elem()) +} + +type CnsSnapshotDeleteSpec struct { + types.DynamicData + + VolumeId CnsVolumeId `xml:"volumeId"` + SnapshotId CnsSnapshotId `xml:"snapshotId"` +} + +func init() { + types.Add("CnsSnapshotDeleteSpec", reflect.TypeOf((*CnsSnapshotDeleteSpec)(nil)).Elem()) +} + +type CnsSnapshot struct { + types.DynamicData + + SnapshotId CnsSnapshotId `xml:"snapshotId"` + VolumeId CnsVolumeId `xml:"volumeId"` + Description string `xml:"description,omitempty"` + CreateTime time.Time `xml:"createTime"` +} + +func init() { + types.Add("CnsSnapshot", reflect.TypeOf((*CnsSnapshot)(nil)).Elem()) +} + +type CnsSnapshotOperationResult struct { + CnsVolumeOperationResult +} + +func init() { + types.Add("CnsSnapshotOperationResult", reflect.TypeOf((*CnsSnapshotOperationResult)(nil)).Elem()) +} + +type CnsSnapshotCreateResult struct { + CnsSnapshotOperationResult + Snapshot CnsSnapshot `xml:"snapshot,omitempty"` +} + +func init() { + types.Add("CnsSnapshotCreateResult", reflect.TypeOf((*CnsSnapshotCreateResult)(nil)).Elem()) +} + +type CnsSnapshotDeleteResult struct { + CnsSnapshotOperationResult + SnapshotId CnsSnapshotId `xml:"snapshotId,omitempty"` +} + +func init() { + types.Add("CnsSnapshotDeleteResult", reflect.TypeOf((*CnsSnapshotDeleteResult)(nil)).Elem()) +} + +type CnsVolumeSource struct { + types.DynamicData +} + +func init() { + types.Add("CnsVolumeSource", reflect.TypeOf((*CnsVolumeSource)(nil)).Elem()) +} + +type CnsSnapshotVolumeSource struct { + CnsVolumeSource + + VolumeId CnsVolumeId `xml:"volumeId,omitempty"` + SnapshotId CnsSnapshotId `xml:"snapshotId,omitempty"` +} + +func init() { + types.Add("CnsSnapshotVolumeSource", reflect.TypeOf((*CnsSnapshotVolumeSource)(nil)).Elem()) +} + +// CNS QuerySnapshots related types + +type CnsQuerySnapshotsRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + SnapshotQueryFilter CnsSnapshotQueryFilter `xml:"snapshotQueryFilter"` +} + +func init() { + types.Add("CnsQuerySnapshotsRequestType", reflect.TypeOf((*CnsQuerySnapshotsRequestType)(nil)).Elem()) +} + +type CnsQuerySnapshots CnsQuerySnapshotsRequestType + +func init() { + types.Add("CnsQuerySnapshots", reflect.TypeOf((*CnsQuerySnapshots)(nil)).Elem()) +} + +type CnsQuerySnapshotsResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsSnapshotQueryResult struct { + types.DynamicData + + Entries []CnsSnapshotQueryResultEntry `xml:"entries,omitempty"` + Cursor CnsCursor `xml:"cursor"` +} + +func init() { + types.Add("CnsSnapshotQueryResult", reflect.TypeOf((*CnsSnapshotQueryResult)(nil)).Elem()) +} + +type CnsSnapshotQueryResultEntry struct { + types.DynamicData + + Snapshot CnsSnapshot `xml:"snapshot,omitempty"` + Error *types.LocalizedMethodFault `xml:"error,omitempty"` +} + +func init() { + types.Add("CnsSnapshotQueryResultEntry", reflect.TypeOf((*CnsSnapshotQueryResultEntry)(nil)).Elem()) +} + +type CnsSnapshotQueryFilter struct { + types.DynamicData + + SnapshotQuerySpecs []CnsSnapshotQuerySpec `xml:"snapshotQuerySpecs,omitempty"` + Cursor *CnsCursor `xml:"cursor,omitempty"` +} + +func init() { + types.Add("CnsSnapshotQueryFilter", reflect.TypeOf((*CnsSnapshotQueryFilter)(nil)).Elem()) +} + +type CnsSnapshotQuerySpec struct { + types.DynamicData + + VolumeId CnsVolumeId `xml:"volumeId"` + SnapshotId *CnsSnapshotId `xml:"snapshotId,omitempty"` +} + +func init() { + types.Add("CnsSnapshotQuerySpec", reflect.TypeOf((*CnsSnapshotQuerySpec)(nil)).Elem()) +} + +type CnsReconfigVolumePolicy CnsReconfigVolumePolicyRequestType + +func init() { + types.Add("vsan:CnsReconfigVolumePolicy", reflect.TypeOf((*CnsReconfigVolumePolicy)(nil)).Elem()) +} + +type CnsReconfigVolumePolicyRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + VolumePolicyReconfigSpecs []CnsVolumePolicyReconfigSpec `xml:"volumePolicyReconfigSpecs,omitempty"` +} + +func init() { + types.Add("vsan:CnsReconfigVolumePolicyRequestType", reflect.TypeOf((*CnsReconfigVolumePolicyRequestType)(nil)).Elem()) +} + +type CnsReconfigVolumePolicyResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} + +type CnsVolumePolicyReconfigSpec struct { + types.DynamicData + + VolumeId CnsVolumeId `xml:"volumeId"` + Profile []types.BaseVirtualMachineProfileSpec `xml:"profile,omitempty,typeattr"` +} + +func init() { + types.Add("vsan:CnsVolumePolicyReconfigSpec", reflect.TypeOf((*CnsVolumePolicyReconfigSpec)(nil)).Elem()) +} + +type CnsSyncDatastore CnsSyncDatastoreRequestType + +func init() { + types.Add("vsan:CnsSyncDatastore", reflect.TypeOf((*CnsSyncDatastore)(nil)).Elem()) +} + +type CnsSyncDatastoreRequestType struct { + This types.ManagedObjectReference `xml:"_this"` + DatastoreUrl string `xml:"datastoreUrl,omitempty"` + FullSync *bool `xml:"fullSync"` +} + +func init() { + types.Add("vsan:CnsSyncDatastoreRequestType", reflect.TypeOf((*CnsSyncDatastoreRequestType)(nil)).Elem()) +} + +type CnsSyncDatastoreResponse struct { + Returnval types.ManagedObjectReference `xml:"returnval"` +} diff --git a/vendor/github.com/vmware/govmomi/find/doc.go b/vendor/github.com/vmware/govmomi/find/doc.go index 0c8acee016..d22e883534 100644 --- a/vendor/github.com/vmware/govmomi/find/doc.go +++ b/vendor/github.com/vmware/govmomi/find/doc.go @@ -32,6 +32,6 @@ otherwise "find" mode is used. The exception is to use a "..." wildcard with a path to find all objects recursively underneath any root object. For example: VirtualMachineList("/DC1/...") -See also: https://github.com/vmware/govmomi/blob/master/govc/README.md#usage +See also: https://github.com/vmware/govmomi/blob/main/govc/README.md#usage */ package find diff --git a/vendor/github.com/vmware/govmomi/govc/cli/command.go b/vendor/github.com/vmware/govmomi/govc/cli/command.go new file mode 100644 index 0000000000..ef468c6221 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/cli/command.go @@ -0,0 +1,249 @@ +/* +Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cli + +import ( + "context" + "flag" + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" + "text/tabwriter" + + "github.com/vmware/govmomi/vim25/types" +) + +type HasFlags interface { + // Register may be called more than once and should be idempotent. + Register(ctx context.Context, f *flag.FlagSet) + + // Process may be called more than once and should be idempotent. + Process(ctx context.Context) error +} + +type Command interface { + HasFlags + + Run(ctx context.Context, f *flag.FlagSet) error +} + +func generalHelp(w io.Writer, filter string) { + var cmds, matches []string + for name := range commands { + cmds = append(cmds, name) + + if filter != "" && strings.Contains(name, filter) { + matches = append(matches, name) + } + } + + if len(matches) == 0 { + fmt.Fprintf(w, `Usage: %[1]s [COMMON OPTIONS] [PATH]... + +govmomi is a Go library for interacting with VMware vSphere APIs (ESXi and/or +vCenter Server). +It is licensed under the Apache License, Version 2.0 + +%[1]s is the CLI for govmomi. + +The available commands are listed below. A detailed description of each +command can be displayed with "govc -h". The description of all +commands can be also found at https://via.vmw.com/GJ98hk . + +Examples: + show usage of a command: govc -h + show toplevel structure: govc ls + show datacenter summary: govc datacenter.info + show all VMs: govc find -type m + upload a ISO file: govc datastore.upload -ds datastore1 ./config.iso vm-name/config.iso + +Common options: + -h Show this message + -cert= Certificate [GOVC_CERTIFICATE] + -debug=false Store debug logs [GOVC_DEBUG] + -trace=false Write SOAP/REST traffic to stderr + -verbose=false Write request/response data to stderr + -dump=false Enable output dump + -json=false Enable JSON output + -xml=false Enable XML output + -k=false Skip verification of server certificate [GOVC_INSECURE] + -key= Private key [GOVC_PRIVATE_KEY] + -persist-session=true Persist session to disk [GOVC_PERSIST_SESSION] + -tls-ca-certs= TLS CA certificates file [GOVC_TLS_CA_CERTS] + -tls-known-hosts= TLS known hosts file [GOVC_TLS_KNOWN_HOSTS] + -u= ESX or vCenter URL [GOVC_URL] + -vim-namespace=urn:vim25 Vim namespace [GOVC_VIM_NAMESPACE] + -vim-version=6.0 Vim version [GOVC_VIM_VERSION] + -dc= Datacenter [GOVC_DATACENTER] + -host.dns= Find host by FQDN + -host.ip= Find host by IP address + -host.ipath= Find host by inventory path + -host.uuid= Find host by UUID + -vm.dns= Find VM by FQDN + -vm.ip= Find VM by IP address + -vm.ipath= Find VM by inventory path + -vm.path= Find VM by path to .vmx file + -vm.uuid= Find VM by UUID + +Available commands: +`, filepath.Base(os.Args[0])) + + } else { + fmt.Fprintf(w, "%s: command '%s' not found, did you mean:\n", os.Args[0], filter) + cmds = matches + } + + sort.Strings(cmds) + for _, name := range cmds { + fmt.Fprintf(w, " %s\n", name) + } +} + +func commandHelp(w io.Writer, name string, cmd Command, f *flag.FlagSet) { + type HasUsage interface { + Usage() string + } + + fmt.Fprintf(w, "Usage: %s %s [OPTIONS]", os.Args[0], name) + if u, ok := cmd.(HasUsage); ok { + fmt.Fprintf(w, " %s", u.Usage()) + } + fmt.Fprintf(w, "\n") + + type HasDescription interface { + Description() string + } + + if u, ok := cmd.(HasDescription); ok { + fmt.Fprintf(w, "\n%s\n", u.Description()) + } + + n := 0 + f.VisitAll(func(_ *flag.Flag) { + n += 1 + }) + + if n > 0 { + fmt.Fprintf(w, "\nOptions:\n") + tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0) + f.VisitAll(func(f *flag.Flag) { + fmt.Fprintf(tw, "\t-%s=%s\t%s\n", f.Name, f.DefValue, f.Usage) + }) + tw.Flush() + } +} + +func clientLogout(ctx context.Context, cmd Command) error { + type logout interface { + Logout(context.Context) error + } + + if l, ok := cmd.(logout); ok { + return l.Logout(ctx) + } + + return nil +} + +func Run(args []string) int { + hw := os.Stderr + rc := 1 + hwrc := func(arg string) { + arg = strings.TrimLeft(arg, "-") + if arg == "h" || arg == "help" { + hw = os.Stdout + rc = 0 + } + } + + var err error + + if len(args) == 0 { + generalHelp(hw, "") + return rc + } + + // Look up real command name in aliases table. + name, ok := aliases[args[0]] + if !ok { + name = args[0] + } + + cmd, ok := commands[name] + if !ok { + hwrc(name) + generalHelp(hw, name) + return rc + } + + fs := flag.NewFlagSet("", flag.ContinueOnError) + fs.SetOutput(io.Discard) + + ctx := context.Background() + + if id := os.Getenv("GOVC_OPERATION_ID"); id != "" { + ctx = context.WithValue(ctx, types.ID{}, id) + } + + cmd.Register(ctx, fs) + + if err = fs.Parse(args[1:]); err != nil { + goto error + } + + if err = cmd.Process(ctx); err != nil { + goto error + } + + if err = cmd.Run(ctx, fs); err != nil { + goto error + } + + if err = clientLogout(ctx, cmd); err != nil { + goto error + } + + return 0 + +error: + if err == flag.ErrHelp { + if len(args) == 2 { + hwrc(args[1]) + } + commandHelp(hw, args[0], cmd, fs) + } else { + if x, ok := err.(interface{ ExitCode() int }); ok { + // propagate exit code, e.g. from guest.run + rc = x.ExitCode() + } else { + w, ok := cmd.(interface{ WriteError(error) bool }) + if ok { + ok = w.WriteError(err) + } + if !ok { + fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], err) + } + } + } + + _ = clientLogout(ctx, cmd) + + return rc +} diff --git a/vendor/github.com/vmware/govmomi/govc/cli/register.go b/vendor/github.com/vmware/govmomi/govc/cli/register.go new file mode 100644 index 0000000000..866c5816be --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/cli/register.go @@ -0,0 +1,47 @@ +/* +Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cli + +import "os" + +var commands = map[string]Command{} + +var aliases = map[string]string{} + +// hideUnreleased allows commands to be compiled into the govc binary without being registered by default. +// Unreleased commands are omitted from 'govc -h' help text and the generated govc/USAGE.md +// Setting the env var GOVC_SHOW_UNRELEASED=true enables any commands registered as unreleased. +var hideUnreleased = os.Getenv("GOVC_SHOW_UNRELEASED") != "true" + +func ShowUnreleased() bool { + return !hideUnreleased +} + +func Register(name string, c Command, unreleased ...bool) { + if len(unreleased) != 0 && unreleased[0] && hideUnreleased { + return + } + commands[name] = c +} + +func Alias(name string, alias string) { + aliases[alias] = name +} + +func Commands() map[string]Command { + return commands +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/client.go b/vendor/github.com/vmware/govmomi/govc/flags/client.go new file mode 100644 index 0000000000..9b04882ca2 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/client.go @@ -0,0 +1,557 @@ +/* +Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "crypto/tls" + "errors" + "flag" + "fmt" + "net/url" + "os" + "os/signal" + "path/filepath" + "strings" + "syscall" + "time" + + "github.com/vmware/govmomi/cns" + "github.com/vmware/govmomi/pbm" + "github.com/vmware/govmomi/session" + "github.com/vmware/govmomi/session/cache" + "github.com/vmware/govmomi/session/keepalive" + "github.com/vmware/govmomi/vapi/rest" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/soap" +) + +const ( + envURL = "GOVC_URL" + envUsername = "GOVC_USERNAME" + envPassword = "GOVC_PASSWORD" + envCertificate = "GOVC_CERTIFICATE" + envPrivateKey = "GOVC_PRIVATE_KEY" + envInsecure = "GOVC_INSECURE" + envPersist = "GOVC_PERSIST_SESSION" + envMinAPIVersion = "GOVC_MIN_API_VERSION" + envVimNamespace = "GOVC_VIM_NAMESPACE" + envVimVersion = "GOVC_VIM_VERSION" + envTLSCaCerts = "GOVC_TLS_CA_CERTS" + envTLSKnownHosts = "GOVC_TLS_KNOWN_HOSTS" + + defaultMinVimVersion = "5.5" +) + +const cDescr = "ESX or vCenter URL" + +type ClientFlag struct { + common + + *DebugFlag + + username string + password string + cert string + key string + persist bool + minAPIVersion string + vimNamespace string + vimVersion string + tlsCaCerts string + tlsKnownHosts string + client *vim25.Client + restClient *rest.Client + Session cache.Session +} + +var ( + home = os.Getenv("GOVMOMI_HOME") + clientFlagKey = flagKey("client") +) + +func init() { + if home == "" { + home = filepath.Join(os.Getenv("HOME"), ".govmomi") + } +} + +func NewClientFlag(ctx context.Context) (*ClientFlag, context.Context) { + if v := ctx.Value(clientFlagKey); v != nil { + return v.(*ClientFlag), ctx + } + + v := &ClientFlag{} + v.DebugFlag, ctx = NewDebugFlag(ctx) + ctx = context.WithValue(ctx, clientFlagKey, v) + return v, ctx +} + +func (flag *ClientFlag) String() string { + url := flag.Session.Endpoint() + if url == nil { + return "" + } + + return url.String() +} + +func (flag *ClientFlag) Set(s string) error { + var err error + + flag.Session.URL, err = soap.ParseURL(s) + + return err +} + +func (flag *ClientFlag) Register(ctx context.Context, f *flag.FlagSet) { + flag.RegisterOnce(func() { + flag.DebugFlag.Register(ctx, f) + + { + flag.Set(os.Getenv(envURL)) + usage := fmt.Sprintf("%s [%s]", cDescr, envURL) + f.Var(flag, "u", usage) + } + + { + flag.username = os.Getenv(envUsername) + flag.password = os.Getenv(envPassword) + } + + { + value := os.Getenv(envCertificate) + usage := fmt.Sprintf("Certificate [%s]", envCertificate) + f.StringVar(&flag.cert, "cert", value, usage) + } + + { + value := os.Getenv(envPrivateKey) + usage := fmt.Sprintf("Private key [%s]", envPrivateKey) + f.StringVar(&flag.key, "key", value, usage) + } + + { + insecure := false + switch env := strings.ToLower(os.Getenv(envInsecure)); env { + case "1", "true": + insecure = true + } + + usage := fmt.Sprintf("Skip verification of server certificate [%s]", envInsecure) + f.BoolVar(&flag.Session.Insecure, "k", insecure, usage) + } + + { + persist := true + switch env := strings.ToLower(os.Getenv(envPersist)); env { + case "0", "false": + persist = false + } + + usage := fmt.Sprintf("Persist session to disk [%s]", envPersist) + f.BoolVar(&flag.persist, "persist-session", persist, usage) + } + + { + env := os.Getenv(envMinAPIVersion) + if env == "" { + env = defaultMinVimVersion + } + + flag.minAPIVersion = env + } + + { + value := os.Getenv(envVimNamespace) + if value == "" { + value = vim25.Namespace + } + usage := fmt.Sprintf("Vim namespace [%s]", envVimNamespace) + f.StringVar(&flag.vimNamespace, "vim-namespace", value, usage) + } + + { + value := os.Getenv(envVimVersion) + if value == "" { + value = vim25.Version + } + usage := fmt.Sprintf("Vim version [%s]", envVimVersion) + f.StringVar(&flag.vimVersion, "vim-version", value, usage) + } + + { + value := os.Getenv(envTLSCaCerts) + usage := fmt.Sprintf("TLS CA certificates file [%s]", envTLSCaCerts) + f.StringVar(&flag.tlsCaCerts, "tls-ca-certs", value, usage) + } + + { + value := os.Getenv(envTLSKnownHosts) + usage := fmt.Sprintf("TLS known hosts file [%s]", envTLSKnownHosts) + f.StringVar(&flag.tlsKnownHosts, "tls-known-hosts", value, usage) + } + }) +} + +func (flag *ClientFlag) Process(ctx context.Context) error { + return flag.ProcessOnce(func() error { + err := flag.DebugFlag.Process(ctx) + if err != nil { + return err + } + + if flag.Session.URL == nil { + return errors.New("specify an " + cDescr) + } + + if !flag.persist { + flag.Session.Passthrough = true + } + + flag.username, err = session.Secret(flag.username) + if err != nil { + return err + } + flag.password, err = session.Secret(flag.password) + if err != nil { + return err + } + + // Override username if set + if flag.username != "" { + var password string + var ok bool + + if flag.Session.URL.User != nil { + password, ok = flag.Session.URL.User.Password() + } + + if ok { + flag.Session.URL.User = url.UserPassword(flag.username, password) + } else { + flag.Session.URL.User = url.User(flag.username) + } + } + + // Override password if set + if flag.password != "" { + var username string + + if flag.Session.URL.User != nil { + username = flag.Session.URL.User.Username() + } + + flag.Session.URL.User = url.UserPassword(username, flag.password) + } + + return nil + }) +} + +func (flag *ClientFlag) ConfigureTLS(sc *soap.Client) error { + if flag.cert != "" { + cert, err := tls.LoadX509KeyPair(flag.cert, flag.key) + if err != nil { + return fmt.Errorf("%s=%q %s=%q: %s", envCertificate, flag.cert, envPrivateKey, flag.key, err) + } + + sc.SetCertificate(cert) + } + + // Set namespace and version + sc.Namespace = "urn:" + flag.vimNamespace + sc.Version = flag.vimVersion + + sc.UserAgent = fmt.Sprintf("govc/%s", strings.TrimPrefix(BuildVersion, "v")) + + if err := flag.SetRootCAs(sc); err != nil { + return err + } + + if err := sc.LoadThumbprints(flag.tlsKnownHosts); err != nil { + return err + } + + t := sc.DefaultTransport() + var err error + + value := os.Getenv("GOVC_TLS_HANDSHAKE_TIMEOUT") + if value != "" { + t.TLSHandshakeTimeout, err = time.ParseDuration(value) + if err != nil { + return err + } + } + + sc.UseJSON(os.Getenv("GOVC_VI_JSON") != "") + + return nil +} + +func (flag *ClientFlag) SetRootCAs(c *soap.Client) error { + if flag.tlsCaCerts != "" { + return c.SetRootCAs(flag.tlsCaCerts) + } + return nil +} + +func isDevelopmentVersion(apiVersion string) bool { + // Skip version check for development builds which can be in the form of "r4A70F" or "6.5.x" + return strings.Count(apiVersion, ".") == 0 || strings.HasSuffix(apiVersion, ".x") +} + +// apiVersionValid returns whether or not the API version supported by the +// server the client is connected to is not recent enough. +func apiVersionValid(c *vim25.Client, minVersionString string) error { + if minVersionString == "-" { + // Disable version check + return nil + } + + apiVersion := c.ServiceContent.About.ApiVersion + if isDevelopmentVersion(apiVersion) { + return nil + } + + realVersion, err := ParseVersion(apiVersion) + if err != nil { + return fmt.Errorf("error parsing API version %q: %s", apiVersion, err) + } + + minVersion, err := ParseVersion(minVersionString) + if err != nil { + return fmt.Errorf("error parsing %s=%q: %s", envMinAPIVersion, minVersionString, err) + } + + if !minVersion.Lte(realVersion) { + err = fmt.Errorf("require API version %q, connected to API version %q (set %s to override)", + minVersionString, + c.ServiceContent.About.ApiVersion, + envMinAPIVersion) + return err + } + + return nil +} + +func (flag *ClientFlag) RoundTripper(c *soap.Client) soap.RoundTripper { + // Retry twice when a temporary I/O error occurs. + // This means a maximum of 3 attempts. + rt := vim25.Retry(c, vim25.RetryTemporaryNetworkError, 3) + + switch { + case flag.dump: + rt = &dump{roundTripper: rt} + case flag.verbose: + rt = &verbose{roundTripper: rt} + } + + return rt +} + +func (flag *ClientFlag) Client() (*vim25.Client, error) { + if flag.client != nil { + return flag.client, nil + } + + c := new(vim25.Client) + err := flag.Session.Login(context.Background(), c, flag.ConfigureTLS) + if err != nil { + return nil, err + } + + // Check that the endpoint has the right API version + err = apiVersionValid(c, flag.minAPIVersion) + if err != nil { + return nil, err + } + + if flag.vimVersion == "" { + err = c.UseServiceVersion() + if err != nil { + return nil, err + } + } + + c.RoundTripper = flag.RoundTripper(c.Client) + flag.client = c + + return flag.client, nil +} + +func (flag *ClientFlag) RestClient() (*rest.Client, error) { + if flag.restClient != nil { + return flag.restClient, nil + } + + c := new(rest.Client) + + err := flag.Session.Login(context.Background(), c, flag.ConfigureTLS) + if err != nil { + return nil, err + } + + flag.restClient = c + return flag.restClient, nil +} + +func (flag *ClientFlag) PbmClient() (*pbm.Client, error) { + vc, err := flag.Client() + if err != nil { + return nil, err + } + c, err := pbm.NewClient(context.Background(), vc) + if err != nil { + return nil, err + } + + c.RoundTripper = flag.RoundTripper(c.Client) + + return c, nil +} + +func (flag *ClientFlag) CnsClient() (*cns.Client, error) { + vc, err := flag.Client() + if err != nil { + return nil, err + } + _ = vc.UseServiceVersion("vsan") + + c, err := cns.NewClient(context.Background(), vc) + if err != nil { + return nil, err + } + + c.RoundTripper = flag.RoundTripper(c.Client) + + return c, nil +} + +func (flag *ClientFlag) KeepAlive(client cache.Client) { + switch c := client.(type) { + case *vim25.Client: + keepalive.NewHandlerSOAP(c, 0, nil).Start() + case *rest.Client: + keepalive.NewHandlerREST(c, 0, nil).Start() + default: + panic(fmt.Sprintf("unsupported client type=%T", client)) + } +} + +func (flag *ClientFlag) Logout(ctx context.Context) error { + if flag.client != nil { + _ = flag.Session.Logout(ctx, flag.client) + } + + if flag.restClient != nil { + _ = flag.Session.Logout(ctx, flag.restClient) + } + + return nil +} + +// Environ returns the govc environment variables for this connection +func (flag *ClientFlag) Environ(extra bool) []string { + var env []string + add := func(k, v string) { + env = append(env, fmt.Sprintf("%s=%s", k, v)) + } + + u := *flag.Session.URL + if u.User != nil { + add(envUsername, u.User.Username()) + + if p, ok := u.User.Password(); ok { + add(envPassword, p) + } + + u.User = nil + } + + if u.Path == vim25.Path { + u.Path = "" + } + u.Fragment = "" + u.RawQuery = "" + + add(envURL, strings.TrimPrefix(u.String(), "https://")) + + keys := []string{ + envCertificate, + envPrivateKey, + envInsecure, + envPersist, + envMinAPIVersion, + envVimNamespace, + envVimVersion, + } + + for _, k := range keys { + if v := os.Getenv(k); v != "" { + add(k, v) + } + } + + if extra { + add("GOVC_URL_SCHEME", flag.Session.URL.Scheme) + + v := strings.SplitN(u.Host, ":", 2) + add("GOVC_URL_HOST", v[0]) + if len(v) == 2 { + add("GOVC_URL_PORT", v[1]) + } + + add("GOVC_URL_PATH", flag.Session.URL.Path) + + if f := flag.Session.URL.Fragment; f != "" { + add("GOVC_URL_FRAGMENT", f) + } + + if q := flag.Session.URL.RawQuery; q != "" { + add("GOVC_URL_QUERY", q) + } + } + + return env +} + +// WithCancel calls the given function, returning when complete or canceled via SIGINT. +func (flag *ClientFlag) WithCancel(ctx context.Context, f func(context.Context) error) error { + sig := make(chan os.Signal, 1) + signal.Notify(sig, syscall.SIGINT) + + wctx, cancel := context.WithCancel(ctx) + defer cancel() + + done := make(chan bool) + var werr error + + go func() { + defer close(done) + werr = f(wctx) + }() + + select { + case <-sig: + cancel() + <-done // Wait for f() to complete + case <-done: + } + + return werr +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/cluster.go b/vendor/github.com/vmware/govmomi/govc/flags/cluster.go new file mode 100644 index 0000000000..a386d33f2f --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/cluster.go @@ -0,0 +1,204 @@ +/* +Copyright (c) 2017 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + "fmt" + "os" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/view" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" +) + +type ClusterFlag struct { + common + + *DatacenterFlag + + Name string + + cluster *object.ClusterComputeResource + pc *property.Collector +} + +var clusterFlagKey = flagKey("cluster") + +func NewClusterFlag(ctx context.Context) (*ClusterFlag, context.Context) { + if v := ctx.Value(clusterFlagKey); v != nil { + return v.(*ClusterFlag), ctx + } + + v := &ClusterFlag{} + v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) + ctx = context.WithValue(ctx, clusterFlagKey, v) + return v, ctx +} + +func (f *ClusterFlag) Register(ctx context.Context, fs *flag.FlagSet) { + f.RegisterOnce(func() { + f.DatacenterFlag.Register(ctx, fs) + + env := "GOVC_CLUSTER" + value := os.Getenv(env) + usage := fmt.Sprintf("Cluster [%s]", env) + fs.StringVar(&f.Name, "cluster", value, usage) + }) +} + +// RegisterPlacement registers the -cluster flag without using GOVC_CLUSTER env as the default value, +// usage is specific to VM placement. +func (f *ClusterFlag) RegisterPlacement(ctx context.Context, fs *flag.FlagSet) { + f.RegisterOnce(func() { + f.DatacenterFlag.Register(ctx, fs) + + fs.StringVar(&f.Name, "cluster", "", "Use cluster for VM placement via DRS") + }) +} + +func (f *ClusterFlag) Process(ctx context.Context) error { + return f.ProcessOnce(func() error { + if err := f.DatacenterFlag.Process(ctx); err != nil { + return err + } + return nil + }) +} + +func (f *ClusterFlag) Cluster() (*object.ClusterComputeResource, error) { + if f.cluster != nil { + return f.cluster, nil + } + + finder, err := f.Finder() + if err != nil { + return nil, err + } + + if f.cluster, err = finder.ClusterComputeResourceOrDefault(context.TODO(), f.Name); err != nil { + return nil, err + } + + f.pc = property.DefaultCollector(f.cluster.Client()) + + return f.cluster, nil +} + +func (f *ClusterFlag) ClusterIfSpecified() (*object.ClusterComputeResource, error) { + if f.Name == "" { + return nil, nil + } + return f.Cluster() +} + +func (f *ClusterFlag) Reconfigure(ctx context.Context, spec types.BaseComputeResourceConfigSpec) error { + cluster, err := f.Cluster() + if err != nil { + return err + } + + task, err := cluster.Reconfigure(ctx, spec, true) + if err != nil { + return err + } + + logger := f.ProgressLogger(fmt.Sprintf("Reconfigure %s...", cluster.InventoryPath)) + defer logger.Wait() + + _, err = task.WaitForResult(ctx, logger) + return err +} + +func (f *ClusterFlag) objectMap(ctx context.Context, kind string, names []string) (map[string]types.ManagedObjectReference, error) { + cluster, err := f.Cluster() + if err != nil { + return nil, err + } + + objects := make(map[string]types.ManagedObjectReference, len(names)) + for _, name := range names { + objects[name] = types.ManagedObjectReference{} + } + + m := view.NewManager(cluster.Client()) + v, err := m.CreateContainerView(ctx, cluster.Reference(), []string{kind}, true) + if err != nil { + return nil, err + } + + defer func() { + _ = v.Destroy(ctx) + }() + + var entities []mo.ManagedEntity + + err = v.Retrieve(ctx, []string{"ManagedEntity"}, []string{"name"}, &entities) + if err != nil { + return nil, err + } + + for _, e := range entities { + if _, ok := objects[e.Name]; ok { + objects[e.Name] = e.Self + } + } + + for name, ref := range objects { + if ref.Value == "" { + return nil, fmt.Errorf("%s %q not found", kind, name) + } + } + + return objects, nil +} + +func (f *ClusterFlag) ObjectList(ctx context.Context, kind string, names []string) ([]types.ManagedObjectReference, error) { + objs, err := f.objectMap(ctx, kind, names) + if err != nil { + return nil, err + } + + var refs []types.ManagedObjectReference + + for _, name := range names { // preserve order + refs = append(refs, objs[name]) + } + + return refs, nil +} + +func (f *ClusterFlag) Names(ctx context.Context, refs []types.ManagedObjectReference) (map[types.ManagedObjectReference]string, error) { + names := make(map[types.ManagedObjectReference]string, len(refs)) + + if len(refs) != 0 { + var objs []mo.ManagedEntity + err := f.pc.Retrieve(ctx, refs, []string{"name"}, &objs) + if err != nil { + return nil, err + } + + for _, obj := range objs { + names[obj.Self] = obj.Name + } + } + + return names, nil +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/common.go b/vendor/github.com/vmware/govmomi/govc/flags/common.go new file mode 100644 index 0000000000..002c239b9e --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/common.go @@ -0,0 +1,38 @@ +/* +Copyright (c) 2015-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package flags + +import "sync" + +// Key type for storing flag instances in a context.Context. +type flagKey string + +// Type to help flags out with only registering/processing once. +type common struct { + register sync.Once + process sync.Once +} + +func (c *common) RegisterOnce(fn func()) { + c.register.Do(fn) +} + +func (c *common) ProcessOnce(fn func() error) (err error) { + c.process.Do(func() { + err = fn() + }) + return err +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/datacenter.go b/vendor/github.com/vmware/govmomi/govc/flags/datacenter.go new file mode 100644 index 0000000000..d73f36a819 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/datacenter.go @@ -0,0 +1,225 @@ +/* +Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + "fmt" + "os" + "strings" + + "github.com/vmware/govmomi/find" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25/types" +) + +type DatacenterFlag struct { + common + + *ClientFlag + *OutputFlag + + Name string + dc *object.Datacenter + finder *find.Finder + err error +} + +var datacenterFlagKey = flagKey("datacenter") + +func NewDatacenterFlag(ctx context.Context) (*DatacenterFlag, context.Context) { + if v := ctx.Value(datacenterFlagKey); v != nil { + return v.(*DatacenterFlag), ctx + } + + v := &DatacenterFlag{} + v.ClientFlag, ctx = NewClientFlag(ctx) + v.OutputFlag, ctx = NewOutputFlag(ctx) + ctx = context.WithValue(ctx, datacenterFlagKey, v) + return v, ctx +} + +func (flag *DatacenterFlag) Register(ctx context.Context, f *flag.FlagSet) { + flag.RegisterOnce(func() { + flag.ClientFlag.Register(ctx, f) + flag.OutputFlag.Register(ctx, f) + + env := "GOVC_DATACENTER" + value := os.Getenv(env) + usage := fmt.Sprintf("Datacenter [%s]", env) + f.StringVar(&flag.Name, "dc", value, usage) + }) +} + +func (flag *DatacenterFlag) Process(ctx context.Context) error { + return flag.ProcessOnce(func() error { + if err := flag.ClientFlag.Process(ctx); err != nil { + return err + } + if err := flag.OutputFlag.Process(ctx); err != nil { + return err + } + return nil + }) +} + +func (flag *DatacenterFlag) Finder(all ...bool) (*find.Finder, error) { + if flag.finder != nil { + return flag.finder, nil + } + + c, err := flag.Client() + if err != nil { + return nil, err + } + + allFlag := false + if len(all) == 1 { + allFlag = all[0] + } + finder := find.NewFinder(c, allFlag) + + // Datacenter is not required (ls command for example). + // Set for relative func if dc flag is given or + // if there is a single (default) Datacenter + ctx := context.TODO() + if flag.Name == "" { + flag.dc, flag.err = finder.DefaultDatacenter(ctx) + } else { + if flag.dc, err = finder.Datacenter(ctx, flag.Name); err != nil { + return nil, err + } + } + + finder.SetDatacenter(flag.dc) + + flag.finder = finder + + return flag.finder, nil +} + +func (flag *DatacenterFlag) Datacenter() (*object.Datacenter, error) { + if flag.dc != nil { + return flag.dc, nil + } + + _, err := flag.Finder() + if err != nil { + return nil, err + } + + if flag.err != nil { + // Should only happen if no dc is specified and len(dcs) > 1 + return nil, flag.err + } + + return flag.dc, err +} + +func (flag *DatacenterFlag) DatacenterIfSpecified() (*object.Datacenter, error) { + if flag.Name == "" { + return nil, nil + } + return flag.Datacenter() +} + +func (flag *DatacenterFlag) ManagedObject(ctx context.Context, arg string) (types.ManagedObjectReference, error) { + var ref types.ManagedObjectReference + + finder, err := flag.Finder() + if err != nil { + return ref, err + } + + if ref.FromString(arg) { + if strings.HasPrefix(ref.Type, "com.vmware.content.") { + return ref, nil // special case for content library + } + pc := property.DefaultCollector(flag.client) + var content []types.ObjectContent + err = pc.RetrieveOne(ctx, ref, []string{"name"}, &content) + if err == nil { + return ref, nil + } + } + + l, err := finder.ManagedObjectList(ctx, arg) + if err != nil { + return ref, err + } + + switch len(l) { + case 0: + return ref, fmt.Errorf("%s not found", arg) + case 1: + return l[0].Object.Reference(), nil + default: + var objs []types.ManagedObjectReference + for _, o := range l { + objs = append(objs, o.Object.Reference()) + } + return ref, fmt.Errorf("%d objects at path %q: %s", len(l), arg, objs) + } +} + +func (flag *DatacenterFlag) ManagedObjects(ctx context.Context, args []string) ([]types.ManagedObjectReference, error) { + var refs []types.ManagedObjectReference + + c, err := flag.Client() + if err != nil { + return nil, err + } + + if len(args) == 0 { + refs = append(refs, c.ServiceContent.RootFolder) + return refs, nil + } + + finder, err := flag.Finder() + if err != nil { + return nil, err + } + + for _, arg := range args { + if ref := object.ReferenceFromString(arg); ref != nil { + // e.g. output from object.collect + refs = append(refs, *ref) + continue + } + + if !strings.Contains(arg, "/") { + return nil, fmt.Errorf("%q must be qualified with a path", arg) + } + + elements, err := finder.ManagedObjectList(ctx, arg) + if err != nil { + return nil, err + } + + if len(elements) == 0 { + return nil, fmt.Errorf("object '%s' not found", arg) + } + + for _, e := range elements { + refs = append(refs, e.Object.Reference()) + } + } + + return refs, nil +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/datastore.go b/vendor/github.com/vmware/govmomi/govc/flags/datastore.go new file mode 100644 index 0000000000..8030a6e00e --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/datastore.go @@ -0,0 +1,150 @@ +/* +Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + "fmt" + "os" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25/types" +) + +type DatastoreFlag struct { + common + + *DatacenterFlag + + Name string + + ds *object.Datastore +} + +var datastoreFlagKey = flagKey("datastore") + +// NewCustomDatastoreFlag creates and returns a new DatastoreFlag without +// trying to retrieve an existing one from the specified context. +func NewCustomDatastoreFlag(ctx context.Context) (*DatastoreFlag, context.Context) { + v := &DatastoreFlag{} + v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) + return v, ctx +} + +func NewDatastoreFlag(ctx context.Context) (*DatastoreFlag, context.Context) { + if v := ctx.Value(datastoreFlagKey); v != nil { + return v.(*DatastoreFlag), ctx + } + + v, ctx := NewCustomDatastoreFlag(ctx) + ctx = context.WithValue(ctx, datastoreFlagKey, v) + return v, ctx +} + +func (f *DatastoreFlag) Register(ctx context.Context, fs *flag.FlagSet) { + f.RegisterOnce(func() { + f.DatacenterFlag.Register(ctx, fs) + + env := "GOVC_DATASTORE" + value := os.Getenv(env) + usage := fmt.Sprintf("Datastore [%s]", env) + fs.StringVar(&f.Name, "ds", value, usage) + }) +} + +func (f *DatastoreFlag) Process(ctx context.Context) error { + return f.ProcessOnce(func() error { + if err := f.DatacenterFlag.Process(ctx); err != nil { + return err + } + return nil + }) +} + +func (flag *DatastoreFlag) IsSet() bool { + return flag.Name != "" +} + +func (f *DatastoreFlag) Args(args []string) []object.DatastorePath { + var files []object.DatastorePath + + for _, arg := range args { + var p object.DatastorePath + + if p.FromString(arg) { + f.Name = p.Datastore + } else { + p.Datastore = f.Name + p.Path = arg + } + + files = append(files, p) + } + + return files +} + +func (f *DatastoreFlag) Datastore() (*object.Datastore, error) { + if f.ds != nil { + return f.ds, nil + } + + var p object.DatastorePath + if p.FromString(f.Name) { + // Example use case: + // -ds "$(govc object.collect -s vm/foo config.files.logDirectory)" + f.Name = p.Datastore + } + + finder, err := f.Finder() + if err != nil { + return nil, err + } + + if f.ds, err = finder.DatastoreOrDefault(context.TODO(), f.Name); err != nil { + return nil, err + } + + return f.ds, nil +} + +func (flag *DatastoreFlag) DatastoreIfSpecified() (*object.Datastore, error) { + if flag.Name == "" { + return nil, nil + } + return flag.Datastore() +} + +func (f *DatastoreFlag) DatastorePath(name string) (string, error) { + ds, err := f.Datastore() + if err != nil { + return "", err + } + + return ds.Path(name), nil +} + +func (f *DatastoreFlag) Stat(ctx context.Context, file string) (types.BaseFileInfo, error) { + ds, err := f.Datastore() + if err != nil { + return nil, err + } + + return ds.Stat(ctx, file) + +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/debug.go b/vendor/github.com/vmware/govmomi/govc/flags/debug.go new file mode 100644 index 0000000000..702cf42e66 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/debug.go @@ -0,0 +1,474 @@ +/* +Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "bufio" + "context" + "flag" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "reflect" + "strings" + "sync" + "text/tabwriter" + "time" + + "github.com/dougm/pretty" + + "github.com/vmware/govmomi/vim25/debug" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +type cmdFormat struct { + path string + err error + args []string +} + +func (c *cmdFormat) lookPath(file string, args ...string) { + c.args = args + c.path, c.err = exec.LookPath(file) +} + +func (c *cmdFormat) cmd() (*exec.Cmd, error) { + if c.err != nil { + return nil, c.err + } + return exec.Command(c.path, c.args...), nil +} + +type DebugFlag struct { + common + + enable bool + trace bool + verbose bool + dump bool + xml cmdFormat + json cmdFormat +} + +var debugFlagKey = flagKey("debug") + +func NewDebugFlag(ctx context.Context) (*DebugFlag, context.Context) { + if v := ctx.Value(debugFlagKey); v != nil { + return v.(*DebugFlag), ctx + } + + v := &DebugFlag{} + ctx = context.WithValue(ctx, debugFlagKey, v) + return v, ctx +} + +func (flag *DebugFlag) Verbose() bool { + return flag.verbose +} + +func (flag *DebugFlag) Register(ctx context.Context, f *flag.FlagSet) { + flag.RegisterOnce(func() { + env := "GOVC_DEBUG" + enable := false + switch env := strings.ToLower(os.Getenv(env)); env { + case "1", "true": + enable = true + } + + usage := fmt.Sprintf("Store debug logs [%s]", env) + f.BoolVar(&flag.enable, "debug", enable, usage) + f.BoolVar(&flag.trace, "trace", false, "Write SOAP/REST traffic to stderr") + f.BoolVar(&flag.verbose, "verbose", false, "Write request/response data to stderr") + }) +} + +type cmdFormatCloser struct { + rc io.Closer + in io.Closer + cmd *exec.Cmd + wg *sync.WaitGroup +} + +func (c *cmdFormatCloser) Close() error { + _ = c.rc.Close() + _ = c.in.Close() + c.wg.Wait() + return c.cmd.Wait() +} + +func (flag *DebugFlag) newFormatReader(rc io.ReadCloser, w io.Writer, ext string) (io.ReadCloser, error) { + var err error + var cmd *exec.Cmd + + switch ext { + case "json": + cmd, err = flag.json.cmd() + if err != nil { + return nil, err + } + case "xml": + cmd, err = flag.xml.cmd() + if err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("unsupported type %s", ext) + } + + cmd.Stderr = os.Stderr + + stdin, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + + err = cmd.Start() + if err != nil { + return nil, err + } + + var wg sync.WaitGroup + wg.Add(1) + go func() { + _, _ = io.Copy(w, stdout) + wg.Done() + }() + + return debug.ReadCloser{ + Reader: io.TeeReader(rc, stdin), + Closer: &cmdFormatCloser{rc, stdin, cmd, &wg}, + }, nil +} + +func (flag *DebugFlag) debugTrace(rc io.ReadCloser, w io.Writer, ext string) io.ReadCloser { + fr, err := flag.newFormatReader(rc, w, ext) + if err != nil { + return debug.NewTeeReader(rc, w) + } + return fr +} + +func (flag *DebugFlag) Process(ctx context.Context) error { + // Base path for storing debug logs. + r := os.Getenv("GOVC_DEBUG_PATH") + + if flag.trace { + if flag.verbose { + flag.dump = true // output req/res as Go code + return nil + } + r = "-" + flag.enable = true + if os.Getenv("GOVC_DEBUG_FORMAT") != "false" { + debugXML := os.Getenv("GOVC_DEBUG_XML") + if debugXML == "" { + debugXML = "xmlstarlet" + } + flag.xml.lookPath(debugXML, "fo") + + debugJSON := os.Getenv("GOVC_DEBUG_JSON") + if debugJSON == "" { + debugJSON = "jq" + } + flag.json.lookPath(debugJSON, ".") + + soap.Trace = flag.debugTrace + } + } + + if !flag.enable { + return nil + } + + return flag.ProcessOnce(func() error { + switch r { + case "-": + debug.SetProvider(&debug.LogProvider{}) + return nil + case "": + r = home + } + r = filepath.Join(r, "debug") + + // Path for this particular run. + run := os.Getenv("GOVC_DEBUG_PATH_RUN") + if run == "" { + now := time.Now().Format("2006-01-02T15-04-05.999999999") + r = filepath.Join(r, now) + } else { + // reuse the same path + r = filepath.Join(r, run) + _ = os.RemoveAll(r) + } + + err := os.MkdirAll(r, 0700) + if err != nil { + return err + } + + p := debug.FileProvider{ + Path: r, + } + + debug.SetProvider(&p) + return nil + }) +} + +type dump struct { + roundTripper soap.RoundTripper +} + +func (d *dump) RoundTrip(ctx context.Context, req, res soap.HasFault) error { + vreq := reflect.ValueOf(req).Elem().FieldByName("Req").Elem() + + pretty.Fprintf(os.Stderr, "%# v\n", vreq.Interface()) + + err := d.roundTripper.RoundTrip(ctx, req, res) + if err != nil { + if fault := res.Fault(); fault != nil { + pretty.Fprintf(os.Stderr, "%# v\n", fault) + } + return err + } + + vres := reflect.ValueOf(res).Elem().FieldByName("Res").Elem() + pretty.Fprintf(os.Stderr, "%# v\n", vres.Interface()) + + return nil +} + +type verbose struct { + roundTripper soap.RoundTripper +} + +func (*verbose) mor(ref types.ManagedObjectReference) string { + if strings.HasPrefix(ref.Value, "session") { + ref.Value = "session[...]" + return ref.String() + } + return ref.Value +} + +func (*verbose) str(val reflect.Value) string { + if !val.IsValid() { + return "" + } + + switch val.Kind() { + case reflect.Ptr, reflect.Interface: + if val.IsNil() { + return "nil" + } + } + + p := "" + + switch pval := val.Interface().(type) { + case fmt.Stringer: + p = pval.String() + case string: + if len(pval) > 45 { + pval = pval[:42] + "..." + } + p = fmt.Sprintf("%s", pval) + case []string: + p = fmt.Sprintf("%v", pval) + case []types.ManagedObjectReference: + refs := make([]string, len(pval)) + for i := range pval { + refs[i] = pval[i].Value + } + p = fmt.Sprintf("%v", refs) + default: + return "" + } + + return p +} + +func (v *verbose) value(val types.AnyType) string { + rval := reflect.ValueOf(val) + if rval.Kind() == reflect.Ptr && !rval.IsNil() { + rval = rval.Elem() + } + if rval.Kind() == reflect.Struct { + if strings.HasPrefix(rval.Type().Name(), "ArrayOf") { + rval = rval.Field(0) + val = rval.Interface() + } + } + s := v.str(rval) + if s != "" { + return s + } + return v.prettyPrint(val) +} + +func (v *verbose) propertyValue(obj types.ManagedObjectReference, name string, pval types.AnyType) string { + val := v.value(pval) + if obj.Type != "Task" && !strings.HasPrefix(obj.Value, "session") { + if len(val) > 512 { + val = fmt.Sprintf("`govc object.collect -dump %s %s`", obj, name) + } + } + return fmt.Sprintf("%s\t%s:\t%s", v.mor(obj), name, val) +} + +func (v *verbose) missingSet(o types.ManagedObjectReference, m []types.MissingProperty) []string { + var s []string + for _, p := range m { + s = append(s, fmt.Sprintf("%s\t%s:\t%s", v.mor(o), p.Path, v.prettyPrint(p.Fault.Fault))) + } + return s +} + +func (v *verbose) updateSet(u *types.UpdateSet) []string { + var s []string + if u == nil { + return s + } + for _, f := range u.FilterSet { + for _, o := range f.ObjectSet { + for _, c := range o.ChangeSet { + s = append(s, v.propertyValue(o.Obj, c.Name, c.Val)) + } + s = append(s, v.missingSet(o.Obj, o.MissingSet)...) + } + } + return s +} + +func (v *verbose) objectContent(content []types.ObjectContent) []string { + var s []string + for _, o := range content { + for _, p := range o.PropSet { + s = append(s, v.propertyValue(o.Obj, p.Name, p.Val)) + } + s = append(s, v.missingSet(o.Obj, o.MissingSet)...) + } + return s +} + +func (v *verbose) prettyPrint(val interface{}) string { + p := pretty.Sprintf("%# v\n", val) + var res []string + scanner := bufio.NewScanner(strings.NewReader(p)) + for scanner.Scan() { + line := scanner.Text() + if strings.Contains(line, "nil,") || strings.Contains(line, "(nil),") { + continue // nil pointer field + } + if strings.Contains(line, `"",`) { + continue // empty string field + } + if strings.Contains(line, `{},`) { + continue // empty embedded struct + } + if strings.Contains(line, "[context]") { + continue // noisy base64 encoded backtrace + } + res = append(res, line) + } + return strings.Join(res, "\n") +} + +func (v *verbose) table(vals []string) { + tw := tabwriter.NewWriter(os.Stderr, 2, 0, 1, ' ', 0) + for _, val := range vals { + fmt.Fprintf(tw, "...%s\n", val) + } + tw.Flush() +} + +func (v *verbose) RoundTrip(ctx context.Context, req, res soap.HasFault) error { + vreq := reflect.ValueOf(req).Elem().FieldByName("Req").Elem() + param := []string{""} + switch f := vreq.Field(0).Interface().(type) { + case types.ManagedObjectReference: + param[0] = v.mor(f) + default: + param[0] = fmt.Sprintf("%v", f) + } + + for i := 1; i < vreq.NumField(); i++ { + val := vreq.Field(i) + + if val.Kind() == reflect.Interface { + val = val.Elem() + } + + p := v.str(val) + if p == "" { + switch val.Kind() { + case reflect.Ptr, reflect.Slice, reflect.Struct: + p = val.Type().String() + default: + p = fmt.Sprintf("%v", val.Interface()) + } + } + + param = append(param, p) + } + + fmt.Fprintf(os.Stderr, "%s(%s)...\n", vreq.Type().Name(), strings.Join(param, ", ")) + + err := v.roundTripper.RoundTrip(ctx, req, res) + if err != nil { + if fault := res.Fault(); fault != nil { + fmt.Fprintln(os.Stderr, v.prettyPrint(fault)) + } else { + fmt.Fprintf(os.Stderr, "...%s\n", err) + } + return err + } + + vres := reflect.ValueOf(res).Elem().FieldByName("Res").Elem() + ret := vres.FieldByName("Returnval") + var s interface{} = "void" + + if ret.IsValid() { + switch x := ret.Interface().(type) { + case types.ManagedObjectReference: + s = v.mor(x) + case *types.UpdateSet: + s = v.updateSet(x) + case []types.ObjectContent: + s = v.objectContent(x) + case fmt.Stringer: + s = x.String() + default: + s = v.value(x) + } + } + if vals, ok := s.([]string); ok { + v.table(vals) + } else { + fmt.Fprintf(os.Stderr, "...%s\n", s) + } + fmt.Fprintln(os.Stderr) + + return err +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/empty.go b/vendor/github.com/vmware/govmomi/govc/flags/empty.go new file mode 100644 index 0000000000..8b17241ba1 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/empty.go @@ -0,0 +1,31 @@ +/* +Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" +) + +type EmptyFlag struct{} + +func (flag *EmptyFlag) Register(ctx context.Context, f *flag.FlagSet) { +} + +func (flag *EmptyFlag) Process(ctx context.Context) error { + return nil +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/env.go b/vendor/github.com/vmware/govmomi/govc/flags/env.go new file mode 100644 index 0000000000..c8b4c53f21 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/env.go @@ -0,0 +1,94 @@ +/* +Copyright (c) 2023-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25/mo" +) + +type EnvBrowser struct { + *ClusterFlag + *HostSystemFlag + *VirtualMachineFlag +} + +func (cmd *EnvBrowser) Register(ctx context.Context, f *flag.FlagSet) { + cmd.ClusterFlag, ctx = NewClusterFlag(ctx) + cmd.ClusterFlag.Register(ctx, f) + + cmd.HostSystemFlag, ctx = NewHostSystemFlag(ctx) + cmd.HostSystemFlag.Register(ctx, f) + + cmd.VirtualMachineFlag, ctx = NewVirtualMachineFlag(ctx) + cmd.VirtualMachineFlag.Register(ctx, f) +} + +func (cmd *EnvBrowser) Process(ctx context.Context) error { + if err := cmd.ClusterFlag.Process(ctx); err != nil { + return err + } + if err := cmd.HostSystemFlag.Process(ctx); err != nil { + return err + } + return cmd.VirtualMachineFlag.Process(ctx) +} + +func (cmd *EnvBrowser) Browser(ctx context.Context) (*object.EnvironmentBrowser, error) { + c, err := cmd.VirtualMachineFlag.Client() + if err != nil { + return nil, err + } + + vm, err := cmd.VirtualMachine() + if err != nil { + return nil, err + } + if vm != nil { + return vm.EnvironmentBrowser(ctx) + } + + host, err := cmd.HostSystemIfSpecified() + if err != nil { + return nil, err + } + + if host != nil { + var h mo.HostSystem + err = host.Properties(ctx, host.Reference(), []string{"parent"}, &h) + if err != nil { + return nil, err + } + + return object.NewComputeResource(c, *h.Parent).EnvironmentBrowser(ctx) + } + + finder, ferr := cmd.ClusterFlag.Finder() + if ferr != nil { + return nil, ferr + } + + cr, ferr := finder.ComputeResourceOrDefault(ctx, cmd.ClusterFlag.Name) + if ferr != nil { + return nil, ferr + } + + return cr.EnvironmentBrowser(ctx) +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/folder.go b/vendor/github.com/vmware/govmomi/govc/flags/folder.go new file mode 100644 index 0000000000..da17bfa726 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/folder.go @@ -0,0 +1,142 @@ +/* +Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + "fmt" + "os" + + "github.com/vmware/govmomi/object" +) + +type FolderFlag struct { + common + + *DatacenterFlag + + name string + folder *object.Folder +} + +var folderFlagKey = flagKey("folder") + +func NewFolderFlag(ctx context.Context) (*FolderFlag, context.Context) { + if v := ctx.Value(folderFlagKey); v != nil { + return v.(*FolderFlag), ctx + } + + v := &FolderFlag{} + v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) + ctx = context.WithValue(ctx, folderFlagKey, v) + return v, ctx +} + +func (flag *FolderFlag) Register(ctx context.Context, f *flag.FlagSet) { + flag.RegisterOnce(func() { + flag.DatacenterFlag.Register(ctx, f) + + env := "GOVC_FOLDER" + value := os.Getenv(env) + usage := fmt.Sprintf("Inventory folder [%s]", env) + f.StringVar(&flag.name, "folder", value, usage) + }) +} + +func (flag *FolderFlag) Process(ctx context.Context) error { + return flag.ProcessOnce(func() error { + if err := flag.DatacenterFlag.Process(ctx); err != nil { + return err + } + return nil + }) +} + +func (flag *FolderFlag) IsSet() bool { + return flag.name != "" +} + +func (flag *FolderFlag) Folder() (*object.Folder, error) { + if flag.folder != nil { + return flag.folder, nil + } + + finder, err := flag.Finder() + if err != nil { + return nil, err + } + + if flag.folder, err = finder.FolderOrDefault(context.TODO(), flag.name); err != nil { + return nil, err + } + + return flag.folder, nil +} + +func (flag *FolderFlag) FolderIfSpecified() (*object.Folder, error) { + if flag.name == "" { + return nil, nil + } + return flag.Folder() +} + +func (flag *FolderFlag) FolderOrDefault(kind string) (*object.Folder, error) { + if flag.folder != nil { + return flag.folder, nil + } + + if flag.name != "" { + return flag.Folder() + } + + // RootFolder, no dc required + if kind == "/" { + client, err := flag.Client() + if err != nil { + return nil, err + } + + flag.folder = object.NewRootFolder(client) + return flag.folder, nil + } + + dc, err := flag.Datacenter() + if err != nil { + return nil, err + } + + folders, err := dc.Folders(context.TODO()) + if err != nil { + return nil, err + } + + switch kind { + case "vm": + flag.folder = folders.VmFolder + case "host": + flag.folder = folders.HostFolder + case "datastore": + flag.folder = folders.DatastoreFolder + case "network": + flag.folder = folders.NetworkFolder + default: + panic(kind) + } + + return flag.folder, nil +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/host_connect.go b/vendor/github.com/vmware/govmomi/govc/flags/host_connect.go new file mode 100644 index 0000000000..c64e4368b2 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/host_connect.go @@ -0,0 +1,100 @@ +/* +Copyright (c) 2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + "fmt" + "net/url" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/types" +) + +type HostConnectFlag struct { + common + + types.HostConnectSpec + + noverify bool +} + +var hostConnectFlagKey = flagKey("hostConnect") + +func NewHostConnectFlag(ctx context.Context) (*HostConnectFlag, context.Context) { + if v := ctx.Value(hostConnectFlagKey); v != nil { + return v.(*HostConnectFlag), ctx + } + + v := &HostConnectFlag{} + ctx = context.WithValue(ctx, hostConnectFlagKey, v) + return v, ctx +} + +func (flag *HostConnectFlag) Register(ctx context.Context, f *flag.FlagSet) { + flag.RegisterOnce(func() { + f.StringVar(&flag.HostName, "hostname", "", "Hostname or IP address of the host") + f.StringVar(&flag.UserName, "username", "", "Username of administration account on the host") + f.StringVar(&flag.Password, "password", "", "Password of administration account on the host") + f.StringVar(&flag.SslThumbprint, "thumbprint", "", "SHA-1 thumbprint of the host's SSL certificate") + f.BoolVar(&flag.Force, "force", false, "Force when host is managed by another VC") + + f.BoolVar(&flag.noverify, "noverify", false, "Accept host thumbprint without verification") + }) +} + +func (flag *HostConnectFlag) Process(ctx context.Context) error { + return nil +} + +// Spec attempts to fill in SslThumbprint if empty. +// First checks GOVC_TLS_KNOWN_HOSTS, if not found and noverify=true then +// use object.HostCertificateInfo to get the thumbprint. +func (flag *HostConnectFlag) Spec(c *vim25.Client) types.HostConnectSpec { + spec := flag.HostConnectSpec + + if spec.SslThumbprint == "" { + spec.SslThumbprint = c.Thumbprint(spec.HostName) + + if spec.SslThumbprint == "" && flag.noverify { + var info object.HostCertificateInfo + t := c.DefaultTransport() + _ = info.FromURL(&url.URL{Host: spec.HostName}, t.TLSClientConfig) + spec.SslThumbprint = info.ThumbprintSHA1 + } + } + + return spec +} + +// Fault checks if error is SSLVerifyFault, including the thumbprint if so +func (flag *HostConnectFlag) Fault(err error) error { + if err == nil { + return nil + } + + if f, ok := err.(types.HasFault); ok { + switch fault := f.Fault().(type) { + case *types.SSLVerifyFault: + return fmt.Errorf("%s thumbprint=%s", err, fault.Thumbprint) + } + } + + return err +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/host_system.go b/vendor/github.com/vmware/govmomi/govc/flags/host_system.go new file mode 100644 index 0000000000..f8704def1a --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/host_system.go @@ -0,0 +1,141 @@ +/* +Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + "fmt" + "os" + + "github.com/vmware/govmomi/object" +) + +type HostSystemFlag struct { + common + + *ClientFlag + *DatacenterFlag + *SearchFlag + + name string + host *object.HostSystem + pool *object.ResourcePool +} + +var hostSystemFlagKey = flagKey("hostSystem") + +func NewHostSystemFlag(ctx context.Context) (*HostSystemFlag, context.Context) { + if v := ctx.Value(hostSystemFlagKey); v != nil { + return v.(*HostSystemFlag), ctx + } + + v := &HostSystemFlag{} + v.ClientFlag, ctx = NewClientFlag(ctx) + v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) + v.SearchFlag, ctx = NewSearchFlag(ctx, SearchHosts) + ctx = context.WithValue(ctx, hostSystemFlagKey, v) + return v, ctx +} + +func (flag *HostSystemFlag) Register(ctx context.Context, f *flag.FlagSet) { + flag.RegisterOnce(func() { + flag.ClientFlag.Register(ctx, f) + flag.DatacenterFlag.Register(ctx, f) + flag.SearchFlag.Register(ctx, f) + + env := "GOVC_HOST" + value := os.Getenv(env) + usage := fmt.Sprintf("Host system [%s]", env) + f.StringVar(&flag.name, "host", value, usage) + }) +} + +func (flag *HostSystemFlag) Process(ctx context.Context) error { + return flag.ProcessOnce(func() error { + if err := flag.ClientFlag.Process(ctx); err != nil { + return err + } + if err := flag.DatacenterFlag.Process(ctx); err != nil { + return err + } + if err := flag.SearchFlag.Process(ctx); err != nil { + return err + } + return nil + }) +} + +func (flag *HostSystemFlag) HostSystemIfSpecified() (*object.HostSystem, error) { + if flag.host != nil { + return flag.host, nil + } + + // Use search flags if specified. + if flag.SearchFlag.IsSet() && flag.SearchFlag.t == SearchHosts { + host, err := flag.SearchFlag.HostSystem() + if err != nil { + return nil, err + } + + flag.host = host + return flag.host, nil + } + + // Never look for a default host system. + // A host system parameter is optional for vm creation. It uses a mandatory + // resource pool parameter to determine where the vm should be placed. + if flag.name == "" { + return nil, nil + } + + finder, err := flag.Finder() + if err != nil { + return nil, err + } + + flag.host, err = finder.HostSystem(context.TODO(), flag.name) + return flag.host, err +} + +func (flag *HostSystemFlag) HostSystem() (*object.HostSystem, error) { + host, err := flag.HostSystemIfSpecified() + if err != nil { + return nil, err + } + + if host != nil { + return host, nil + } + + finder, err := flag.Finder() + if err != nil { + return nil, err + } + + flag.host, err = finder.DefaultHostSystem(context.TODO()) + return flag.host, err +} + +func (flag *HostSystemFlag) HostNetworkSystem() (*object.HostNetworkSystem, error) { + host, err := flag.HostSystem() + if err != nil { + return nil, err + } + + return host.ConfigManager().NetworkSystem(context.TODO()) +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/int32.go b/vendor/github.com/vmware/govmomi/govc/flags/int32.go new file mode 100644 index 0000000000..a993c3eeac --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/int32.go @@ -0,0 +1,72 @@ +/* +Copyright (c) 2016-2017 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "flag" + "fmt" + "strconv" +) + +// This flag type is internal to stdlib: +// https://github.com/golang/go/blob/master/src/cmd/internal/obj/flag.go +type int32Value int32 + +func (i *int32Value) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 32) + *i = int32Value(v) + return err +} + +func (i *int32Value) Get() interface{} { + return int32(*i) +} + +func (i *int32Value) String() string { + return fmt.Sprintf("%v", *i) +} + +// NewInt32 behaves as flag.IntVar, but using an int32 type. +func NewInt32(v *int32) flag.Value { + return (*int32Value)(v) +} + +type int32ptrValue struct { + val **int32 +} + +func (i *int32ptrValue) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 32) + *i.val = new(int32) + **i.val = int32(v) + return err +} + +func (i *int32ptrValue) Get() interface{} { + if i.val == nil || *i.val == nil { + return nil + } + return *i.val +} + +func (i *int32ptrValue) String() string { + return fmt.Sprintf("%v", i.Get()) +} + +func NewOptionalInt32(v **int32) flag.Value { + return &int32ptrValue{val: v} +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/int64.go b/vendor/github.com/vmware/govmomi/govc/flags/int64.go new file mode 100644 index 0000000000..e3b8cc5a95 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/int64.go @@ -0,0 +1,72 @@ +/* +Copyright (c) 2017 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "flag" + "fmt" + "strconv" +) + +// This flag type is internal to stdlib: +// https://github.com/golang/go/blob/master/src/cmd/internal/obj/flag.go +type int64Value int64 + +func (i *int64Value) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + *i = int64Value(v) + return err +} + +func (i *int64Value) Get() interface{} { + return int64(*i) +} + +func (i *int64Value) String() string { + return fmt.Sprintf("%v", *i) +} + +// NewInt64 behaves as flag.IntVar, but using an int64 type. +func NewInt64(v *int64) flag.Value { + return (*int64Value)(v) +} + +type int64ptrValue struct { + val **int64 +} + +func (i *int64ptrValue) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + *i.val = new(int64) + **i.val = int64(v) + return err +} + +func (i *int64ptrValue) Get() interface{} { + if i.val == nil || *i.val == nil { + return nil + } + return **i.val +} + +func (i *int64ptrValue) String() string { + return fmt.Sprintf("%v", i.Get()) +} + +func NewOptionalInt64(v **int64) flag.Value { + return &int64ptrValue{val: v} +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/library.go b/vendor/github.com/vmware/govmomi/govc/flags/library.go new file mode 100644 index 0000000000..3b715f457f --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/library.go @@ -0,0 +1,93 @@ +/* +Copyright (c) 2020-2022 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "fmt" + + "github.com/vmware/govmomi/vapi/library" + "github.com/vmware/govmomi/vapi/library/finder" + "github.com/vmware/govmomi/vapi/rest" +) + +// errContentLibraryMatch is an error returned when a query returns more than one result. +type errContentLibraryMatch struct { + // Type is the type of object being queried. + Type string + + // Key is the key used to perform the query. + Key string + + // Val is the value used to perform the query. + Val string + + // Count is the number of objects returned. + Count int +} + +// Error returns the error string. +func (e errContentLibraryMatch) Error() string { + kind := e.Type + if kind == "" { + kind = "library|item" + } + hint := "" + if e.Count > 1 { + hint = fmt.Sprintf(" (use %q ID instead of NAME)", kind) + } + return fmt.Sprintf("%q=%q matches %d items%s", e.Key, e.Val, e.Count, hint) +} + +func ContentLibraryResult(ctx context.Context, c *rest.Client, kind string, path string) (finder.FindResult, error) { + res, err := finder.NewFinder(library.NewManager(c)).Find(ctx, path) + if err != nil { + return nil, err + } + if len(res) != 1 { + return nil, errContentLibraryMatch{Type: kind, Key: "path", Val: path, Count: len(res)} + } + return res[0], nil +} + +// ContentLibrary attempts to find a content library with the given path, +// asserting 1 match of type library.Library. +func ContentLibrary(ctx context.Context, c *rest.Client, path string) (*library.Library, error) { + r, err := ContentLibraryResult(ctx, c, "library", path) + if err != nil { + return nil, err + } + lib, ok := r.GetResult().(library.Library) + if !ok { + return nil, fmt.Errorf("%q is a %T", path, r) + } + return &lib, nil +} + +// ContentLibraryItem attempts to find a content library with the given path, +// asserting 1 match of type library.Item. +func ContentLibraryItem(ctx context.Context, c *rest.Client, path string) (*library.Item, error) { + r, err := ContentLibraryResult(ctx, c, "item", path) + if err != nil { + return nil, err + } + item, ok := r.GetResult().(library.Item) + if !ok { + return nil, fmt.Errorf("%q is a %T", path, r) + } + return &item, nil +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/list.go b/vendor/github.com/vmware/govmomi/govc/flags/list.go new file mode 100644 index 0000000000..0cd874b77a --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/list.go @@ -0,0 +1,30 @@ +/* +Copyright (c) 2019 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import "fmt" + +type StringList []string + +func (l *StringList) String() string { + return fmt.Sprint(*l) +} + +func (l *StringList) Set(value string) error { + *l = append(*l, value) + return nil +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/network.go b/vendor/github.com/vmware/govmomi/govc/flags/network.go new file mode 100644 index 0000000000..5e187303c0 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/network.go @@ -0,0 +1,165 @@ +/* +Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + "fmt" + "os" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25/types" +) + +type NetworkFlag struct { + common + + *DatacenterFlag + + name string + net object.NetworkReference + adapter string + address string + isset bool + proto string +} + +var networkFlagKey = flagKey("network") + +func NewNetworkFlag(ctx context.Context) (*NetworkFlag, context.Context) { + if v := ctx.Value(networkFlagKey); v != nil { + return v.(*NetworkFlag), ctx + } + + v := &NetworkFlag{} + v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) + ctx = context.WithValue(ctx, networkFlagKey, v) + return v, ctx +} + +func (flag *NetworkFlag) Register(ctx context.Context, f *flag.FlagSet) { + flag.RegisterOnce(func() { + flag.DatacenterFlag.Register(ctx, f) + + env := "GOVC_NETWORK" + value := os.Getenv(env) + flag.name = value + usage := fmt.Sprintf("Network [%s]", env) + f.Var(flag, "net", usage) + f.StringVar(&flag.adapter, "net.adapter", "e1000", "Network adapter type") + f.StringVar(&flag.address, "net.address", "", "Network hardware address") + f.StringVar(&flag.proto, "net.protocol", "", fmt.Sprintf("Network device protocol. Applicable to vmxnet3vrdma. Default to '%s'", string(types.VirtualVmxnet3VrdmaOptionDeviceProtocolsRocev2))) + }) +} + +func (flag *NetworkFlag) Process(ctx context.Context) error { + return flag.ProcessOnce(func() error { + if err := flag.DatacenterFlag.Process(ctx); err != nil { + return err + } + return nil + }) +} + +func (flag *NetworkFlag) String() string { + return flag.name +} + +func (flag *NetworkFlag) Set(name string) error { + flag.name = name + flag.isset = true + return nil +} + +func (flag *NetworkFlag) IsSet() bool { + return flag.isset +} + +func (flag *NetworkFlag) Network() (object.NetworkReference, error) { + if flag.net != nil { + return flag.net, nil + } + + finder, err := flag.Finder() + if err != nil { + return nil, err + } + + if flag.net, err = finder.NetworkOrDefault(context.TODO(), flag.name); err != nil { + return nil, err + } + + return flag.net, nil +} + +func (flag *NetworkFlag) Device() (types.BaseVirtualDevice, error) { + net, err := flag.Network() + if err != nil { + return nil, err + } + + backing, err := net.EthernetCardBackingInfo(context.TODO()) + if err != nil { + return nil, err + } + + device, err := object.EthernetCardTypes().CreateEthernetCard(flag.adapter, backing) + if err != nil { + return nil, err + } + + if a, ok := device.(*types.VirtualVmxnet3Vrdma); ok { + if flag.proto != "" { + if flag.proto != string(types.VirtualVmxnet3VrdmaOptionDeviceProtocolsRocev2) && + flag.proto != string(types.VirtualVmxnet3VrdmaOptionDeviceProtocolsRocev1) { + return nil, fmt.Errorf("invalid device protocol '%s'", flag.proto) + } + a.DeviceProtocol = flag.proto + } + } else if flag.proto != "" { + return nil, fmt.Errorf("device protocol is only supported for vmxnet3vrdma at the moment") + } + + if flag.address == "-" { + card := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() + card.AddressType = string(types.VirtualEthernetCardMacTypeGenerated) + card.MacAddress = "" + } else if flag.address != "" { + card := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() + card.AddressType = string(types.VirtualEthernetCardMacTypeManual) + card.MacAddress = flag.address + } + + return device, nil +} + +// Change applies update backing and hardware address changes to the given network device. +func (flag *NetworkFlag) Change(device types.BaseVirtualDevice, update types.BaseVirtualDevice) { + current := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() + changed := update.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() + + current.Backing = changed.Backing + + if changed.MacAddress != "" { + current.MacAddress = changed.MacAddress + } + + if changed.AddressType != "" { + current.AddressType = changed.AddressType + } +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/optional_bool.go b/vendor/github.com/vmware/govmomi/govc/flags/optional_bool.go new file mode 100644 index 0000000000..db1b81f89b --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/optional_bool.go @@ -0,0 +1,55 @@ +/* +Copyright (c) 2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "flag" + "fmt" + "strconv" +) + +type optionalBool struct { + val **bool +} + +func (b *optionalBool) Set(s string) error { + v, err := strconv.ParseBool(s) + *b.val = &v + return err +} + +func (b *optionalBool) Get() interface{} { + if *b.val == nil { + return nil + } + return **b.val +} + +func (b *optionalBool) String() string { + if b.val == nil || *b.val == nil { + return "" + } + return fmt.Sprintf("%v", **b.val) +} + +func (b *optionalBool) IsBoolFlag() bool { return true } + +// NewOptionalBool returns a flag.Value implementation where there is no default value. +// This avoids sending a default value over the wire as using flag.BoolVar() would. +func NewOptionalBool(v **bool) flag.Value { + return &optionalBool{v} +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/optional_string.go b/vendor/github.com/vmware/govmomi/govc/flags/optional_string.go new file mode 100644 index 0000000000..0460785d03 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/optional_string.go @@ -0,0 +1,50 @@ +/* +Copyright (c) 2023-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "flag" +) + +type optionalString struct { + val **string +} + +func (s *optionalString) Set(input string) error { + *s.val = &input + return nil +} + +func (s *optionalString) Get() interface{} { + if *s.val == nil { + return nil + } + return **s.val +} + +func (s *optionalString) String() string { + if s.val == nil || *s.val == nil { + return "" + } + return **s.val +} + +// NewOptionalString returns a flag.Value implementation where there is no default value. +// This avoids sending a default value over the wire as using flag.StringVar() would. +func NewOptionalString(v **string) flag.Value { + return &optionalString{v} +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/output.go b/vendor/github.com/vmware/govmomi/govc/flags/output.go new file mode 100644 index 0000000000..c0338b18c3 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/output.go @@ -0,0 +1,384 @@ +/* +Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "encoding/json" + "errors" + "flag" + "fmt" + "io" + "os" + "reflect" + "strings" + "sync" + "time" + + "github.com/dougm/pretty" + + "github.com/vmware/govmomi/task" + "github.com/vmware/govmomi/vim25/progress" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" + "github.com/vmware/govmomi/vim25/xml" +) + +type OutputWriter interface { + Write(io.Writer) error +} + +type OutputFlag struct { + common + + JSON bool + XML bool + TTY bool + Dump bool + Out io.Writer + + formatError bool + formatIndent bool +} + +var outputFlagKey = flagKey("output") + +func NewOutputFlag(ctx context.Context) (*OutputFlag, context.Context) { + if v := ctx.Value(outputFlagKey); v != nil { + return v.(*OutputFlag), ctx + } + + v := &OutputFlag{Out: os.Stdout} + ctx = context.WithValue(ctx, outputFlagKey, v) + return v, ctx +} + +func (flag *OutputFlag) Register(ctx context.Context, f *flag.FlagSet) { + flag.RegisterOnce(func() { + f.BoolVar(&flag.JSON, "json", false, "Enable JSON output") + f.BoolVar(&flag.XML, "xml", false, "Enable XML output") + f.BoolVar(&flag.Dump, "dump", false, "Enable Go output") + // Avoid adding more flags for now.. + flag.formatIndent = os.Getenv("GOVC_INDENT") != "false" // Default to indented output + flag.formatError = os.Getenv("GOVC_FORMAT_ERROR") != "false" // Default to formatted errors + }) +} + +func (flag *OutputFlag) Process(ctx context.Context) error { + return flag.ProcessOnce(func() error { + if !flag.All() { + // Assume we have a tty if not outputting JSON + flag.TTY = true + } + + return nil + }) +} + +// Log outputs the specified string, prefixed with the current time. +// A newline is not automatically added. If the specified string +// starts with a '\r', the current line is cleared first. +func (flag *OutputFlag) Log(s string) (int, error) { + if len(s) > 0 && s[0] == '\r' { + flag.Write([]byte{'\r', 033, '[', 'K'}) + s = s[1:] + } + + return flag.WriteString(time.Now().Format("[02-01-06 15:04:05] ") + s) +} + +func (flag *OutputFlag) Write(b []byte) (int, error) { + if !flag.TTY { + return 0, nil + } + + w := flag.Out + if w == nil { + w = os.Stdout + } + n, err := w.Write(b) + if w == os.Stdout { + os.Stdout.Sync() + } + return n, err +} + +func (flag *OutputFlag) WriteString(s string) (int, error) { + return flag.Write([]byte(s)) +} + +func (flag *OutputFlag) All() bool { + return flag.JSON || flag.XML || flag.Dump +} + +func dumpValue(val interface{}) interface{} { + type dumper interface { + Dump() interface{} + } + + if d, ok := val.(dumper); ok { + return d.Dump() + } + + rval := reflect.ValueOf(val) + if rval.Type().Kind() != reflect.Ptr { + return val + } + + rval = rval.Elem() + if rval.Type().Kind() == reflect.Struct { + f := rval.Field(0) + if f.Type().Kind() == reflect.Slice { + // common case for the various 'type infoResult' + if f.Len() == 1 { + return f.Index(0).Interface() + } + return f.Interface() + } + + if rval.NumField() == 1 && rval.Type().Field(0).Anonymous { + // common case where govc type wraps govmomi type to implement OutputWriter + return f.Interface() + } + } + + return val +} + +func (flag *OutputFlag) WriteResult(result OutputWriter) error { + var err error + + switch { + case flag.Dump: + format := "%#v\n" + if flag.formatIndent { + format = "%# v\n" + } + _, err = pretty.Fprintf(flag.Out, format, dumpValue(result)) + case flag.JSON: + e := json.NewEncoder(flag.Out) + if flag.formatIndent { + e.SetIndent("", " ") + } + err = e.Encode(result) + case flag.XML: + e := xml.NewEncoder(flag.Out) + if flag.formatIndent { + e.Indent("", " ") + } + err = e.Encode(dumpValue(result)) + if err == nil { + fmt.Fprintln(flag.Out) + } + default: + err = result.Write(flag.Out) + } + + return err +} + +func (flag *OutputFlag) WriteError(err error) bool { + if flag.formatError { + flag.Out = os.Stderr + return flag.WriteResult(&errorOutput{err}) == nil + } + return false +} + +type errorOutput struct { + error +} + +func (e errorOutput) Write(w io.Writer) error { + reason := e.error.Error() + var messages []string + var faults []types.LocalizableMessage + + switch err := e.error.(type) { + case task.Error: + faults = err.LocalizedMethodFault.Fault.GetMethodFault().FaultMessage + if err.Description != nil { + reason = fmt.Sprintf("%s (%s)", reason, err.Description.Message) + } + default: + if soap.IsSoapFault(err) { + detail := soap.ToSoapFault(err).Detail.Fault + if f, ok := detail.(types.BaseMethodFault); ok { + faults = f.GetMethodFault().FaultMessage + } + } + } + + for _, m := range faults { + if m.Message != "" && !strings.HasPrefix(m.Message, "[context]") { + messages = append(messages, fmt.Sprintf("%s (%s)", m.Message, m.Key)) + } + } + + messages = append(messages, reason) + + for _, message := range messages { + if _, err := fmt.Fprintf(w, "%s: %s\n", os.Args[0], message); err != nil { + return err + } + } + + return nil +} + +func (e errorOutput) Dump() interface{} { + if f, ok := e.error.(task.Error); ok { + return f.LocalizedMethodFault + } + if soap.IsSoapFault(e.error) { + return soap.ToSoapFault(e.error) + } + if soap.IsVimFault(e.error) { + return soap.ToVimFault(e.error) + } + return e +} + +func (e errorOutput) canEncode() bool { + switch e.error.(type) { + case task.Error: + return true + } + return soap.IsSoapFault(e.error) || soap.IsVimFault(e.error) +} + +// cannotEncode causes cli.Run to output err.Error() as it would without an error format specified +var cannotEncode = errors.New("cannot encode error") + +func (e errorOutput) MarshalJSON() ([]byte, error) { + _, ok := e.error.(json.Marshaler) + if ok || e.canEncode() { + return json.Marshal(e.error) + } + return nil, cannotEncode +} + +func (e errorOutput) MarshalXML(encoder *xml.Encoder, start xml.StartElement) error { + _, ok := e.error.(xml.Marshaler) + if ok || e.canEncode() { + return encoder.Encode(e.error) + } + return cannotEncode +} + +type progressLogger struct { + flag *OutputFlag + prefix string + + wg sync.WaitGroup + + sink chan chan progress.Report + done chan struct{} +} + +func newProgressLogger(flag *OutputFlag, prefix string) *progressLogger { + p := &progressLogger{ + flag: flag, + prefix: prefix, + + sink: make(chan chan progress.Report), + done: make(chan struct{}), + } + + p.wg.Add(1) + + go p.loopA() + + return p +} + +// loopA runs before Sink() has been called. +func (p *progressLogger) loopA() { + var err error + + defer p.wg.Done() + + tick := time.NewTicker(100 * time.Millisecond) + defer tick.Stop() + + called := false + + for stop := false; !stop; { + select { + case ch := <-p.sink: + err = p.loopB(tick, ch) + stop = true + called = true + case <-p.done: + stop = true + case <-tick.C: + line := fmt.Sprintf("\r%s", p.prefix) + p.flag.Log(line) + } + } + + if err != nil && err != io.EOF { + p.flag.Log(fmt.Sprintf("\r%sError: %s\n", p.prefix, err)) + } else if called { + p.flag.Log(fmt.Sprintf("\r%sOK\n", p.prefix)) + } +} + +// loopA runs after Sink() has been called. +func (p *progressLogger) loopB(tick *time.Ticker, ch <-chan progress.Report) error { + var r progress.Report + var ok bool + var err error + + for ok = true; ok; { + select { + case r, ok = <-ch: + if !ok { + break + } + err = r.Error() + case <-tick.C: + line := fmt.Sprintf("\r%s", p.prefix) + if r != nil { + line += fmt.Sprintf("(%.0f%%", r.Percentage()) + detail := r.Detail() + if detail != "" { + line += fmt.Sprintf(", %s", detail) + } + line += ")" + } + p.flag.Log(line) + } + } + + return err +} + +func (p *progressLogger) Sink() chan<- progress.Report { + ch := make(chan progress.Report) + p.sink <- ch + return ch +} + +func (p *progressLogger) Wait() { + close(p.done) + p.wg.Wait() +} + +func (flag *OutputFlag) ProgressLogger(prefix string) *progressLogger { + return newProgressLogger(flag, prefix) +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/resource_allocation_info.go b/vendor/github.com/vmware/govmomi/govc/flags/resource_allocation_info.go new file mode 100644 index 0000000000..99a262ec45 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/resource_allocation_info.go @@ -0,0 +1,85 @@ +/* +Copyright (c) 2017 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + "strconv" + "strings" + + "github.com/vmware/govmomi/vim25/types" +) + +type sharesInfo types.SharesInfo + +func (s *sharesInfo) String() string { + return string(s.Level) +} + +func (s *sharesInfo) Set(val string) error { + switch val { + case string(types.SharesLevelNormal), string(types.SharesLevelLow), string(types.SharesLevelHigh): + s.Level = types.SharesLevel(val) + default: + n, err := strconv.Atoi(val) + if err != nil { + return err + } + + s.Level = types.SharesLevelCustom + s.Shares = int32(n) + } + + return nil +} + +type ResourceAllocationFlag struct { + cpu, mem *types.ResourceAllocationInfo + ExpandableReservation bool +} + +func NewResourceAllocationFlag(cpu, mem *types.ResourceAllocationInfo) *ResourceAllocationFlag { + return &ResourceAllocationFlag{cpu, mem, true} +} + +func (r *ResourceAllocationFlag) Register(ctx context.Context, f *flag.FlagSet) { + opts := []struct { + name string + units string + *types.ResourceAllocationInfo + }{ + {"CPU", "MHz", r.cpu}, + {"Memory", "MB", r.mem}, + } + + for _, opt := range opts { + prefix := strings.ToLower(opt.name)[:3] + shares := (*sharesInfo)(opt.Shares) + + f.Var(NewOptionalInt64(&opt.Limit), prefix+".limit", opt.name+" limit in "+opt.units) + f.Var(NewOptionalInt64(&opt.Reservation), prefix+".reservation", opt.name+" reservation in "+opt.units) + if r.ExpandableReservation { + f.Var(NewOptionalBool(&opt.ExpandableReservation), prefix+".expandable", opt.name+" expandable reservation") + } + f.Var(shares, prefix+".shares", opt.name+" shares level or number") + } +} + +func (s *ResourceAllocationFlag) Process(ctx context.Context) error { + return nil +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/resource_pool.go b/vendor/github.com/vmware/govmomi/govc/flags/resource_pool.go new file mode 100644 index 0000000000..b3d87b7197 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/resource_pool.go @@ -0,0 +1,106 @@ +/* +Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + "fmt" + "os" + + "github.com/vmware/govmomi/find" + "github.com/vmware/govmomi/object" +) + +type ResourcePoolFlag struct { + common + + *DatacenterFlag + + name string + pool *object.ResourcePool +} + +var resourcePoolFlagKey = flagKey("resourcePool") + +func NewResourcePoolFlag(ctx context.Context) (*ResourcePoolFlag, context.Context) { + if v := ctx.Value(resourcePoolFlagKey); v != nil { + return v.(*ResourcePoolFlag), ctx + } + + v := &ResourcePoolFlag{} + v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) + ctx = context.WithValue(ctx, resourcePoolFlagKey, v) + return v, ctx +} + +func (flag *ResourcePoolFlag) Register(ctx context.Context, f *flag.FlagSet) { + flag.RegisterOnce(func() { + flag.DatacenterFlag.Register(ctx, f) + + env := "GOVC_RESOURCE_POOL" + value := os.Getenv(env) + usage := fmt.Sprintf("Resource pool [%s]", env) + f.StringVar(&flag.name, "pool", value, usage) + }) +} + +func (flag *ResourcePoolFlag) Process(ctx context.Context) error { + return flag.ProcessOnce(func() error { + if err := flag.DatacenterFlag.Process(ctx); err != nil { + return err + } + return nil + }) +} + +func (flag *ResourcePoolFlag) IsSet() bool { + return flag.name != "" +} + +func (flag *ResourcePoolFlag) ResourcePool() (*object.ResourcePool, error) { + if flag.pool != nil { + return flag.pool, nil + } + + finder, err := flag.Finder() + if err != nil { + return nil, err + } + + flag.pool, err = finder.ResourcePoolOrDefault(context.TODO(), flag.name) + if err != nil { + if _, ok := err.(*find.NotFoundError); ok { + vapp, verr := finder.VirtualApp(context.TODO(), flag.name) + if verr != nil { + return nil, err + } + flag.pool = vapp.ResourcePool + } else { + return nil, err + } + } + + return flag.pool, nil +} + +func (flag *ResourcePoolFlag) ResourcePoolIfSpecified() (*object.ResourcePool, error) { + if flag.name == "" { + return nil, nil + } + return flag.ResourcePool() +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/search.go b/vendor/github.com/vmware/govmomi/govc/flags/search.go new file mode 100644 index 0000000000..ba884090a7 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/search.go @@ -0,0 +1,438 @@ +/* +Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "errors" + "flag" + "fmt" + "strings" + + "github.com/vmware/govmomi/find" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +const ( + SearchVirtualMachines = iota + 1 + SearchHosts + SearchVirtualApps +) + +type SearchFlag struct { + common + + *ClientFlag + *DatacenterFlag + + t int + entity string + + byDatastorePath string + byDNSName string + byInventoryPath string + byIP string + byUUID string + + isset bool +} + +func NewSearchFlag(ctx context.Context, t int) (*SearchFlag, context.Context) { + searchFlagKey := flagKey(fmt.Sprintf("search%d", t)) + + if v := ctx.Value(searchFlagKey); v != nil { + return v.(*SearchFlag), ctx + } + + v := &SearchFlag{ + t: t, + } + + v.ClientFlag, ctx = NewClientFlag(ctx) + v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) + + switch t { + case SearchVirtualMachines: + v.entity = "VM" + case SearchHosts: + v.entity = "host" + case SearchVirtualApps: + v.entity = "vapp" + default: + panic("invalid search type") + } + + ctx = context.WithValue(ctx, searchFlagKey, v) + return v, ctx +} + +func (flag *SearchFlag) Register(ctx context.Context, fs *flag.FlagSet) { + flag.RegisterOnce(func() { + flag.ClientFlag.Register(ctx, fs) + flag.DatacenterFlag.Register(ctx, fs) + + register := func(v *string, f string, d string) { + f = fmt.Sprintf("%s.%s", strings.ToLower(flag.entity), f) + d = fmt.Sprintf(d, flag.entity) + fs.StringVar(v, f, "", d) + } + + switch flag.t { + case SearchVirtualMachines: + register(&flag.byDatastorePath, "path", "Find %s by path to .vmx file") + } + + switch flag.t { + case SearchVirtualMachines, SearchHosts: + register(&flag.byDNSName, "dns", "Find %s by FQDN") + register(&flag.byIP, "ip", "Find %s by IP address") + register(&flag.byUUID, "uuid", "Find %s by UUID") + } + + register(&flag.byInventoryPath, "ipath", "Find %s by inventory path") + }) +} + +func (flag *SearchFlag) Process(ctx context.Context) error { + return flag.ProcessOnce(func() error { + if err := flag.ClientFlag.Process(ctx); err != nil { + return err + } + if err := flag.DatacenterFlag.Process(ctx); err != nil { + return err + } + + flags := []string{ + flag.byDatastorePath, + flag.byDNSName, + flag.byInventoryPath, + flag.byIP, + flag.byUUID, + } + + flag.isset = false + for _, f := range flags { + if f != "" { + if flag.isset { + return errors.New("cannot use more than one search flag") + } + flag.isset = true + } + } + + return nil + }) +} + +func (flag *SearchFlag) IsSet() bool { + return flag.isset +} + +func (flag *SearchFlag) searchIndex(c *vim25.Client) *object.SearchIndex { + return object.NewSearchIndex(c) +} + +func (flag *SearchFlag) searchByDatastorePath(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { + ctx := context.TODO() + switch flag.t { + case SearchVirtualMachines: + return flag.searchIndex(c).FindByDatastorePath(ctx, dc, flag.byDatastorePath) + default: + panic("unsupported type") + } +} + +func (flag *SearchFlag) searchByDNSName(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { + ctx := context.TODO() + switch flag.t { + case SearchVirtualMachines: + return flag.searchIndex(c).FindByDnsName(ctx, dc, flag.byDNSName, true) + case SearchHosts: + return flag.searchIndex(c).FindByDnsName(ctx, dc, flag.byDNSName, false) + default: + panic("unsupported type") + } +} + +func (flag *SearchFlag) searchByInventoryPath(c *vim25.Client) (object.Reference, error) { + ctx := context.TODO() + return flag.searchIndex(c).FindByInventoryPath(ctx, flag.byInventoryPath) +} + +func (flag *SearchFlag) searchByIP(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { + ctx := context.TODO() + switch flag.t { + case SearchVirtualMachines: + return flag.searchIndex(c).FindByIp(ctx, dc, flag.byIP, true) + case SearchHosts: + return flag.searchIndex(c).FindByIp(ctx, dc, flag.byIP, false) + default: + panic("unsupported type") + } +} + +func (flag *SearchFlag) searchByUUID(c *vim25.Client, dc *object.Datacenter) (object.Reference, error) { + ctx := context.TODO() + isVM := false + switch flag.t { + case SearchVirtualMachines: + isVM = true + case SearchHosts: + default: + panic("unsupported type") + } + + var ref object.Reference + var err error + + for _, iu := range []*bool{nil, types.NewBool(true)} { + ref, err = flag.searchIndex(c).FindByUuid(ctx, dc, flag.byUUID, isVM, iu) + if err != nil { + if soap.IsSoapFault(err) { + fault := soap.ToSoapFault(err).VimFault() + if _, ok := fault.(types.InvalidArgument); ok { + continue + } + } + return nil, err + } + if ref != nil { + break + } + } + + return ref, nil +} + +func (flag *SearchFlag) search() (object.Reference, error) { + ctx := context.TODO() + var ref object.Reference + var err error + var dc *object.Datacenter + + c, err := flag.Client() + if err != nil { + return nil, err + } + + isPath := flag.byInventoryPath != "" + if !isPath { + // All other SearchIndex methods require a Datacenter param + dc, err = flag.Datacenter() + if err != nil { + return nil, err + } + } + + switch { + case isPath: + ref, err = flag.searchByInventoryPath(c) + case flag.byDatastorePath != "": + ref, err = flag.searchByDatastorePath(c, dc) + case flag.byDNSName != "": + ref, err = flag.searchByDNSName(c, dc) + case flag.byIP != "": + ref, err = flag.searchByIP(c, dc) + case flag.byUUID != "": + ref, err = flag.searchByUUID(c, dc) + default: + err = errors.New("no search flag specified") + } + + if err != nil { + return nil, err + } + + if ref == nil { + return nil, fmt.Errorf("no such %s", flag.entity) + } + + // set the InventoryPath field + finder, err := flag.Finder() + if err != nil { + return nil, err + } + ref, err = finder.ObjectReference(ctx, ref.Reference()) + if err != nil { + return nil, err + } + + return ref, nil +} + +func (flag *SearchFlag) VirtualMachine() (*object.VirtualMachine, error) { + ref, err := flag.search() + if err != nil { + return nil, err + } + + vm, ok := ref.(*object.VirtualMachine) + if !ok { + return nil, fmt.Errorf("expected VirtualMachine entity, got %s", ref.Reference().Type) + } + + return vm, nil +} + +func (flag *SearchFlag) VirtualMachines(args []string) ([]*object.VirtualMachine, error) { + ctx := context.TODO() + var out []*object.VirtualMachine + + if flag.IsSet() { + vm, err := flag.VirtualMachine() + if err != nil { + return nil, err + } + + out = append(out, vm) + return out, nil + } + + // List virtual machines + if len(args) == 0 { + return nil, errors.New("no argument") + } + + finder, err := flag.Finder() + if err != nil { + return nil, err + } + + var nfe error + + // List virtual machines for every argument + for _, arg := range args { + vms, err := finder.VirtualMachineList(ctx, arg) + if err != nil { + if _, ok := err.(*find.NotFoundError); ok { + // Let caller decide how to handle NotFoundError + nfe = err + continue + } + return nil, err + } + + out = append(out, vms...) + } + + return out, nfe +} + +func (flag *SearchFlag) VirtualApp() (*object.VirtualApp, error) { + ref, err := flag.search() + if err != nil { + return nil, err + } + + app, ok := ref.(*object.VirtualApp) + if !ok { + return nil, fmt.Errorf("expected VirtualApp entity, got %s", ref.Reference().Type) + } + + return app, nil +} + +func (flag *SearchFlag) VirtualApps(args []string) ([]*object.VirtualApp, error) { + ctx := context.TODO() + var out []*object.VirtualApp + + if flag.IsSet() { + app, err := flag.VirtualApp() + if err != nil { + return nil, err + } + + out = append(out, app) + return out, nil + } + + // List virtual apps + if len(args) == 0 { + return nil, errors.New("no argument") + } + + finder, err := flag.Finder() + if err != nil { + return nil, err + } + + // List virtual apps for every argument + for _, arg := range args { + apps, err := finder.VirtualAppList(ctx, arg) + if err != nil { + return nil, err + } + + out = append(out, apps...) + } + + return out, nil +} + +func (flag *SearchFlag) HostSystem() (*object.HostSystem, error) { + ref, err := flag.search() + if err != nil { + return nil, err + } + + host, ok := ref.(*object.HostSystem) + if !ok { + return nil, fmt.Errorf("expected HostSystem entity, got %s", ref.Reference().Type) + } + + return host, nil +} + +func (flag *SearchFlag) HostSystems(args []string) ([]*object.HostSystem, error) { + ctx := context.TODO() + var out []*object.HostSystem + + if flag.IsSet() { + host, err := flag.HostSystem() + if err != nil { + return nil, err + } + + out = append(out, host) + return out, nil + } + + // List host system + if len(args) == 0 { + return nil, errors.New("no argument") + } + + finder, err := flag.Finder() + if err != nil { + return nil, err + } + + // List host systems for every argument + for _, arg := range args { + vms, err := finder.HostSystemList(ctx, arg) + if err != nil { + return nil, err + } + + out = append(out, vms...) + } + + return out, nil +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/storage_pod.go b/vendor/github.com/vmware/govmomi/govc/flags/storage_pod.go new file mode 100644 index 0000000000..a7631486f8 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/storage_pod.go @@ -0,0 +1,94 @@ +/* +Copyright (c) 2014-2022 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + "fmt" + "os" + + "github.com/vmware/govmomi/object" +) + +type StoragePodFlag struct { + common + + *DatacenterFlag + + Name string + + sp *object.StoragePod +} + +var storagePodFlagKey = flagKey("storagePod") + +func NewStoragePodFlag(ctx context.Context) (*StoragePodFlag, context.Context) { + if v := ctx.Value(storagePodFlagKey); v != nil { + return v.(*StoragePodFlag), ctx + } + + v := &StoragePodFlag{} + v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) + ctx = context.WithValue(ctx, storagePodFlagKey, v) + return v, ctx +} + +func (f *StoragePodFlag) Register(ctx context.Context, fs *flag.FlagSet) { + f.RegisterOnce(func() { + f.DatacenterFlag.Register(ctx, fs) + + env := "GOVC_DATASTORE_CLUSTER" + value := os.Getenv(env) + usage := fmt.Sprintf("Datastore cluster [%s]", env) + fs.StringVar(&f.Name, "datastore-cluster", value, usage) + }) +} + +func (f *StoragePodFlag) Process(ctx context.Context) error { + return f.DatacenterFlag.Process(ctx) +} + +func (f *StoragePodFlag) Isset() bool { + return f.Name != "" +} + +func (f *StoragePodFlag) StoragePod() (*object.StoragePod, error) { + ctx := context.TODO() + if f.sp != nil { + return f.sp, nil + } + + finder, err := f.Finder() + if err != nil { + return nil, err + } + + if f.Isset() { + f.sp, err = finder.DatastoreCluster(ctx, f.Name) + if err != nil { + return nil, err + } + } else { + f.sp, err = finder.DefaultDatastoreCluster(ctx) + if err != nil { + return nil, err + } + } + + return f.sp, nil +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/version.go b/vendor/github.com/vmware/govmomi/govc/flags/version.go new file mode 100644 index 0000000000..72d0772b03 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/version.go @@ -0,0 +1,71 @@ +/* +Copyright (c) 2014-2020 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "strconv" + "strings" +) + +var ( + BuildVersion = "v0.0.0" // govc-test requires an (arbitrary) version set + BuildCommit string + BuildDate string +) + +type version []int + +func ParseVersion(s string) (version, error) { + // remove any trailing "v" version identifier + s = strings.TrimPrefix(s, "v") + v := make(version, 0) + + ds := strings.Split(s, "-") + ps := strings.Split(ds[0], ".") + for _, p := range ps { + i, err := strconv.Atoi(p) + if err != nil { + return nil, err + } + + v = append(v, i) + } + + return v, nil +} + +func (v version) Lte(u version) bool { + lv := len(v) + lu := len(u) + + for i := 0; i < lv; i++ { + // Everything up to here has been equal and v has more elements than u. + if i >= lu { + return false + } + + // Move to next digit if equal. + if v[i] == u[i] { + continue + } + + return v[i] < u[i] + } + + // Equal. + return true +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/virtual_app.go b/vendor/github.com/vmware/govmomi/govc/flags/virtual_app.go new file mode 100644 index 0000000000..88a0b9cbfe --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/virtual_app.go @@ -0,0 +1,106 @@ +/* +Copyright (c) 2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + "fmt" + "os" + + "github.com/vmware/govmomi/object" +) + +type VirtualAppFlag struct { + common + + *DatacenterFlag + *SearchFlag + + name string + app *object.VirtualApp +} + +var virtualAppFlagKey = flagKey("virtualApp") + +func NewVirtualAppFlag(ctx context.Context) (*VirtualAppFlag, context.Context) { + if v := ctx.Value(virtualAppFlagKey); v != nil { + return v.(*VirtualAppFlag), ctx + } + + v := &VirtualAppFlag{} + v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) + v.SearchFlag, ctx = NewSearchFlag(ctx, SearchVirtualApps) + ctx = context.WithValue(ctx, virtualAppFlagKey, v) + return v, ctx +} + +func (flag *VirtualAppFlag) Register(ctx context.Context, f *flag.FlagSet) { + flag.RegisterOnce(func() { + flag.DatacenterFlag.Register(ctx, f) + flag.SearchFlag.Register(ctx, f) + + env := "GOVC_VAPP" + value := os.Getenv(env) + usage := fmt.Sprintf("Virtual App [%s]", env) + f.StringVar(&flag.name, "vapp", value, usage) + }) +} + +func (flag *VirtualAppFlag) Process(ctx context.Context) error { + return flag.ProcessOnce(func() error { + if err := flag.DatacenterFlag.Process(ctx); err != nil { + return err + } + if err := flag.SearchFlag.Process(ctx); err != nil { + return err + } + return nil + }) +} + +func (flag *VirtualAppFlag) VirtualApp() (*object.VirtualApp, error) { + ctx := context.TODO() + + if flag.app != nil { + return flag.app, nil + } + + // Use search flags if specified. + if flag.SearchFlag.IsSet() { + app, err := flag.SearchFlag.VirtualApp() + if err != nil { + return nil, err + } + + flag.app = app + return flag.app, nil + } + + // Never look for a default virtual app. + if flag.name == "" { + return nil, nil + } + + finder, err := flag.Finder() + if err != nil { + return nil, err + } + + flag.app, err = finder.VirtualApp(ctx, flag.name) + return flag.app, err +} diff --git a/vendor/github.com/vmware/govmomi/govc/flags/virtual_machine.go b/vendor/github.com/vmware/govmomi/govc/flags/virtual_machine.go new file mode 100644 index 0000000000..e0b1acae8c --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/flags/virtual_machine.go @@ -0,0 +1,112 @@ +/* +Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package flags + +import ( + "context" + "flag" + "fmt" + "os" + + "github.com/vmware/govmomi/object" +) + +type VirtualMachineFlag struct { + common + + *ClientFlag + *DatacenterFlag + *SearchFlag + + name string + vm *object.VirtualMachine +} + +var virtualMachineFlagKey = flagKey("virtualMachine") + +func NewVirtualMachineFlag(ctx context.Context) (*VirtualMachineFlag, context.Context) { + if v := ctx.Value(virtualMachineFlagKey); v != nil { + return v.(*VirtualMachineFlag), ctx + } + + v := &VirtualMachineFlag{} + v.ClientFlag, ctx = NewClientFlag(ctx) + v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) + v.SearchFlag, ctx = NewSearchFlag(ctx, SearchVirtualMachines) + ctx = context.WithValue(ctx, virtualMachineFlagKey, v) + return v, ctx +} + +func (flag *VirtualMachineFlag) Register(ctx context.Context, f *flag.FlagSet) { + flag.RegisterOnce(func() { + flag.ClientFlag.Register(ctx, f) + flag.DatacenterFlag.Register(ctx, f) + flag.SearchFlag.Register(ctx, f) + + env := "GOVC_VM" + value := os.Getenv(env) + usage := fmt.Sprintf("Virtual machine [%s]", env) + f.StringVar(&flag.name, "vm", value, usage) + }) +} + +func (flag *VirtualMachineFlag) Process(ctx context.Context) error { + return flag.ProcessOnce(func() error { + if err := flag.ClientFlag.Process(ctx); err != nil { + return err + } + if err := flag.DatacenterFlag.Process(ctx); err != nil { + return err + } + if err := flag.SearchFlag.Process(ctx); err != nil { + return err + } + return nil + }) +} + +func (flag *VirtualMachineFlag) VirtualMachine() (*object.VirtualMachine, error) { + ctx := context.TODO() + + if flag.vm != nil { + return flag.vm, nil + } + + // Use search flags if specified. + if flag.SearchFlag.IsSet() { + vm, err := flag.SearchFlag.VirtualMachine() + if err != nil { + return nil, err + } + + flag.vm = vm + return flag.vm, nil + } + + // Never look for a default virtual machine. + if flag.name == "" { + return nil, nil + } + + finder, err := flag.Finder() + if err != nil { + return nil, err + } + + flag.vm, err = finder.VirtualMachine(ctx, flag.name) + return flag.vm, err +} diff --git a/vendor/github.com/vmware/govmomi/govc/importx/archive.go b/vendor/github.com/vmware/govmomi/govc/importx/archive.go new file mode 100644 index 0000000000..fef36abdcb --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/importx/archive.go @@ -0,0 +1,205 @@ +/* +Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package importx + +import ( + "archive/tar" + "bytes" + "context" + "errors" + "flag" + "fmt" + "io" + "net/url" + "os" + "path" + "path/filepath" + "strings" + + "github.com/vmware/govmomi/ovf" + "github.com/vmware/govmomi/vapi/library" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/soap" +) + +// ArchiveFlag doesn't register any flags; +// only encapsulates some common archive related functionality. +type ArchiveFlag struct { + Archive + + manifest map[string]*library.Checksum +} + +func newArchiveFlag(ctx context.Context) (*ArchiveFlag, context.Context) { + return &ArchiveFlag{}, ctx +} + +func (f *ArchiveFlag) Register(ctx context.Context, fs *flag.FlagSet) { +} + +func (f *ArchiveFlag) Process(ctx context.Context) error { + return nil +} + +func (f *ArchiveFlag) ReadOvf(fpath string) ([]byte, error) { + r, _, err := f.Open(fpath) + if err != nil { + return nil, err + } + defer r.Close() + + return io.ReadAll(r) +} + +func (f *ArchiveFlag) ReadEnvelope(data []byte) (*ovf.Envelope, error) { + e, err := ovf.Unmarshal(bytes.NewReader(data)) + if err != nil { + return nil, fmt.Errorf("failed to parse ovf: %s", err) + } + + return e, nil +} + +func (f *ArchiveFlag) readManifest(fpath string) error { + base := filepath.Base(fpath) + ext := filepath.Ext(base) + mfName := strings.Replace(base, ext, ".mf", 1) + + mf, _, err := f.Open(mfName) + if err != nil { + msg := fmt.Sprintf("manifest %q: %s", mf, err) + fmt.Fprintln(os.Stderr, msg) + return errors.New(msg) + } + f.manifest, err = library.ReadManifest(mf) + _ = mf.Close() + return err +} + +type Archive interface { + Open(string) (io.ReadCloser, int64, error) +} + +type TapeArchive struct { + Path string + Opener +} + +type TapeArchiveEntry struct { + io.Reader + f io.Closer + + Name string +} + +func (t *TapeArchiveEntry) Close() error { + return t.f.Close() +} + +func (t *TapeArchive) Open(name string) (io.ReadCloser, int64, error) { + f, _, err := t.OpenFile(t.Path) + if err != nil { + return nil, 0, err + } + + r := tar.NewReader(f) + + for { + h, err := r.Next() + if err == io.EOF { + break + } + if err != nil { + return nil, 0, err + } + + matched, err := path.Match(name, path.Base(h.Name)) + if err != nil { + return nil, 0, err + } + + if matched { + return &TapeArchiveEntry{r, f, h.Name}, h.Size, nil + } + } + + _ = f.Close() + + return nil, 0, os.ErrNotExist +} + +type FileArchive struct { + Path string + Opener +} + +func (t *FileArchive) Open(name string) (io.ReadCloser, int64, error) { + fpath := name + if name != t.Path { + index := strings.LastIndex(t.Path, "/") + if index != -1 { + fpath = t.Path[:index] + "/" + name + } + } + + return t.OpenFile(fpath) +} + +type Opener struct { + *vim25.Client +} + +func isRemotePath(path string) bool { + if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") { + return true + } + return false +} + +func (o Opener) OpenLocal(path string) (io.ReadCloser, int64, error) { + f, err := os.Open(filepath.Clean(path)) + if err != nil { + return nil, 0, err + } + + s, err := f.Stat() + if err != nil { + return nil, 0, err + } + + return f, s.Size(), nil +} + +func (o Opener) OpenFile(path string) (io.ReadCloser, int64, error) { + if isRemotePath(path) { + return o.OpenRemote(path) + } + return o.OpenLocal(path) +} + +func (o Opener) OpenRemote(link string) (io.ReadCloser, int64, error) { + if o.Client == nil { + return nil, 0, errors.New("remote path not supported") + } + + u, err := url.Parse(link) + if err != nil { + return nil, 0, err + } + + return o.Download(context.Background(), u, &soap.DefaultDownload) +} diff --git a/vendor/github.com/vmware/govmomi/govc/importx/importable.go b/vendor/github.com/vmware/govmomi/govc/importx/importable.go new file mode 100644 index 0000000000..14e31670b0 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/importx/importable.go @@ -0,0 +1,59 @@ +/* +Copyright (c) 2014 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package importx + +import ( + "fmt" + "path" +) + +type importable struct { + localPath string + remotePath string +} + +func (i importable) Ext() string { + return path.Ext(i.localPath) +} + +func (i importable) Base() string { + return path.Base(i.localPath) +} + +func (i importable) BaseClean() string { + b := i.Base() + e := i.Ext() + return b[:len(b)-len(e)] +} + +func (i importable) RemoteSrcVMDK() string { + file := fmt.Sprintf("%s-src.vmdk", i.BaseClean()) + return i.toRemotePath(file) +} + +func (i importable) RemoteDstVMDK() string { + file := fmt.Sprintf("%s.vmdk", i.BaseClean()) + return i.toRemotePath(file) +} + +func (i importable) toRemotePath(p string) string { + if i.remotePath == "" { + return p + } + + return path.Join(i.remotePath, p) +} diff --git a/vendor/github.com/vmware/govmomi/govc/importx/options.go b/vendor/github.com/vmware/govmomi/govc/importx/options.go new file mode 100644 index 0000000000..3d8190ec02 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/importx/options.go @@ -0,0 +1,236 @@ +/* +Copyright (c) 2015-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package importx + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "os" + + "github.com/vmware/govmomi/govc/flags" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/ovf" + "github.com/vmware/govmomi/vim25/types" +) + +type KeyValue struct { + Key string + Value string +} + +// case insensitive for Key + Value +func (kv *KeyValue) UnmarshalJSON(b []byte) error { + e := struct { + types.KeyValue + Key *string + Value *string + }{ + types.KeyValue{}, &kv.Key, &kv.Value, + } + + err := json.Unmarshal(b, &e) + if err != nil { + return err + } + + if kv.Key == "" { + kv.Key = e.KeyValue.Key // "key" + } + + if kv.Value == "" { + kv.Value = e.KeyValue.Value // "value" + } + + return nil +} + +type Property struct { + KeyValue + Spec *ovf.Property `json:",omitempty"` +} + +type Network struct { + Name string + Network string +} + +type Options struct { + AllDeploymentOptions []string `json:",omitempty"` + Deployment string `json:",omitempty"` + + AllDiskProvisioningOptions []string `json:",omitempty"` + DiskProvisioning string + + AllIPAllocationPolicyOptions []string `json:",omitempty"` + IPAllocationPolicy string + + AllIPProtocolOptions []string `json:",omitempty"` + IPProtocol string + + PropertyMapping []Property `json:",omitempty"` + + NetworkMapping []Network `json:",omitempty"` + + Annotation string `json:",omitempty"` + + MarkAsTemplate bool + PowerOn bool + InjectOvfEnv bool + WaitForIP bool + Name *string +} + +type OptionsFlag struct { + Options Options + + path string +} + +func newOptionsFlag(ctx context.Context) (*OptionsFlag, context.Context) { + return &OptionsFlag{}, ctx +} + +func (flag *OptionsFlag) Register(ctx context.Context, f *flag.FlagSet) { + f.StringVar(&flag.path, "options", "", "Options spec file path for VM deployment") +} + +func (flag *OptionsFlag) Process(ctx context.Context) error { + if len(flag.path) == 0 { + return nil + } + + var err error + in := os.Stdin + + if flag.path != "-" { + in, err = os.Open(flag.path) + if err != nil { + return err + } + defer in.Close() + } + + return json.NewDecoder(in).Decode(&flag.Options) +} + +func (flag *OptionsFlag) powerOn(vm *object.VirtualMachine, out *flags.OutputFlag) error { + if !flag.Options.PowerOn || flag.Options.MarkAsTemplate { + return nil + } + + out.Log("Powering on VM...\n") + + task, err := vm.PowerOn(context.Background()) + if err != nil { + return err + } + + return task.Wait(context.Background()) +} + +func (flag *OptionsFlag) markAsTemplate(vm *object.VirtualMachine, out *flags.OutputFlag) error { + if !flag.Options.MarkAsTemplate { + return nil + } + + out.Log("Marking VM as template...\n") + + return vm.MarkAsTemplate(context.Background()) +} + +func (flag *OptionsFlag) injectOvfEnv(vm *object.VirtualMachine, out *flags.OutputFlag) error { + if !flag.Options.InjectOvfEnv { + return nil + } + + out.Log("Injecting OVF environment...\n") + + var opts []types.BaseOptionValue + + a := vm.Client().ServiceContent.About + + // build up Environment in order to marshal to xml + var props []ovf.EnvProperty + for _, p := range flag.Options.PropertyMapping { + props = append(props, ovf.EnvProperty{ + Key: p.Key, + Value: p.Value, + }) + } + + env := ovf.Env{ + EsxID: vm.Reference().Value, + Platform: &ovf.PlatformSection{ + Kind: a.Name, + Version: a.Version, + Vendor: a.Vendor, + Locale: "US", + }, + Property: &ovf.PropertySection{ + Properties: props, + }, + } + + opts = append(opts, &types.OptionValue{ + Key: "guestinfo.ovfEnv", + Value: env.MarshalManual(), + }) + + task, err := vm.Reconfigure(context.Background(), types.VirtualMachineConfigSpec{ + ExtraConfig: opts, + }) + + if err != nil { + return err + } + + return task.Wait(context.Background()) +} + +func (flag *OptionsFlag) waitForIP(vm *object.VirtualMachine, out *flags.OutputFlag) error { + if !flag.Options.PowerOn || !flag.Options.WaitForIP || flag.Options.MarkAsTemplate { + return nil + } + + out.Log("Waiting for IP address...\n") + ip, err := vm.WaitForIP(context.Background()) + if err != nil { + return err + } + + out.Log(fmt.Sprintf("Received IP address: %s\n", ip)) + return nil +} + +func (flag *OptionsFlag) Deploy(vm *object.VirtualMachine, out *flags.OutputFlag) error { + deploy := []func(*object.VirtualMachine, *flags.OutputFlag) error{ + flag.injectOvfEnv, + flag.markAsTemplate, + flag.powerOn, + flag.waitForIP, + } + + for _, step := range deploy { + if err := step(vm, out); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/vmware/govmomi/govc/importx/ova.go b/vendor/github.com/vmware/govmomi/govc/importx/ova.go new file mode 100644 index 0000000000..343cdcddab --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/importx/ova.go @@ -0,0 +1,63 @@ +/* +Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package importx + +import ( + "context" + "flag" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25/types" +) + +type ova struct { + *ovfx +} + +func init() { + cli.Register("import.ova", &ova{&ovfx{}}) +} + +func (cmd *ova) Usage() string { + return "PATH_TO_OVA" +} + +func (cmd *ova) Run(ctx context.Context, f *flag.FlagSet) error { + fpath, err := cmd.Prepare(f) + if err != nil { + return err + } + + archive := &TapeArchive{Path: fpath} + archive.Client = cmd.Client + + cmd.Archive = archive + + moref, err := cmd.Import(fpath) + if err != nil { + return err + } + + vm := object.NewVirtualMachine(cmd.Client, *moref) + return cmd.Deploy(vm, cmd.OutputFlag) +} + +func (cmd *ova) Import(fpath string) (*types.ManagedObjectReference, error) { + ovf := "*.ovf" + return cmd.ovfx.Import(ovf) +} diff --git a/vendor/github.com/vmware/govmomi/govc/importx/ovf.go b/vendor/github.com/vmware/govmomi/govc/importx/ovf.go new file mode 100644 index 0000000000..e1765f4cb1 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/importx/ovf.go @@ -0,0 +1,451 @@ +/* +Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package importx + +import ( + "bytes" + "context" + "errors" + "flag" + "fmt" + "path" + "strings" + + "github.com/vmware/govmomi/find" + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" + "github.com/vmware/govmomi/nfc" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/ovf" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +type ovfx struct { + *flags.DatastoreFlag + *flags.HostSystemFlag + *flags.OutputFlag + *flags.ResourcePoolFlag + *flags.FolderFlag + + *ArchiveFlag + *OptionsFlag + + Name string + VerifyManifest bool + Hidden bool + + Client *vim25.Client + Datacenter *object.Datacenter + Datastore *object.Datastore + ResourcePool *object.ResourcePool +} + +func init() { + cli.Register("import.ovf", &ovfx{}) +} + +func (cmd *ovfx) Register(ctx context.Context, f *flag.FlagSet) { + cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx) + cmd.DatastoreFlag.Register(ctx, f) + cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx) + cmd.HostSystemFlag.Register(ctx, f) + cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx) + cmd.OutputFlag.Register(ctx, f) + cmd.ResourcePoolFlag, ctx = flags.NewResourcePoolFlag(ctx) + cmd.ResourcePoolFlag.Register(ctx, f) + cmd.FolderFlag, ctx = flags.NewFolderFlag(ctx) + cmd.FolderFlag.Register(ctx, f) + + cmd.ArchiveFlag, ctx = newArchiveFlag(ctx) + cmd.ArchiveFlag.Register(ctx, f) + cmd.OptionsFlag, ctx = newOptionsFlag(ctx) + cmd.OptionsFlag.Register(ctx, f) + + f.StringVar(&cmd.Name, "name", "", "Name to use for new entity") + f.BoolVar(&cmd.VerifyManifest, "m", false, "Verify checksum of uploaded files against manifest (.mf)") + f.BoolVar(&cmd.Hidden, "hidden", false, "Enable hidden properties") +} + +func (cmd *ovfx) Process(ctx context.Context) error { + if err := cmd.DatastoreFlag.Process(ctx); err != nil { + return err + } + if err := cmd.HostSystemFlag.Process(ctx); err != nil { + return err + } + if err := cmd.OutputFlag.Process(ctx); err != nil { + return err + } + if err := cmd.ResourcePoolFlag.Process(ctx); err != nil { + return err + } + if err := cmd.ArchiveFlag.Process(ctx); err != nil { + return err + } + if err := cmd.OptionsFlag.Process(ctx); err != nil { + return err + } + if err := cmd.FolderFlag.Process(ctx); err != nil { + return err + } + return nil +} + +func (cmd *ovfx) Usage() string { + return "PATH_TO_OVF" +} + +func (cmd *ovfx) Run(ctx context.Context, f *flag.FlagSet) error { + fpath, err := cmd.Prepare(f) + if err != nil { + return err + } + + archive := &FileArchive{Path: fpath} + archive.Client = cmd.Client + + cmd.Archive = archive + + moref, err := cmd.Import(fpath) + if err != nil { + return err + } + + vm := object.NewVirtualMachine(cmd.Client, *moref) + return cmd.Deploy(vm, cmd.OutputFlag) +} + +func (cmd *ovfx) Prepare(f *flag.FlagSet) (string, error) { + var err error + + args := f.Args() + if len(args) != 1 { + return "", errors.New("no file specified") + } + + cmd.Client, err = cmd.DatastoreFlag.Client() + if err != nil { + return "", err + } + + cmd.Datacenter, err = cmd.DatastoreFlag.Datacenter() + if err != nil { + return "", err + } + + cmd.Datastore, err = cmd.DatastoreFlag.Datastore() + if err != nil { + return "", err + } + + cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePoolIfSpecified() + if err != nil { + return "", err + } + + return f.Arg(0), nil +} + +func (cmd *ovfx) Map(op []Property) (p []types.KeyValue) { + for _, v := range op { + p = append(p, types.KeyValue{ + Key: v.Key, + Value: v.Value, + }) + } + + return +} + +func (cmd *ovfx) validateNetwork(e *ovf.Envelope, net Network) { + var names []string + + if e.Network != nil { + for _, n := range e.Network.Networks { + if n.Name == net.Name { + return + } + names = append(names, n.Name) + } + } + + _, _ = cmd.Log(fmt.Sprintf("Warning: invalid NetworkMapping.Name=%q, valid names=%s\n", net.Name, names)) +} + +func (cmd *ovfx) NetworkMap(e *ovf.Envelope) ([]types.OvfNetworkMapping, error) { + ctx := context.TODO() + finder, err := cmd.DatastoreFlag.Finder() + if err != nil { + return nil, err + } + + var nmap []types.OvfNetworkMapping + for _, m := range cmd.Options.NetworkMapping { + if m.Network == "" { + continue // Not set, let vSphere choose the default network + } + cmd.validateNetwork(e, m) + + var ref types.ManagedObjectReference + + net, err := finder.Network(ctx, m.Network) + if err != nil { + switch err.(type) { + case *find.NotFoundError: + if !ref.FromString(m.Network) { + return nil, err + } // else this is a raw MO ref + default: + return nil, err + } + } else { + ref = net.Reference() + } + + nmap = append(nmap, types.OvfNetworkMapping{ + Name: m.Name, + Network: ref, + }) + } + + return nmap, err +} + +func (cmd *ovfx) Import(fpath string) (*types.ManagedObjectReference, error) { + ctx := context.TODO() + + o, err := cmd.ReadOvf(fpath) + if err != nil { + return nil, err + } + + e, err := cmd.ReadEnvelope(o) + if err != nil { + return nil, fmt.Errorf("failed to parse ovf: %s", err) + } + + name := "Govc Virtual Appliance" + if e.VirtualSystem != nil { + name = e.VirtualSystem.ID + if e.VirtualSystem.Name != nil { + name = *e.VirtualSystem.Name + } + + if cmd.Hidden { + // TODO: userConfigurable is optional and defaults to false, so we should *add* userConfigurable=true + // if not set for a Property. But, there'd be a bunch more work involved to preserve other data in doing + // a complete xml.Marshal of the .ovf + o = bytes.ReplaceAll(o, []byte(`userConfigurable="false"`), []byte(`userConfigurable="true"`)) + } + } + + // Override name from options if specified + if cmd.Options.Name != nil { + name = *cmd.Options.Name + } + + // Override name from arguments if specified + if cmd.Name != "" { + name = cmd.Name + } + + nmap, err := cmd.NetworkMap(e) + if err != nil { + return nil, err + } + + cisp := types.OvfCreateImportSpecParams{ + DiskProvisioning: cmd.Options.DiskProvisioning, + EntityName: name, + IpAllocationPolicy: cmd.Options.IPAllocationPolicy, + IpProtocol: cmd.Options.IPProtocol, + OvfManagerCommonParams: types.OvfManagerCommonParams{ + DeploymentOption: cmd.Options.Deployment, + Locale: "US"}, + PropertyMapping: cmd.Map(cmd.Options.PropertyMapping), + NetworkMapping: nmap, + } + + host, err := cmd.HostSystemIfSpecified() + if err != nil { + return nil, err + } + + if cmd.ResourcePool == nil { + if host == nil { + cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool() + } else { + cmd.ResourcePool, err = host.ResourcePool(ctx) + } + if err != nil { + return nil, err + } + } + + m := ovf.NewManager(cmd.Client) + spec, err := m.CreateImportSpec(ctx, string(o), cmd.ResourcePool, cmd.Datastore, cisp) + if err != nil { + return nil, err + } + if spec.Error != nil { + return nil, errors.New(spec.Error[0].LocalizedMessage) + } + if spec.Warning != nil { + for _, w := range spec.Warning { + _, _ = cmd.Log(fmt.Sprintf("Warning: %s\n", w.LocalizedMessage)) + } + } + + if cmd.Options.Annotation != "" { + switch s := spec.ImportSpec.(type) { + case *types.VirtualMachineImportSpec: + s.ConfigSpec.Annotation = cmd.Options.Annotation + case *types.VirtualAppImportSpec: + s.VAppConfigSpec.Annotation = cmd.Options.Annotation + } + } + + var folder *object.Folder + // The folder argument must not be set on a VM in a vApp, otherwise causes + // InvalidArgument fault: A specified parameter was not correct: pool + if cmd.ResourcePool.Reference().Type != "VirtualApp" { + folder, err = cmd.FolderOrDefault("vm") + if err != nil { + return nil, err + } + } + + if cmd.VerifyManifest { + err = cmd.readManifest(fpath) + if err != nil { + return nil, err + } + } + + lease, err := cmd.ResourcePool.ImportVApp(ctx, spec.ImportSpec, folder, host) + if err != nil { + return nil, err + } + + info, err := lease.Wait(ctx, spec.FileItem) + if err != nil { + return nil, err + } + + u := lease.StartUpdater(ctx, info) + defer u.Done() + + for _, i := range info.Items { + err = cmd.Upload(ctx, lease, i) + if err != nil { + return nil, err + } + } + + return &info.Entity, lease.Complete(ctx) +} + +func (cmd *ovfx) Upload(ctx context.Context, lease *nfc.Lease, item nfc.FileItem) error { + file := item.Path + + f, size, err := cmd.Open(file) + if err != nil { + return err + } + defer f.Close() + + logger := cmd.ProgressLogger(fmt.Sprintf("Uploading %s... ", path.Base(file))) + defer logger.Wait() + + opts := soap.Upload{ + ContentLength: size, + Progress: logger, + } + + err = lease.Upload(ctx, item, f, opts) + if err != nil { + return err + } + + if cmd.VerifyManifest { + mapImportKeyToKey := func(urls []types.HttpNfcLeaseDeviceUrl, importKey string) string { + for _, url := range urls { + if url.ImportKey == importKey { + return url.Key + } + } + return "" + } + leaseInfo, err := lease.Wait(ctx, nil) + if err != nil { + return err + } + return cmd.validateChecksum(ctx, lease, file, mapImportKeyToKey(leaseInfo.DeviceUrl, item.DeviceId)) + } + return nil +} + +func (cmd *ovfx) validateChecksum(ctx context.Context, lease *nfc.Lease, file string, key string) error { + sum, found := cmd.manifest[file] + if !found { + msg := fmt.Sprintf("missing checksum for %v in manifest file", file) + return errors.New(msg) + } + // Perform the checksum match eagerly, after each file upload, instead + // of after uploading all the files, to provide fail-fast behavior. + // (Trade-off here is multiple GetManifest() API calls to the server.) + manifests, err := lease.GetManifest(ctx) + if err != nil { + return err + } + for _, m := range manifests { + if m.Key == key { + // Compare server-side computed checksum of uploaded file + // against the client's manifest entry (assuming client's + // manifest has correct checksums - client doesn't compute + // checksum of the file before uploading). + + // Try matching sha1 first (newer versions have moved to sha256). + if strings.ToUpper(sum.Algorithm) == "SHA1" { + if sum.Checksum != m.Sha1 { + msg := fmt.Sprintf("manifest checksum %v mismatch with uploaded checksum %v for file %v", + sum.Checksum, m.Sha1, file) + return errors.New(msg) + } + // Uploaded file checksum computed by server matches with local manifest entry. + return nil + } + // If not sha1, check for other types (in a separate field). + if !strings.EqualFold(sum.Algorithm, m.ChecksumType) { + msg := fmt.Sprintf("manifest checksum type %v mismatch with uploaded checksum type %v for file %v", + sum.Algorithm, m.ChecksumType, file) + return errors.New(msg) + } + if !strings.EqualFold(sum.Checksum, m.Checksum) { + msg := fmt.Sprintf("manifest checksum %v mismatch with uploaded checksum %v for file %v", + sum.Checksum, m.Checksum, file) + return errors.New(msg) + } + // Uploaded file checksum computed by server matches with local manifest entry. + return nil + } + } + msg := fmt.Sprintf("missing manifest entry on server for uploaded file %v (key %v), manifests=%#v", file, key, manifests) + return errors.New(msg) +} diff --git a/vendor/github.com/vmware/govmomi/govc/importx/spec.go b/vendor/github.com/vmware/govmomi/govc/importx/spec.go new file mode 100644 index 0000000000..09763e2b11 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/importx/spec.go @@ -0,0 +1,250 @@ +/* +Copyright (c) 2015-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package importx + +import ( + "context" + "flag" + "fmt" + "io" + "path" + "strings" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" + "github.com/vmware/govmomi/ovf" + "github.com/vmware/govmomi/vim25/types" +) + +var ( + allDiskProvisioningOptions = []string{ + string(types.OvfCreateImportSpecParamsDiskProvisioningTypeFlat), + string(types.OvfCreateImportSpecParamsDiskProvisioningTypeMonolithicSparse), + string(types.OvfCreateImportSpecParamsDiskProvisioningTypeMonolithicFlat), + string(types.OvfCreateImportSpecParamsDiskProvisioningTypeTwoGbMaxExtentSparse), + string(types.OvfCreateImportSpecParamsDiskProvisioningTypeTwoGbMaxExtentFlat), + string(types.OvfCreateImportSpecParamsDiskProvisioningTypeThin), + string(types.OvfCreateImportSpecParamsDiskProvisioningTypeThick), + string(types.OvfCreateImportSpecParamsDiskProvisioningTypeSeSparse), + string(types.OvfCreateImportSpecParamsDiskProvisioningTypeEagerZeroedThick), + string(types.OvfCreateImportSpecParamsDiskProvisioningTypeSparse), + } + allIPAllocationPolicyOptions = []string{ + string(types.VAppIPAssignmentInfoIpAllocationPolicyDhcpPolicy), + string(types.VAppIPAssignmentInfoIpAllocationPolicyTransientPolicy), + string(types.VAppIPAssignmentInfoIpAllocationPolicyFixedPolicy), + string(types.VAppIPAssignmentInfoIpAllocationPolicyFixedAllocatedPolicy), + } + allIPProtocolOptions = []string{ + string(types.VAppIPAssignmentInfoProtocolsIPv4), + string(types.VAppIPAssignmentInfoProtocolsIPv6), + } +) + +type spec struct { + *ArchiveFlag + *flags.ClientFlag + *flags.OutputFlag + + hidden bool +} + +func init() { + cli.Register("import.spec", &spec{}) +} + +func (cmd *spec) Register(ctx context.Context, f *flag.FlagSet) { + cmd.ArchiveFlag, ctx = newArchiveFlag(ctx) + cmd.ArchiveFlag.Register(ctx, f) + cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) + cmd.ClientFlag.Register(ctx, f) + + cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx) + cmd.OutputFlag.Register(ctx, f) + + f.BoolVar(&cmd.hidden, "hidden", false, "Enable hidden properties") +} + +func (cmd *spec) Process(ctx context.Context) error { + if err := cmd.ArchiveFlag.Process(ctx); err != nil { + return err + } + if err := cmd.ClientFlag.Process(ctx); err != nil { + return err + } + return cmd.OutputFlag.Process(ctx) +} + +func (cmd *spec) Usage() string { + return "PATH_TO_OVF_OR_OVA" +} + +func (cmd *spec) Run(ctx context.Context, f *flag.FlagSet) error { + fpath := "" + args := f.Args() + if len(args) == 1 { + fpath = f.Arg(0) + } + + if len(fpath) > 0 { + switch path.Ext(fpath) { + case ".ovf": + cmd.Archive = &FileArchive{Path: fpath} + case "", ".ova": + cmd.Archive = &TapeArchive{Path: fpath} + fpath = "*.ovf" + default: + return fmt.Errorf("invalid file extension %s", path.Ext(fpath)) + } + + if isRemotePath(f.Arg(0)) { + client, err := cmd.Client() + if err != nil { + return err + } + switch archive := cmd.Archive.(type) { + case *FileArchive: + archive.Client = client + case *TapeArchive: + archive.Client = client + } + } + } + + env, err := cmd.Spec(fpath) + if err != nil { + return err + } + + if !cmd.All() { + cmd.JSON = true + } + return cmd.WriteResult(&specResult{env}) +} + +type specResult struct { + *Options +} + +func (*specResult) Write(w io.Writer) error { + return nil +} + +func (cmd *spec) Map(e *ovf.Envelope) (res []Property) { + if e == nil || e.VirtualSystem == nil { + return nil + } + + for _, p := range e.VirtualSystem.Product { + for i, v := range p.Property { + if v.UserConfigurable == nil { + continue + } + if !*v.UserConfigurable && !cmd.hidden { + continue + } + + d := "" + if v.Default != nil { + d = *v.Default + } + + // vSphere only accept True/False as boolean values for some reason + if v.Type == "boolean" { + d = strings.Title(d) + } + + np := Property{KeyValue: KeyValue{Key: p.Key(v), Value: d}} + + if cmd.Verbose() { + np.Spec = &p.Property[i] + } + + res = append(res, np) + } + } + + return +} + +func (cmd *spec) Spec(fpath string) (*Options, error) { + e := &ovf.Envelope{} + if fpath != "" { + d, err := cmd.ReadOvf(fpath) + if err != nil { + return nil, err + } + + if e, err = cmd.ReadEnvelope(d); err != nil { + return nil, err + } + } + + var deploymentOptions []string + if e.DeploymentOption != nil && e.DeploymentOption.Configuration != nil { + // add default first + for _, c := range e.DeploymentOption.Configuration { + if c.Default != nil && *c.Default { + deploymentOptions = append(deploymentOptions, c.ID) + } + } + + for _, c := range e.DeploymentOption.Configuration { + if c.Default == nil || !*c.Default { + deploymentOptions = append(deploymentOptions, c.ID) + } + } + } + + o := Options{ + DiskProvisioning: allDiskProvisioningOptions[0], + IPAllocationPolicy: allIPAllocationPolicyOptions[0], + IPProtocol: allIPProtocolOptions[0], + MarkAsTemplate: false, + PowerOn: false, + WaitForIP: false, + InjectOvfEnv: false, + PropertyMapping: cmd.Map(e), + } + + if deploymentOptions != nil { + o.Deployment = deploymentOptions[0] + } + + if e.VirtualSystem != nil && e.VirtualSystem.Annotation != nil { + for _, a := range e.VirtualSystem.Annotation { + o.Annotation += a.Annotation + } + } + + if e.Network != nil { + for _, net := range e.Network.Networks { + o.NetworkMapping = append(o.NetworkMapping, Network{net.Name, ""}) + } + } + + if cmd.Verbose() { + if deploymentOptions != nil { + o.AllDeploymentOptions = deploymentOptions + } + o.AllDiskProvisioningOptions = allDiskProvisioningOptions + o.AllIPAllocationPolicyOptions = allIPAllocationPolicyOptions + o.AllIPProtocolOptions = allIPProtocolOptions + } + + return &o, nil +} diff --git a/vendor/github.com/vmware/govmomi/govc/importx/vmdk.go b/vendor/github.com/vmware/govmomi/govc/importx/vmdk.go new file mode 100644 index 0000000000..6e0ac5f992 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/govc/importx/vmdk.go @@ -0,0 +1,132 @@ +/* +Copyright (c) 2014-2017 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package importx + +import ( + "context" + "errors" + "flag" + "fmt" + "path" + + "github.com/vmware/govmomi/govc/cli" + "github.com/vmware/govmomi/govc/flags" + "github.com/vmware/govmomi/vmdk" +) + +type disk struct { + *flags.DatastoreFlag + *flags.ResourcePoolFlag + *flags.FolderFlag + *flags.OutputFlag + + force bool +} + +func init() { + cli.Register("import.vmdk", &disk{}) +} + +func (cmd *disk) Register(ctx context.Context, f *flag.FlagSet) { + cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx) + cmd.DatastoreFlag.Register(ctx, f) + cmd.ResourcePoolFlag, ctx = flags.NewResourcePoolFlag(ctx) + cmd.ResourcePoolFlag.Register(ctx, f) + cmd.FolderFlag, ctx = flags.NewFolderFlag(ctx) + cmd.FolderFlag.Register(ctx, f) + cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx) + cmd.OutputFlag.Register(ctx, f) + + f.BoolVar(&cmd.force, "force", false, "Overwrite existing disk") +} + +func (cmd *disk) Process(ctx context.Context) error { + if err := cmd.DatastoreFlag.Process(ctx); err != nil { + return err + } + if err := cmd.ResourcePoolFlag.Process(ctx); err != nil { + return err + } + if err := cmd.FolderFlag.Process(ctx); err != nil { + return err + } + if err := cmd.OutputFlag.Process(ctx); err != nil { + return err + } + return nil +} + +func (cmd *disk) Usage() string { + return "PATH_TO_VMDK [REMOTE_DIRECTORY]" +} + +func (cmd *disk) Run(ctx context.Context, f *flag.FlagSet) error { + args := f.Args() + if len(args) < 1 { + return errors.New("no file to import") + } + + src := f.Arg(0) + + c, err := cmd.DatastoreFlag.Client() + if err != nil { + return err + } + + dc, err := cmd.DatastoreFlag.Datacenter() + if err != nil { + return err + } + + ds, err := cmd.DatastoreFlag.Datastore() + if err != nil { + return err + } + + pool, err := cmd.ResourcePoolFlag.ResourcePool() + if err != nil { + return err + } + + folder, err := cmd.FolderOrDefault("vm") + if err != nil { + return err + } + + logger := cmd.ProgressLogger(fmt.Sprintf("Uploading %s... ", path.Base(src))) + defer logger.Wait() + + p := vmdk.ImportParams{ + Path: f.Arg(1), + Logger: logger, + Type: "", // TODO: flag + Force: cmd.force, + Datacenter: dc, + Pool: pool, + Folder: folder, + } + + err = vmdk.Import(ctx, c, src, ds, p) + if err != nil && err == vmdk.ErrInvalidFormat { + return fmt.Errorf(`%s +The vmdk can be converted using one of: + vmware-vdiskmanager -t 5 -r '%s' new.vmdk + qemu-img convert -O vmdk -o subformat=streamOptimized '%s' new.vmdk`, err, src, src) + } + + return err +} diff --git a/vendor/github.com/vmware/govmomi/internal/helpers.go b/vendor/github.com/vmware/govmomi/internal/helpers.go index b3eafeadfd..41e533fd75 100644 --- a/vendor/github.com/vmware/govmomi/internal/helpers.go +++ b/vendor/github.com/vmware/govmomi/internal/helpers.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2020 VMware, Inc. All Rights Reserved. +Copyright (c) 2020-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,13 +17,25 @@ limitations under the License. package internal import ( + "context" + "fmt" "net" + "net/http" + "net/url" + "os" "path" + "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" "github.com/vmware/govmomi/vim25/types" ) +const ( + vCenterHostGatewaySocket = "/var/run/envoy-hgw/hgw-pipe" + vCenterHostGatewaySocketEnv = "VCENTER_ENVOY_HOST_GATEWAY" +) + // InventoryPath composed of entities by Name func InventoryPath(entities []mo.ManagedEntity) string { val := "/" @@ -61,3 +73,69 @@ func HostSystemManagementIPs(config []types.VirtualNicManagerNetConfig) []net.IP return ips } + +// UsingEnvoySidecar determines if the given *vim25.Client is using vCenter's +// local Envoy sidecar (as opposed to using the HTTPS port.) +// Returns a boolean indicating whether to use the sidecar or not. +func UsingEnvoySidecar(c *vim25.Client) bool { + envoySidecarPort := os.Getenv("GOVMOMI_ENVOY_SIDECAR_PORT") + if envoySidecarPort == "" { + envoySidecarPort = "1080" + } + envoySidecarHost := os.Getenv("GOVMOMI_ENVOY_SIDECAR_HOST") + if envoySidecarHost == "" { + envoySidecarHost = "localhost" + } + return c.URL().Hostname() == envoySidecarHost && c.URL().Scheme == "http" && c.URL().Port() == envoySidecarPort +} + +// ClientWithEnvoyHostGateway clones the provided soap.Client and returns a new +// one that uses a Unix socket to leverage vCenter's local Envoy host +// gateway. +// This should be used to construct clients that talk to ESX. +// This method returns a new *vim25.Client and does not modify the original input. +// This client disables HTTP keep alives and is intended for a single round +// trip. (eg. guest file transfer, datastore file transfer) +func ClientWithEnvoyHostGateway(vc *vim25.Client) *vim25.Client { + // Override the vim client with a new one that wraps a Unix socket transport. + // Using HTTP here so secure means nothing. + sc := soap.NewClient(vc.URL(), true) + // Clone the underlying HTTP transport, only replacing the dialer logic. + transport := sc.DefaultTransport().Clone() + hostGatewaySocketPath := os.Getenv(vCenterHostGatewaySocketEnv) + if hostGatewaySocketPath == "" { + hostGatewaySocketPath = vCenterHostGatewaySocket + } + transport.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) { + return net.Dial("unix", hostGatewaySocketPath) + } + // We use this client for a single request, so we don't require keepalives. + transport.DisableKeepAlives = true + sc.Client = http.Client{ + Transport: transport, + } + newVC := &vim25.Client{ + Client: sc, + } + return newVC +} + +// HostGatewayTransferURL rewrites the provided URL to be suitable for use +// with the Envoy host gateway on vCenter. +// It returns a copy of the provided URL with the host, scheme rewritten as needed. +// Receivers of such URLs must typically also use ClientWithEnvoyHostGateway to +// use the appropriate http.Transport to be able to make use of the host +// gateway. +// nil input yields an uninitialized struct. +func HostGatewayTransferURL(u *url.URL, hostMoref types.ManagedObjectReference) *url.URL { + if u == nil { + return &url.URL{} + } + // Make a copy of the provided URL. + turl := *u + turl.Host = "localhost" + turl.Scheme = "http" + oldPath := turl.Path + turl.Path = fmt.Sprintf("/hgw/%s%s", hostMoref.Value, oldPath) + return &turl +} diff --git a/vendor/github.com/vmware/govmomi/internal/version/version.go b/vendor/github.com/vmware/govmomi/internal/version/version.go index c376332722..7111a1ad2d 100644 --- a/vendor/github.com/vmware/govmomi/internal/version/version.go +++ b/vendor/github.com/vmware/govmomi/internal/version/version.go @@ -21,5 +21,5 @@ const ( ClientName = "govmomi" // ClientVersion is the version of this SDK - ClientVersion = "0.30.4" + ClientVersion = "0.33.0" ) diff --git a/vendor/github.com/vmware/govmomi/nfc/lease.go b/vendor/github.com/vmware/govmomi/nfc/lease.go index 4575680336..eb3ef9fcaf 100644 --- a/vendor/github.com/vmware/govmomi/nfc/lease.go +++ b/vendor/github.com/vmware/govmomi/nfc/lease.go @@ -71,17 +71,17 @@ func (l *Lease) Complete(ctx context.Context) error { } // GetManifest wraps methods.GetManifest -func (l *Lease) GetManifest(ctx context.Context) error { +func (l *Lease) GetManifest(ctx context.Context) ([]types.HttpNfcLeaseManifestEntry, error) { req := types.HttpNfcLeaseGetManifest{ This: l.Reference(), } - _, err := methods.HttpNfcLeaseGetManifest(ctx, l.c, &req) + res, err := methods.HttpNfcLeaseGetManifest(ctx, l.c, &req) if err != nil { - return err + return nil, err } - return nil + return res.Returnval, nil } // Progress wraps methods.Progress diff --git a/vendor/github.com/vmware/govmomi/object/compute_resource.go b/vendor/github.com/vmware/govmomi/object/compute_resource.go index 7645fddaf3..4a2db74117 100644 --- a/vendor/github.com/vmware/govmomi/object/compute_resource.go +++ b/vendor/github.com/vmware/govmomi/object/compute_resource.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2015 VMware, Inc. All Rights Reserved. +Copyright (c) 2015-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -18,6 +18,7 @@ package object import ( "context" + "fmt" "path" "github.com/vmware/govmomi/property" @@ -84,6 +85,21 @@ func (c ComputeResource) Datastores(ctx context.Context) ([]*Datastore, error) { return dss, nil } +func (c ComputeResource) EnvironmentBrowser(ctx context.Context) (*EnvironmentBrowser, error) { + var cr mo.ComputeResource + + err := c.Properties(ctx, c.Reference(), []string{"environmentBrowser"}, &cr) + if err != nil { + return nil, err + } + + if cr.EnvironmentBrowser == nil { + return nil, fmt.Errorf("%s: nil environmentBrowser", c.Reference()) + } + + return NewEnvironmentBrowser(c.c, *cr.EnvironmentBrowser), nil +} + func (c ComputeResource) ResourcePool(ctx context.Context) (*ResourcePool, error) { var cr mo.ComputeResource diff --git a/vendor/github.com/vmware/govmomi/object/datastore.go b/vendor/github.com/vmware/govmomi/object/datastore.go index 65264ae152..b3b7f0bb89 100644 --- a/vendor/github.com/vmware/govmomi/object/datastore.go +++ b/vendor/github.com/vmware/govmomi/object/datastore.go @@ -27,6 +27,7 @@ import ( "path" "strings" + "github.com/vmware/govmomi/internal" "github.com/vmware/govmomi/property" "github.com/vmware/govmomi/session" "github.com/vmware/govmomi/vim25" @@ -83,8 +84,14 @@ func (d Datastore) Path(path string) string { func (d Datastore) NewURL(path string) *url.URL { u := d.c.URL() + scheme := u.Scheme + // In rare cases where vCenter and ESX are accessed using different schemes. + if overrideScheme := os.Getenv("GOVMOMI_DATASTORE_ACCESS_SCHEME"); overrideScheme != "" { + scheme = overrideScheme + } + return &url.URL{ - Scheme: u.Scheme, + Scheme: scheme, Host: u.Host, Path: fmt.Sprintf("/folder/%s", path), RawQuery: url.Values{ @@ -223,8 +230,18 @@ func (d Datastore) ServiceTicket(ctx context.Context, path string, method string delete(q, "dcPath") u.RawQuery = q.Encode() + // Now that we have a host selected, take a copy of the URL. + transferURL := *u + + if internal.UsingEnvoySidecar(d.Client()) { + // Rewrite the host URL to go through the Envoy sidecar on VC. + // Reciever must use a custom dialer. + u = internal.HostGatewayTransferURL(u, host.Reference()) + } + spec := types.SessionManagerHttpServiceRequestSpec{ - Url: u.String(), + // Use the original URL (without rewrites) for the session ticket. + Url: transferURL.String(), // See SessionManagerHttpServiceRequestSpecMethod enum Method: fmt.Sprintf("http%s%s", method[0:1], strings.ToLower(method[1:])), } @@ -261,7 +278,10 @@ func (d Datastore) uploadTicket(ctx context.Context, path string, param *soap.Up return nil, nil, err } - p.Ticket = ticket + if ticket != nil { + p.Ticket = ticket + p.Close = true // disable Keep-Alive connection to ESX + } return u, &p, nil } @@ -277,7 +297,10 @@ func (d Datastore) downloadTicket(ctx context.Context, path string, param *soap. return nil, nil, err } - p.Ticket = ticket + if ticket != nil { + p.Ticket = ticket + p.Close = true // disable Keep-Alive connection to ESX + } return u, &p, nil } @@ -297,7 +320,13 @@ func (d Datastore) UploadFile(ctx context.Context, file string, path string, par if err != nil { return err } - return d.Client().UploadFile(ctx, file, u, p) + vc := d.Client() + if internal.UsingEnvoySidecar(vc) { + // Override the vim client with a new one that wraps a Unix socket transport. + // Using HTTP here so secure means nothing. + vc = internal.ClientWithEnvoyHostGateway(vc) + } + return vc.UploadFile(ctx, file, u, p) } // Download via soap.Download with an http service ticket @@ -315,7 +344,13 @@ func (d Datastore) DownloadFile(ctx context.Context, path string, file string, p if err != nil { return err } - return d.Client().DownloadFile(ctx, file, u, p) + vc := d.Client() + if internal.UsingEnvoySidecar(vc) { + // Override the vim client with a new one that wraps a Unix socket transport. + // Using HTTP here so secure means nothing. + vc = internal.ClientWithEnvoyHostGateway(vc) + } + return vc.DownloadFile(ctx, file, u, p) } // AttachedHosts returns hosts that have this Datastore attached, accessible and writable. diff --git a/vendor/github.com/vmware/govmomi/object/environment_browser.go b/vendor/github.com/vmware/govmomi/object/environment_browser.go new file mode 100644 index 0000000000..54ab4cb8d5 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/object/environment_browser.go @@ -0,0 +1,98 @@ +/* +Copyright (c) 2023-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package object + +import ( + "context" + + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +type EnvironmentBrowser struct { + Common +} + +func NewEnvironmentBrowser(c *vim25.Client, ref types.ManagedObjectReference) *EnvironmentBrowser { + return &EnvironmentBrowser{ + Common: NewCommon(c, ref), + } +} + +func (b EnvironmentBrowser) QueryConfigTarget(ctx context.Context, host *HostSystem) (*types.ConfigTarget, error) { + req := types.QueryConfigTarget{ + This: b.Reference(), + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + res, err := methods.QueryConfigTarget(ctx, b.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (b EnvironmentBrowser) QueryTargetCapabilities(ctx context.Context, host *HostSystem) (*types.HostCapability, error) { + req := types.QueryTargetCapabilities{ + This: b.Reference(), + } + + if host != nil { + ref := host.Reference() + req.Host = &ref + } + + res, err := methods.QueryTargetCapabilities(ctx, b.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (b EnvironmentBrowser) QueryConfigOption(ctx context.Context, spec *types.EnvironmentBrowserConfigOptionQuerySpec) (*types.VirtualMachineConfigOption, error) { + req := types.QueryConfigOptionEx{ + This: b.Reference(), + Spec: spec, + } + + res, err := methods.QueryConfigOptionEx(ctx, b.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (b EnvironmentBrowser) QueryConfigOptionDescriptor(ctx context.Context) ([]types.VirtualMachineConfigOptionDescriptor, error) { + req := types.QueryConfigOptionDescriptor{ + This: b.Reference(), + } + + res, err := methods.QueryConfigOptionDescriptor(ctx, b.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/object/host_certificate_info.go b/vendor/github.com/vmware/govmomi/object/host_certificate_info.go index 52c26a9dd6..fd9b370eba 100644 --- a/vendor/github.com/vmware/govmomi/object/host_certificate_info.go +++ b/vendor/github.com/vmware/govmomi/object/host_certificate_info.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2016 VMware, Inc. All Rights Reserved. +Copyright (c) 2016-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -36,10 +36,10 @@ import ( type HostCertificateInfo struct { types.HostCertificateManagerCertificateInfo - ThumbprintSHA1 string - ThumbprintSHA256 string + ThumbprintSHA1 string `json:"thumbprintSHA1"` + ThumbprintSHA256 string `json:"thumbprintSHA256"` - Err error + Err error `json:"err"` Certificate *x509.Certificate `json:"-"` subjectName *pkix.Name @@ -86,10 +86,7 @@ func (info *HostCertificateInfo) FromURL(u *url.URL, config *tls.Config) error { conn, err := tls.Dial("tcp", addr, config) if err != nil { - switch err.(type) { - case x509.UnknownAuthorityError: - case x509.HostnameError: - default: + if !soap.IsCertificateUntrusted(err) { return err } diff --git a/vendor/github.com/vmware/govmomi/object/search_index.go b/vendor/github.com/vmware/govmomi/object/search_index.go index bcf5e29f27..288f78097c 100644 --- a/vendor/github.com/vmware/govmomi/object/search_index.go +++ b/vendor/github.com/vmware/govmomi/object/search_index.go @@ -93,7 +93,18 @@ func (s SearchIndex) FindByInventoryPath(ctx context.Context, path string) (Refe if res.Returnval == nil { return nil, nil } - return NewReference(s.c, *res.Returnval), nil + + r := NewReference(s.c, *res.Returnval) + + type common interface { + SetInventoryPath(string) + } + + if c, ok := r.(common); ok { + c.SetInventoryPath(path) + } + + return r, nil } // FindByIp finds a virtual machine or host by IP address. diff --git a/vendor/github.com/vmware/govmomi/object/virtual_device_list.go b/vendor/github.com/vmware/govmomi/object/virtual_device_list.go index 3765506532..92797dcdab 100644 --- a/vendor/github.com/vmware/govmomi/object/virtual_device_list.go +++ b/vendor/github.com/vmware/govmomi/object/virtual_device_list.go @@ -404,9 +404,13 @@ func (l VirtualDeviceList) PickController(kind types.BaseVirtualController) type } // newUnitNumber returns the unit number to use for attaching a new device to the given controller. -func (l VirtualDeviceList) newUnitNumber(c types.BaseVirtualController) int32 { +func (l VirtualDeviceList) newUnitNumber(c types.BaseVirtualController, offset int) int32 { units := make([]bool, 30) + for i := 0; i < offset; i++ { + units[i] = true + } + switch sc := c.(type) { case types.BaseVirtualSCSIController: // The SCSI controller sits on its own bus @@ -455,7 +459,14 @@ func (l VirtualDeviceList) AssignController(device types.BaseVirtualDevice, c ty d := device.GetVirtualDevice() d.ControllerKey = c.GetVirtualController().Key d.UnitNumber = new(int32) - *d.UnitNumber = l.newUnitNumber(c) + + offset := 0 + switch device.(type) { + case types.BaseVirtualEthernetCard: + offset = 7 + } + *d.UnitNumber = l.newUnitNumber(c, offset) + if d.Key == 0 { d.Key = l.newRandomKey() } diff --git a/vendor/github.com/vmware/govmomi/object/virtual_machine.go b/vendor/github.com/vmware/govmomi/object/virtual_machine.go index eeffc19fd3..4665fcb744 100644 --- a/vendor/github.com/vmware/govmomi/object/virtual_machine.go +++ b/vendor/github.com/vmware/govmomi/object/virtual_machine.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2015-2021 VMware, Inc. All Rights Reserved. +Copyright (c) 2015-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -172,6 +172,15 @@ func (v VirtualMachine) ShutdownGuest(ctx context.Context) error { return err } +func (v VirtualMachine) StandbyGuest(ctx context.Context) error { + req := types.StandbyGuest{ + This: v.Reference(), + } + + _, err := methods.StandbyGuest(ctx, v.c, &req) + return err +} + func (v VirtualMachine) RebootGuest(ctx context.Context) error { req := types.RebootGuest{ This: v.Reference(), @@ -429,6 +438,17 @@ func (v VirtualMachine) Device(ctx context.Context) (VirtualDeviceList, error) { return VirtualDeviceList(o.Config.Hardware.Device), nil } +func (v VirtualMachine) EnvironmentBrowser(ctx context.Context) (*EnvironmentBrowser, error) { + var vm mo.VirtualMachine + + err := v.Properties(ctx, v.Reference(), []string{"environmentBrowser"}, &vm) + if err != nil { + return nil, err + } + + return NewEnvironmentBrowser(v.c, vm.EnvironmentBrowser), nil +} + func (v VirtualMachine) HostSystem(ctx context.Context) (*HostSystem, error) { var o mo.VirtualMachine @@ -909,27 +929,6 @@ func (v VirtualMachine) Unregister(ctx context.Context) error { return err } -// QueryEnvironmentBrowser is a helper to get the environmentBrowser property. -func (v VirtualMachine) QueryConfigTarget(ctx context.Context) (*types.ConfigTarget, error) { - var vm mo.VirtualMachine - - err := v.Properties(ctx, v.Reference(), []string{"environmentBrowser"}, &vm) - if err != nil { - return nil, err - } - - req := types.QueryConfigTarget{ - This: vm.EnvironmentBrowser, - } - - res, err := methods.QueryConfigTarget(ctx, v.Client(), &req) - if err != nil { - return nil, err - } - - return res.Returnval, nil -} - func (v VirtualMachine) MountToolsInstaller(ctx context.Context) error { req := types.MountToolsInstaller{ This: v.Reference(), diff --git a/vendor/github.com/vmware/govmomi/ovf/envelope.go b/vendor/github.com/vmware/govmomi/ovf/envelope.go index 274adb9df1..aa77aab2de 100644 --- a/vendor/github.com/vmware/govmomi/ovf/envelope.go +++ b/vendor/github.com/vmware/govmomi/ovf/envelope.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2015 VMware, Inc. All Rights Reserved. +Copyright (c) 2015-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -16,6 +16,10 @@ limitations under the License. package ovf +import ( + "fmt" +) + type Envelope struct { References []File `xml:"References>File"` @@ -61,6 +65,7 @@ type Content struct { type Section struct { Required *bool `xml:"required,attr"` Info string `xml:"Info"` + Category string `xml:"Category"` } type AnnotationSection struct { @@ -85,6 +90,20 @@ type ProductSection struct { Property []Property `xml:"Property"` } +func (p ProductSection) Key(prop Property) string { + // From OVF spec, section 9.5.1: + // key-value-env = [class-value "."] key-value-prod ["." instance-value] + + k := prop.Key + if p.Class != nil { + k = fmt.Sprintf("%s.%s", *p.Class, k) + } + if p.Instance != nil { + k = fmt.Sprintf("%s.%s", k, *p.Instance) + } + return k +} + type Property struct { Key string `xml:"key,attr"` Type string `xml:"type,attr"` diff --git a/vendor/github.com/vmware/govmomi/pbm/client.go b/vendor/github.com/vmware/govmomi/pbm/client.go index ba2531ec96..3c7965ca8e 100644 --- a/vendor/github.com/vmware/govmomi/pbm/client.go +++ b/vendor/github.com/vmware/govmomi/pbm/client.go @@ -285,3 +285,31 @@ func (c *Client) GetProfileNameByID(ctx context.Context, profileID string) (stri } return "", fmt.Errorf("no pbm profile found with id: %q", profileID) } + +func (c *Client) QueryAssociatedProfile(ctx context.Context, entity types.PbmServerObjectRef) ([]types.PbmProfileId, error) { + req := types.PbmQueryAssociatedProfile{ + This: c.ServiceContent.ProfileManager, + Entity: entity, + } + + res, err := methods.PbmQueryAssociatedProfile(ctx, c, &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} + +func (c *Client) QueryAssociatedProfiles(ctx context.Context, entities []types.PbmServerObjectRef) ([]types.PbmQueryProfileResult, error) { + req := types.PbmQueryAssociatedProfiles{ + This: c.ServiceContent.ProfileManager, + Entities: entities, + } + + res, err := methods.PbmQueryAssociatedProfiles(ctx, c, &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil +} diff --git a/vendor/github.com/vmware/govmomi/pbm/methods/methods.go b/vendor/github.com/vmware/govmomi/pbm/methods/methods.go index fa7f2b200f..032c15c54c 100644 --- a/vendor/github.com/vmware/govmomi/pbm/methods/methods.go +++ b/vendor/github.com/vmware/govmomi/pbm/methods/methods.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2014-2022 VMware, Inc. All Rights Reserved. +Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/vendor/github.com/vmware/govmomi/pbm/types/enum.go b/vendor/github.com/vmware/govmomi/pbm/types/enum.go index 66751bb1f4..be05cfd2a0 100644 --- a/vendor/github.com/vmware/govmomi/pbm/types/enum.go +++ b/vendor/github.com/vmware/govmomi/pbm/types/enum.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2014-2022 VMware, Inc. All Rights Reserved. +Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,8 +25,11 @@ import ( type PbmAssociateAndApplyPolicyStatusPolicyStatus string const ( + // Policy applied successfully. PbmAssociateAndApplyPolicyStatusPolicyStatusSuccess = PbmAssociateAndApplyPolicyStatusPolicyStatus("success") - PbmAssociateAndApplyPolicyStatusPolicyStatusFailed = PbmAssociateAndApplyPolicyStatusPolicyStatus("failed") + // Policy cannot be applied + PbmAssociateAndApplyPolicyStatusPolicyStatusFailed = PbmAssociateAndApplyPolicyStatusPolicyStatus("failed") + // Policy cannot be applied PbmAssociateAndApplyPolicyStatusPolicyStatusInvalid = PbmAssociateAndApplyPolicyStatusPolicyStatus("invalid") ) @@ -34,28 +37,90 @@ func init() { types.Add("pbm:PbmAssociateAndApplyPolicyStatusPolicyStatus", reflect.TypeOf((*PbmAssociateAndApplyPolicyStatusPolicyStatus)(nil)).Elem()) } +// The `PbmBuiltinGenericType_enum` enumerated type defines the list +// of builtin generic datatypes. +// +// See +// `PbmCapabilityGenericTypeInfo*.*PbmCapabilityGenericTypeInfo.genericTypeName`. +// +// A generic datatype indicates how to interpret a collection of values +// of a specific datatype (`PbmCapabilityTypeInfo.typeName`). type PbmBuiltinGenericType string const ( + // Indicates a full or partial range of values (`PbmCapabilityRange`). + // + // A full range specifies both min and max values. + // A partial range specifies one or the other, min or max. PbmBuiltinGenericTypeVMW_RANGE = PbmBuiltinGenericType("VMW_RANGE") - PbmBuiltinGenericTypeVMW_SET = PbmBuiltinGenericType("VMW_SET") + // Indicates a single value or a discrete set of values + // (`PbmCapabilityDiscreteSet`). + PbmBuiltinGenericTypeVMW_SET = PbmBuiltinGenericType("VMW_SET") ) func init() { types.Add("pbm:PbmBuiltinGenericType", reflect.TypeOf((*PbmBuiltinGenericType)(nil)).Elem()) } +// The `PbmBuiltinType_enum` enumerated type defines datatypes +// for storage profiles. +// +// Property metadata +// (`PbmCapabilityPropertyMetadata`) uses the builtin types +// to define data types for storage capabilities and requirements. +// It may also specify the semantics that are applied to a collection +// of builtin type values. See `PbmCapabilityTypeInfo`. +// These semantics are specified as a generic builtin type. +// See `PbmCapabilityGenericTypeInfo`. +// The type information determines how capability constraints are interpreted +// `PbmCapabilityPropertyInstance.value`). type PbmBuiltinType string const ( - PbmBuiltinTypeXSD_LONG = PbmBuiltinType("XSD_LONG") - PbmBuiltinTypeXSD_SHORT = PbmBuiltinType("XSD_SHORT") - PbmBuiltinTypeXSD_INTEGER = PbmBuiltinType("XSD_INTEGER") - PbmBuiltinTypeXSD_INT = PbmBuiltinType("XSD_INT") - PbmBuiltinTypeXSD_STRING = PbmBuiltinType("XSD_STRING") - PbmBuiltinTypeXSD_BOOLEAN = PbmBuiltinType("XSD_BOOLEAN") - PbmBuiltinTypeXSD_DOUBLE = PbmBuiltinType("XSD_DOUBLE") + // Unsigned long value. + // + // This datatype supports the following constraint values. + // - Single value + // - Full or partial range of values (`PbmCapabilityRange`) + // - Discrete set of values (`PbmCapabilityDiscreteSet`) + PbmBuiltinTypeXSD_LONG = PbmBuiltinType("XSD_LONG") + // Datatype not supported. + PbmBuiltinTypeXSD_SHORT = PbmBuiltinType("XSD_SHORT") + // Datatype not supported. + // + // Use XSD\_INT instead. + PbmBuiltinTypeXSD_INTEGER = PbmBuiltinType("XSD_INTEGER") + // Integer value. + // + // This datatype supports the following constraint values. + // - Single value + // - Full or partial range of values (`PbmCapabilityRange`) + // - Discrete set of values (`PbmCapabilityDiscreteSet`) + PbmBuiltinTypeXSD_INT = PbmBuiltinType("XSD_INT") + // String value. + // + // This datatype supports a single value + // or a discrete set of values (`PbmCapabilityDiscreteSet`). + PbmBuiltinTypeXSD_STRING = PbmBuiltinType("XSD_STRING") + // Boolean value. + PbmBuiltinTypeXSD_BOOLEAN = PbmBuiltinType("XSD_BOOLEAN") + // Double precision floating point value. + // + // This datatype supports the following + // constraint values. + // - Single value + // - Full or partial range of values (`PbmCapabilityRange`) + // - Discrete set of values (`PbmCapabilityDiscreteSet`) + PbmBuiltinTypeXSD_DOUBLE = PbmBuiltinType("XSD_DOUBLE") + // Date and time value. PbmBuiltinTypeXSD_DATETIME = PbmBuiltinType("XSD_DATETIME") + // Timespan value (`PbmCapabilityTimeSpan`). + // + // This datatype supports + // the following constraint values. + // - Single value + // - Full or partial range of values (`PbmCapabilityRange`) + // - Discrete set of values (`PbmCapabilityDiscreteSet`) PbmBuiltinTypeVMW_TIMESPAN = PbmBuiltinType("VMW_TIMESPAN") PbmBuiltinTypeVMW_POLICY = PbmBuiltinType("VMW_POLICY") ) @@ -64,6 +129,10 @@ func init() { types.Add("pbm:PbmBuiltinType", reflect.TypeOf((*PbmBuiltinType)(nil)).Elem()) } +// List of operators that are supported for constructing policy. +// +// Currently only tag based properties can use this operator. +// Other operators can be added as required. type PbmCapabilityOperator string const ( @@ -74,52 +143,96 @@ func init() { types.Add("pbm:PbmCapabilityOperator", reflect.TypeOf((*PbmCapabilityOperator)(nil)).Elem()) } +// The `PbmCapabilityTimeUnitType_enum` enumeration type +// defines the supported list of time units for profiles that specify +// time span capabilities and constraints. +// +// See `PbmCapabilityTimeSpan`. type PbmCapabilityTimeUnitType string const ( + // Constraints and capabilities expressed in units of seconds. PbmCapabilityTimeUnitTypeSECONDS = PbmCapabilityTimeUnitType("SECONDS") + // Constraints and capabilities expressed in units of minutes. PbmCapabilityTimeUnitTypeMINUTES = PbmCapabilityTimeUnitType("MINUTES") - PbmCapabilityTimeUnitTypeHOURS = PbmCapabilityTimeUnitType("HOURS") - PbmCapabilityTimeUnitTypeDAYS = PbmCapabilityTimeUnitType("DAYS") - PbmCapabilityTimeUnitTypeWEEKS = PbmCapabilityTimeUnitType("WEEKS") - PbmCapabilityTimeUnitTypeMONTHS = PbmCapabilityTimeUnitType("MONTHS") - PbmCapabilityTimeUnitTypeYEARS = PbmCapabilityTimeUnitType("YEARS") + // Constraints and capabilities expressed in units of hours. + PbmCapabilityTimeUnitTypeHOURS = PbmCapabilityTimeUnitType("HOURS") + // Constraints and capabilities expressed in units of days. + PbmCapabilityTimeUnitTypeDAYS = PbmCapabilityTimeUnitType("DAYS") + // Constraints and capabilities expressed in units of weeks. + PbmCapabilityTimeUnitTypeWEEKS = PbmCapabilityTimeUnitType("WEEKS") + // Constraints and capabilities expressed in units of months. + PbmCapabilityTimeUnitTypeMONTHS = PbmCapabilityTimeUnitType("MONTHS") + // Constraints and capabilities expressed in units of years. + PbmCapabilityTimeUnitTypeYEARS = PbmCapabilityTimeUnitType("YEARS") ) func init() { types.Add("pbm:PbmCapabilityTimeUnitType", reflect.TypeOf((*PbmCapabilityTimeUnitType)(nil)).Elem()) } +// The `PbmComplianceResultComplianceTaskStatus_enum` +// enumeration type defines the set of task status for compliance +// operations. +// +// See `PbmComplianceResult` and +// `PbmRollupComplianceResult`. type PbmComplianceResultComplianceTaskStatus string const ( + // Compliance calculation is in progress. PbmComplianceResultComplianceTaskStatusInProgress = PbmComplianceResultComplianceTaskStatus("inProgress") - PbmComplianceResultComplianceTaskStatusSuccess = PbmComplianceResultComplianceTaskStatus("success") - PbmComplianceResultComplianceTaskStatusFailed = PbmComplianceResultComplianceTaskStatus("failed") + // Compliance calculation has succeeded. + PbmComplianceResultComplianceTaskStatusSuccess = PbmComplianceResultComplianceTaskStatus("success") + // Compliance calculation failed due to some exception. + PbmComplianceResultComplianceTaskStatusFailed = PbmComplianceResultComplianceTaskStatus("failed") ) func init() { types.Add("pbm:PbmComplianceResultComplianceTaskStatus", reflect.TypeOf((*PbmComplianceResultComplianceTaskStatus)(nil)).Elem()) } +// The `PbmComplianceStatus_enum` +// enumeration type defines the set of status values +// for compliance operations. +// +// See `PbmComplianceResult` and +// `PbmRollupComplianceResult`. type PbmComplianceStatus string const ( - PbmComplianceStatusCompliant = PbmComplianceStatus("compliant") - PbmComplianceStatusNonCompliant = PbmComplianceStatus("nonCompliant") - PbmComplianceStatusUnknown = PbmComplianceStatus("unknown") + // Entity is in compliance. + PbmComplianceStatusCompliant = PbmComplianceStatus("compliant") + // Entity is out of compliance. + PbmComplianceStatusNonCompliant = PbmComplianceStatus("nonCompliant") + // Compliance status of the entity is not known. + PbmComplianceStatusUnknown = PbmComplianceStatus("unknown") + // Compliance computation is not applicable for this entity, + // because it does not have any storage requirements that + // apply to the object-based datastore on which this entity is placed. PbmComplianceStatusNotApplicable = PbmComplianceStatus("notApplicable") - PbmComplianceStatusOutOfDate = PbmComplianceStatus("outOfDate") + // This is the same as `PbmComplianceResult.mismatch` + // variable. + // + // Compliance status becomes out-of-date when the profile + // associated with the entity is edited and not applied. The compliance + // status will remain in out-of-date compliance status until the latest + // policy is applied to the entity. + PbmComplianceStatusOutOfDate = PbmComplianceStatus("outOfDate") ) func init() { types.Add("pbm:PbmComplianceStatus", reflect.TypeOf((*PbmComplianceStatus)(nil)).Elem()) } +// This enum corresponds to the keystores used by +// sps. type PbmDebugManagerKeystoreName string const ( - PbmDebugManagerKeystoreNameSMS = PbmDebugManagerKeystoreName("SMS") + // Refers to SMS keystore + PbmDebugManagerKeystoreNameSMS = PbmDebugManagerKeystoreName("SMS") + // Refers to TRUSTED\_ROOTS keystore. PbmDebugManagerKeystoreNameTRUSTED_ROOTS = PbmDebugManagerKeystoreName("TRUSTED_ROOTS") ) @@ -127,12 +240,30 @@ func init() { types.Add("pbm:PbmDebugManagerKeystoreName", reflect.TypeOf((*PbmDebugManagerKeystoreName)(nil)).Elem()) } +// The enumeration type defines the set of health status values for an entity +// that is part of entity health operation. type PbmHealthStatusForEntity string const ( - PbmHealthStatusForEntityRed = PbmHealthStatusForEntity("red") - PbmHealthStatusForEntityYellow = PbmHealthStatusForEntity("yellow") - PbmHealthStatusForEntityGreen = PbmHealthStatusForEntity("green") + // For file share: 'red' if the file server for this file share is in error + // state or any of its backing vSAN objects are degraded. + // + // For FCD: 'red' if the datastore on which the FCD resides is not + // accessible from any of the hosts it is mounted. + PbmHealthStatusForEntityRed = PbmHealthStatusForEntity("red") + // For file share: 'yellow' if some backing objects are repairing, i.e. + // + // warning state. + // For FCD: 'yellow' if the datastore on which the entity resides is + // accessible only from some of the hosts it is mounted but not all. + PbmHealthStatusForEntityYellow = PbmHealthStatusForEntity("yellow") + // For file share: 'green' if the file server for this file share is + // running properly and all its backing vSAN objects are healthy. + // + // For FCD: 'green' if the datastore on which the entity resides + // is accessible from all the hosts it is mounted. + PbmHealthStatusForEntityGreen = PbmHealthStatusForEntity("green") + // If the health status of a file share is unknown, not valid for FCD. PbmHealthStatusForEntityUnknown = PbmHealthStatusForEntity("unknown") ) @@ -140,6 +271,11 @@ func init() { types.Add("pbm:PbmHealthStatusForEntity", reflect.TypeOf((*PbmHealthStatusForEntity)(nil)).Elem()) } +// Recognized types of an IO Filter. +// +// String constant used in `IofilterInfo#filterType`. +// These should match(upper case) the IO Filter classes as defined by IO Filter framework. +// See https://opengrok.eng.vmware.com/source/xref/vmcore-main.perforce.1666/bora/scons/apps/esx/iofilterApps.sc#33 type PbmIofilterInfoFilterType string const ( @@ -156,6 +292,7 @@ func init() { types.Add("pbm:PbmIofilterInfoFilterType", reflect.TypeOf((*PbmIofilterInfoFilterType)(nil)).Elem()) } +// Denotes the line of service of a schema. type PbmLineOfServiceInfoLineOfServiceEnum string const ( @@ -174,28 +311,43 @@ func init() { types.Add("pbm:PbmLineOfServiceInfoLineOfServiceEnum", reflect.TypeOf((*PbmLineOfServiceInfoLineOfServiceEnum)(nil)).Elem()) } +// This enum corresponds to the different packages whose logging +// is configured independently by sps service. type PbmLoggingConfigurationComponent string const ( - PbmLoggingConfigurationComponentPbm = PbmLoggingConfigurationComponent("pbm") - PbmLoggingConfigurationComponentVslm = PbmLoggingConfigurationComponent("vslm") - PbmLoggingConfigurationComponentSms = PbmLoggingConfigurationComponent("sms") - PbmLoggingConfigurationComponentSpbm = PbmLoggingConfigurationComponent("spbm") - PbmLoggingConfigurationComponentSps = PbmLoggingConfigurationComponent("sps") - PbmLoggingConfigurationComponentHttpclient_header = PbmLoggingConfigurationComponent("httpclient_header") + // Modifies logging level of com.vmware.pbm package. + PbmLoggingConfigurationComponentPbm = PbmLoggingConfigurationComponent("pbm") + // Modifies logging level of com.vmware.vslm package. + PbmLoggingConfigurationComponentVslm = PbmLoggingConfigurationComponent("vslm") + // Modifies logging level of com.vmware.vim.sms package. + PbmLoggingConfigurationComponentSms = PbmLoggingConfigurationComponent("sms") + // Modifies logging level of com.vmware.spbm package. + PbmLoggingConfigurationComponentSpbm = PbmLoggingConfigurationComponent("spbm") + // Modifies logging level of com.vmware.sps package. + PbmLoggingConfigurationComponentSps = PbmLoggingConfigurationComponent("sps") + // Modifies logging level of httpclient wire header. + PbmLoggingConfigurationComponentHttpclient_header = PbmLoggingConfigurationComponent("httpclient_header") + // Modifies logging level of httpclient wire content. PbmLoggingConfigurationComponentHttpclient_content = PbmLoggingConfigurationComponent("httpclient_content") - PbmLoggingConfigurationComponentVmomi = PbmLoggingConfigurationComponent("vmomi") + // Modifies logging level of com.vmware.vim.vmomi package. + PbmLoggingConfigurationComponentVmomi = PbmLoggingConfigurationComponent("vmomi") ) func init() { types.Add("pbm:PbmLoggingConfigurationComponent", reflect.TypeOf((*PbmLoggingConfigurationComponent)(nil)).Elem()) } +// This enum corresponds to the different log levels supported +// by sps service. type PbmLoggingConfigurationLogLevel string const ( - PbmLoggingConfigurationLogLevelINFO = PbmLoggingConfigurationLogLevel("INFO") + // Refers to INFO level logging + PbmLoggingConfigurationLogLevelINFO = PbmLoggingConfigurationLogLevel("INFO") + // Refers to DEBUG level logging. PbmLoggingConfigurationLogLevelDEBUG = PbmLoggingConfigurationLogLevel("DEBUG") + // Refers to TRACE level logging. PbmLoggingConfigurationLogLevelTRACE = PbmLoggingConfigurationLogLevel("TRACE") ) @@ -203,42 +355,76 @@ func init() { types.Add("pbm:PbmLoggingConfigurationLogLevel", reflect.TypeOf((*PbmLoggingConfigurationLogLevel)(nil)).Elem()) } +// The `PbmObjectType_enum` enumerated type +// defines vSphere Server object types that are known +// to the Storage Policy Server. +// +// See `PbmServerObjectRef*.*PbmServerObjectRef.objectType`. type PbmObjectType string const ( - PbmObjectTypeVirtualMachine = PbmObjectType("virtualMachine") + // Indicates a virtual machine, not including the disks, identified by the virtual machine + // identifier _virtual-machine-mor_. + PbmObjectTypeVirtualMachine = PbmObjectType("virtualMachine") + // Indicates the virtual machine and all its disks, identified by the virtual machine + // identifier _virtual-machine-mor_. PbmObjectTypeVirtualMachineAndDisks = PbmObjectType("virtualMachineAndDisks") - PbmObjectTypeVirtualDiskId = PbmObjectType("virtualDiskId") - PbmObjectTypeVirtualDiskUUID = PbmObjectType("virtualDiskUUID") - PbmObjectTypeDatastore = PbmObjectType("datastore") - PbmObjectTypeVsanObjectId = PbmObjectType("vsanObjectId") - PbmObjectTypeFileShareId = PbmObjectType("fileShareId") - PbmObjectTypeUnknown = PbmObjectType("unknown") + // Indicates a virtual disk, identified by disk key + // (_virtual-machine-mor_:_disk-key_). + PbmObjectTypeVirtualDiskId = PbmObjectType("virtualDiskId") + // Indicates a virtual disk, identified by UUID - for First Class Storage Object support. + PbmObjectTypeVirtualDiskUUID = PbmObjectType("virtualDiskUUID") + // Indicates a datastore. + PbmObjectTypeDatastore = PbmObjectType("datastore") + // Indicates a VSAN object + PbmObjectTypeVsanObjectId = PbmObjectType("vsanObjectId") + // Indicates a file service + PbmObjectTypeFileShareId = PbmObjectType("fileShareId") + // Unknown object type. + PbmObjectTypeUnknown = PbmObjectType("unknown") ) func init() { types.Add("pbm:PbmObjectType", reflect.TypeOf((*PbmObjectType)(nil)).Elem()) } +// The `PbmOperation_enum` enumerated type +// defines the provisioning operation being performed on the entity like FCD, virtual machine. type PbmOperation string const ( - PbmOperationCREATE = PbmOperation("CREATE") - PbmOperationREGISTER = PbmOperation("REGISTER") + // Indicates create operation of an entity. + PbmOperationCREATE = PbmOperation("CREATE") + // Indicates register operation of an entity. + PbmOperationREGISTER = PbmOperation("REGISTER") + // Indicates reconfigure operation of an entity. PbmOperationRECONFIGURE = PbmOperation("RECONFIGURE") - PbmOperationMIGRATE = PbmOperation("MIGRATE") - PbmOperationCLONE = PbmOperation("CLONE") + // Indicates migrate operation of an entity. + PbmOperationMIGRATE = PbmOperation("MIGRATE") + // Indicates clone operation of an entity. + PbmOperationCLONE = PbmOperation("CLONE") ) func init() { types.Add("pbm:PbmOperation", reflect.TypeOf((*PbmOperation)(nil)).Elem()) } +// Volume allocation type constants. type PbmPolicyAssociationVolumeAllocationType string const ( - PbmPolicyAssociationVolumeAllocationTypeFullyInitialized = PbmPolicyAssociationVolumeAllocationType("FullyInitialized") - PbmPolicyAssociationVolumeAllocationTypeReserveSpace = PbmPolicyAssociationVolumeAllocationType("ReserveSpace") + // Space required is fully allocated and initialized. + // + // It is wiped clean of any previous content on the + // physical media. Gives faster runtime IO performance. + PbmPolicyAssociationVolumeAllocationTypeFullyInitialized = PbmPolicyAssociationVolumeAllocationType("FullyInitialized") + // Space required is fully allocated. + // + // It may contain + // stale data on the physical media. + PbmPolicyAssociationVolumeAllocationTypeReserveSpace = PbmPolicyAssociationVolumeAllocationType("ReserveSpace") + // Space required is allocated and zeroed on demand + // as the space is used. PbmPolicyAssociationVolumeAllocationTypeConserveSpaceWhenPossible = PbmPolicyAssociationVolumeAllocationType("ConserveSpaceWhenPossible") ) @@ -246,11 +432,30 @@ func init() { types.Add("pbm:PbmPolicyAssociationVolumeAllocationType", reflect.TypeOf((*PbmPolicyAssociationVolumeAllocationType)(nil)).Elem()) } +// The `PbmProfileCategoryEnum_enum` +// enumerated type defines the profile categories for a capability-based +// storage profile. +// +// See +// `PbmCapabilityProfile`. type PbmProfileCategoryEnum string const ( - PbmProfileCategoryEnumREQUIREMENT = PbmProfileCategoryEnum("REQUIREMENT") - PbmProfileCategoryEnumRESOURCE = PbmProfileCategoryEnum("RESOURCE") + // Indicates a storage requirement. + // + // Requirements are based on + // storage capabilities. + PbmProfileCategoryEnumREQUIREMENT = PbmProfileCategoryEnum("REQUIREMENT") + // Indicates a storage capability. + // + // Storage capabilities + // are defined by storage providers. + PbmProfileCategoryEnumRESOURCE = PbmProfileCategoryEnum("RESOURCE") + // Indicates a data service policy that can be embedded into + // another storage policy. + // + // Policies of this type can't be assigned to + // Virtual Machines or Virtual Disks. PbmProfileCategoryEnumDATA_SERVICE_POLICY = PbmProfileCategoryEnum("DATA_SERVICE_POLICY") ) @@ -258,9 +463,14 @@ func init() { types.Add("pbm:PbmProfileCategoryEnum", reflect.TypeOf((*PbmProfileCategoryEnum)(nil)).Elem()) } +// The `PbmProfileResourceTypeEnum_enum` enumerated type defines the set of resource +// types that are supported for profile management. +// +// See `PbmProfileResourceType`. type PbmProfileResourceTypeEnum string const ( + // Indicates resources that support storage profiles. PbmProfileResourceTypeEnumSTORAGE = PbmProfileResourceTypeEnum("STORAGE") ) @@ -268,12 +478,21 @@ func init() { types.Add("pbm:PbmProfileResourceTypeEnum", reflect.TypeOf((*PbmProfileResourceTypeEnum)(nil)).Elem()) } +// System pre-created profile types. type PbmSystemCreatedProfileType string const ( - PbmSystemCreatedProfileTypeVsanDefaultProfile = PbmSystemCreatedProfileType("VsanDefaultProfile") - PbmSystemCreatedProfileTypeVVolDefaultProfile = PbmSystemCreatedProfileType("VVolDefaultProfile") - PbmSystemCreatedProfileTypePmemDefaultProfile = PbmSystemCreatedProfileType("PmemDefaultProfile") + // Indicates the system pre-created editable VSAN default profile. + PbmSystemCreatedProfileTypeVsanDefaultProfile = PbmSystemCreatedProfileType("VsanDefaultProfile") + // Indicates the system pre-created non-editable default profile + // for VVOL datastores. + PbmSystemCreatedProfileTypeVVolDefaultProfile = PbmSystemCreatedProfileType("VVolDefaultProfile") + // Indicates the system pre-created non-editable default profile + // for PMem datastores + PbmSystemCreatedProfileTypePmemDefaultProfile = PbmSystemCreatedProfileType("PmemDefaultProfile") + // Indicates the system pre-created non-editable VMC default profile. + PbmSystemCreatedProfileTypeVmcManagementProfile = PbmSystemCreatedProfileType("VmcManagementProfile") + // Indicates the system pre-created non-editable VSANMAX default profile. PbmSystemCreatedProfileTypeVsanMaxDefaultProfile = PbmSystemCreatedProfileType("VsanMaxDefaultProfile") ) @@ -281,25 +500,39 @@ func init() { types.Add("pbm:PbmSystemCreatedProfileType", reflect.TypeOf((*PbmSystemCreatedProfileType)(nil)).Elem()) } +// The `PbmVmOperation_enum` enumerated type +// defines the provisioning operation being performed on the virtual machine. type PbmVmOperation string const ( - PbmVmOperationCREATE = PbmVmOperation("CREATE") + // Indicates create operation of a virtual machine. + PbmVmOperationCREATE = PbmVmOperation("CREATE") + // Indicates reconfigure operation of a virtual machine. PbmVmOperationRECONFIGURE = PbmVmOperation("RECONFIGURE") - PbmVmOperationMIGRATE = PbmVmOperation("MIGRATE") - PbmVmOperationCLONE = PbmVmOperation("CLONE") + // Indicates migrate operation of a virtual machine. + PbmVmOperationMIGRATE = PbmVmOperation("MIGRATE") + // Indicates clone operation of a virtual machine. + PbmVmOperationCLONE = PbmVmOperation("CLONE") ) func init() { types.Add("pbm:PbmVmOperation", reflect.TypeOf((*PbmVmOperation)(nil)).Elem()) } +// The `PbmVvolType_enum` enumeration type +// defines VVOL types. +// +// VvolType's are referenced to specify which objectType +// to fetch for default capability. type PbmVvolType string const ( + // meta-data volume PbmVvolTypeConfig = PbmVvolType("Config") - PbmVvolTypeData = PbmVvolType("Data") - PbmVvolTypeSwap = PbmVvolType("Swap") + // vmdk volume + PbmVvolTypeData = PbmVvolType("Data") + // swap volume + PbmVvolTypeSwap = PbmVvolType("Swap") ) func init() { diff --git a/vendor/github.com/vmware/govmomi/pbm/types/if.go b/vendor/github.com/vmware/govmomi/pbm/types/if.go index a740a25dab..4008dffff7 100644 --- a/vendor/github.com/vmware/govmomi/pbm/types/if.go +++ b/vendor/github.com/vmware/govmomi/pbm/types/if.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2014-2022 VMware, Inc. All Rights Reserved. +Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/vendor/github.com/vmware/govmomi/pbm/types/types.go b/vendor/github.com/vmware/govmomi/pbm/types/types.go index 1687df447d..4c6f72caec 100644 --- a/vendor/github.com/vmware/govmomi/pbm/types/types.go +++ b/vendor/github.com/vmware/govmomi/pbm/types/types.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2014-2022 VMware, Inc. All Rights Reserved. +Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,246 +23,304 @@ import ( "github.com/vmware/govmomi/vim25/types" ) +// A boxed array of `PbmCapabilityConstraintInstance`. To be used in `Any` placeholders. type ArrayOfPbmCapabilityConstraintInstance struct { - PbmCapabilityConstraintInstance []PbmCapabilityConstraintInstance `xml:"PbmCapabilityConstraintInstance,omitempty"` + PbmCapabilityConstraintInstance []PbmCapabilityConstraintInstance `xml:"PbmCapabilityConstraintInstance,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmCapabilityConstraintInstance", reflect.TypeOf((*ArrayOfPbmCapabilityConstraintInstance)(nil)).Elem()) } +// A boxed array of `PbmCapabilityInstance`. To be used in `Any` placeholders. type ArrayOfPbmCapabilityInstance struct { - PbmCapabilityInstance []PbmCapabilityInstance `xml:"PbmCapabilityInstance,omitempty"` + PbmCapabilityInstance []PbmCapabilityInstance `xml:"PbmCapabilityInstance,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmCapabilityInstance", reflect.TypeOf((*ArrayOfPbmCapabilityInstance)(nil)).Elem()) } +// A boxed array of `PbmCapabilityMetadata`. To be used in `Any` placeholders. type ArrayOfPbmCapabilityMetadata struct { - PbmCapabilityMetadata []PbmCapabilityMetadata `xml:"PbmCapabilityMetadata,omitempty"` + PbmCapabilityMetadata []PbmCapabilityMetadata `xml:"PbmCapabilityMetadata,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmCapabilityMetadata", reflect.TypeOf((*ArrayOfPbmCapabilityMetadata)(nil)).Elem()) } +// A boxed array of `PbmCapabilityMetadataPerCategory`. To be used in `Any` placeholders. type ArrayOfPbmCapabilityMetadataPerCategory struct { - PbmCapabilityMetadataPerCategory []PbmCapabilityMetadataPerCategory `xml:"PbmCapabilityMetadataPerCategory,omitempty"` + PbmCapabilityMetadataPerCategory []PbmCapabilityMetadataPerCategory `xml:"PbmCapabilityMetadataPerCategory,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmCapabilityMetadataPerCategory", reflect.TypeOf((*ArrayOfPbmCapabilityMetadataPerCategory)(nil)).Elem()) } +// A boxed array of `PbmCapabilityPropertyInstance`. To be used in `Any` placeholders. type ArrayOfPbmCapabilityPropertyInstance struct { - PbmCapabilityPropertyInstance []PbmCapabilityPropertyInstance `xml:"PbmCapabilityPropertyInstance,omitempty"` + PbmCapabilityPropertyInstance []PbmCapabilityPropertyInstance `xml:"PbmCapabilityPropertyInstance,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmCapabilityPropertyInstance", reflect.TypeOf((*ArrayOfPbmCapabilityPropertyInstance)(nil)).Elem()) } +// A boxed array of `PbmCapabilityPropertyMetadata`. To be used in `Any` placeholders. type ArrayOfPbmCapabilityPropertyMetadata struct { - PbmCapabilityPropertyMetadata []PbmCapabilityPropertyMetadata `xml:"PbmCapabilityPropertyMetadata,omitempty"` + PbmCapabilityPropertyMetadata []PbmCapabilityPropertyMetadata `xml:"PbmCapabilityPropertyMetadata,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmCapabilityPropertyMetadata", reflect.TypeOf((*ArrayOfPbmCapabilityPropertyMetadata)(nil)).Elem()) } +// A boxed array of `PbmCapabilitySchema`. To be used in `Any` placeholders. type ArrayOfPbmCapabilitySchema struct { - PbmCapabilitySchema []PbmCapabilitySchema `xml:"PbmCapabilitySchema,omitempty"` + PbmCapabilitySchema []PbmCapabilitySchema `xml:"PbmCapabilitySchema,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmCapabilitySchema", reflect.TypeOf((*ArrayOfPbmCapabilitySchema)(nil)).Elem()) } +// A boxed array of `PbmCapabilitySubProfile`. To be used in `Any` placeholders. type ArrayOfPbmCapabilitySubProfile struct { - PbmCapabilitySubProfile []PbmCapabilitySubProfile `xml:"PbmCapabilitySubProfile,omitempty"` + PbmCapabilitySubProfile []PbmCapabilitySubProfile `xml:"PbmCapabilitySubProfile,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmCapabilitySubProfile", reflect.TypeOf((*ArrayOfPbmCapabilitySubProfile)(nil)).Elem()) } +// A boxed array of `PbmCapabilityVendorNamespaceInfo`. To be used in `Any` placeholders. type ArrayOfPbmCapabilityVendorNamespaceInfo struct { - PbmCapabilityVendorNamespaceInfo []PbmCapabilityVendorNamespaceInfo `xml:"PbmCapabilityVendorNamespaceInfo,omitempty"` + PbmCapabilityVendorNamespaceInfo []PbmCapabilityVendorNamespaceInfo `xml:"PbmCapabilityVendorNamespaceInfo,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmCapabilityVendorNamespaceInfo", reflect.TypeOf((*ArrayOfPbmCapabilityVendorNamespaceInfo)(nil)).Elem()) } +// A boxed array of `PbmCapabilityVendorResourceTypeInfo`. To be used in `Any` placeholders. type ArrayOfPbmCapabilityVendorResourceTypeInfo struct { - PbmCapabilityVendorResourceTypeInfo []PbmCapabilityVendorResourceTypeInfo `xml:"PbmCapabilityVendorResourceTypeInfo,omitempty"` + PbmCapabilityVendorResourceTypeInfo []PbmCapabilityVendorResourceTypeInfo `xml:"PbmCapabilityVendorResourceTypeInfo,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmCapabilityVendorResourceTypeInfo", reflect.TypeOf((*ArrayOfPbmCapabilityVendorResourceTypeInfo)(nil)).Elem()) } +// A boxed array of `PbmCompliancePolicyStatus`. To be used in `Any` placeholders. type ArrayOfPbmCompliancePolicyStatus struct { - PbmCompliancePolicyStatus []PbmCompliancePolicyStatus `xml:"PbmCompliancePolicyStatus,omitempty"` + PbmCompliancePolicyStatus []PbmCompliancePolicyStatus `xml:"PbmCompliancePolicyStatus,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmCompliancePolicyStatus", reflect.TypeOf((*ArrayOfPbmCompliancePolicyStatus)(nil)).Elem()) } +// A boxed array of `PbmComplianceResult`. To be used in `Any` placeholders. type ArrayOfPbmComplianceResult struct { - PbmComplianceResult []PbmComplianceResult `xml:"PbmComplianceResult,omitempty"` + PbmComplianceResult []PbmComplianceResult `xml:"PbmComplianceResult,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmComplianceResult", reflect.TypeOf((*ArrayOfPbmComplianceResult)(nil)).Elem()) } +// A boxed array of `PbmDatastoreSpaceStatistics`. To be used in `Any` placeholders. type ArrayOfPbmDatastoreSpaceStatistics struct { - PbmDatastoreSpaceStatistics []PbmDatastoreSpaceStatistics `xml:"PbmDatastoreSpaceStatistics,omitempty"` + PbmDatastoreSpaceStatistics []PbmDatastoreSpaceStatistics `xml:"PbmDatastoreSpaceStatistics,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmDatastoreSpaceStatistics", reflect.TypeOf((*ArrayOfPbmDatastoreSpaceStatistics)(nil)).Elem()) } +// A boxed array of `PbmDefaultProfileInfo`. To be used in `Any` placeholders. type ArrayOfPbmDefaultProfileInfo struct { - PbmDefaultProfileInfo []PbmDefaultProfileInfo `xml:"PbmDefaultProfileInfo,omitempty"` + PbmDefaultProfileInfo []PbmDefaultProfileInfo `xml:"PbmDefaultProfileInfo,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmDefaultProfileInfo", reflect.TypeOf((*ArrayOfPbmDefaultProfileInfo)(nil)).Elem()) } +// A boxed array of `PbmFaultNoPermissionEntityPrivileges`. To be used in `Any` placeholders. +type ArrayOfPbmFaultNoPermissionEntityPrivileges struct { + PbmFaultNoPermissionEntityPrivileges []PbmFaultNoPermissionEntityPrivileges `xml:"PbmFaultNoPermissionEntityPrivileges,omitempty" json:"_value"` +} + +func init() { + types.Add("pbm:ArrayOfPbmFaultNoPermissionEntityPrivileges", reflect.TypeOf((*ArrayOfPbmFaultNoPermissionEntityPrivileges)(nil)).Elem()) +} + +// A boxed array of `PbmLoggingConfiguration`. To be used in `Any` placeholders. +type ArrayOfPbmLoggingConfiguration struct { + PbmLoggingConfiguration []PbmLoggingConfiguration `xml:"PbmLoggingConfiguration,omitempty" json:"_value"` +} + +func init() { + types.Add("pbm:ArrayOfPbmLoggingConfiguration", reflect.TypeOf((*ArrayOfPbmLoggingConfiguration)(nil)).Elem()) +} + +// A boxed array of `PbmPlacementCompatibilityResult`. To be used in `Any` placeholders. type ArrayOfPbmPlacementCompatibilityResult struct { - PbmPlacementCompatibilityResult []PbmPlacementCompatibilityResult `xml:"PbmPlacementCompatibilityResult,omitempty"` + PbmPlacementCompatibilityResult []PbmPlacementCompatibilityResult `xml:"PbmPlacementCompatibilityResult,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmPlacementCompatibilityResult", reflect.TypeOf((*ArrayOfPbmPlacementCompatibilityResult)(nil)).Elem()) } +// A boxed array of `PbmPlacementHub`. To be used in `Any` placeholders. type ArrayOfPbmPlacementHub struct { - PbmPlacementHub []PbmPlacementHub `xml:"PbmPlacementHub,omitempty"` + PbmPlacementHub []PbmPlacementHub `xml:"PbmPlacementHub,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmPlacementHub", reflect.TypeOf((*ArrayOfPbmPlacementHub)(nil)).Elem()) } +// A boxed array of `PbmPlacementMatchingResources`. To be used in `Any` placeholders. type ArrayOfPbmPlacementMatchingResources struct { - PbmPlacementMatchingResources []BasePbmPlacementMatchingResources `xml:"PbmPlacementMatchingResources,omitempty,typeattr"` + PbmPlacementMatchingResources []BasePbmPlacementMatchingResources `xml:"PbmPlacementMatchingResources,omitempty,typeattr" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmPlacementMatchingResources", reflect.TypeOf((*ArrayOfPbmPlacementMatchingResources)(nil)).Elem()) } +// A boxed array of `PbmPlacementRequirement`. To be used in `Any` placeholders. type ArrayOfPbmPlacementRequirement struct { - PbmPlacementRequirement []BasePbmPlacementRequirement `xml:"PbmPlacementRequirement,omitempty,typeattr"` + PbmPlacementRequirement []BasePbmPlacementRequirement `xml:"PbmPlacementRequirement,omitempty,typeattr" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmPlacementRequirement", reflect.TypeOf((*ArrayOfPbmPlacementRequirement)(nil)).Elem()) } +// A boxed array of `PbmPlacementResourceUtilization`. To be used in `Any` placeholders. type ArrayOfPbmPlacementResourceUtilization struct { - PbmPlacementResourceUtilization []PbmPlacementResourceUtilization `xml:"PbmPlacementResourceUtilization,omitempty"` + PbmPlacementResourceUtilization []PbmPlacementResourceUtilization `xml:"PbmPlacementResourceUtilization,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmPlacementResourceUtilization", reflect.TypeOf((*ArrayOfPbmPlacementResourceUtilization)(nil)).Elem()) } +// A boxed array of `PbmProfile`. To be used in `Any` placeholders. type ArrayOfPbmProfile struct { - PbmProfile []BasePbmProfile `xml:"PbmProfile,omitempty,typeattr"` + PbmProfile []BasePbmProfile `xml:"PbmProfile,omitempty,typeattr" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmProfile", reflect.TypeOf((*ArrayOfPbmProfile)(nil)).Elem()) } +// A boxed array of `PbmProfileId`. To be used in `Any` placeholders. type ArrayOfPbmProfileId struct { - PbmProfileId []PbmProfileId `xml:"PbmProfileId,omitempty"` + PbmProfileId []PbmProfileId `xml:"PbmProfileId,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmProfileId", reflect.TypeOf((*ArrayOfPbmProfileId)(nil)).Elem()) } +// A boxed array of `PbmProfileOperationOutcome`. To be used in `Any` placeholders. type ArrayOfPbmProfileOperationOutcome struct { - PbmProfileOperationOutcome []PbmProfileOperationOutcome `xml:"PbmProfileOperationOutcome,omitempty"` + PbmProfileOperationOutcome []PbmProfileOperationOutcome `xml:"PbmProfileOperationOutcome,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmProfileOperationOutcome", reflect.TypeOf((*ArrayOfPbmProfileOperationOutcome)(nil)).Elem()) } +// A boxed array of `PbmProfileResourceType`. To be used in `Any` placeholders. type ArrayOfPbmProfileResourceType struct { - PbmProfileResourceType []PbmProfileResourceType `xml:"PbmProfileResourceType,omitempty"` + PbmProfileResourceType []PbmProfileResourceType `xml:"PbmProfileResourceType,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmProfileResourceType", reflect.TypeOf((*ArrayOfPbmProfileResourceType)(nil)).Elem()) } +// A boxed array of `PbmProfileType`. To be used in `Any` placeholders. type ArrayOfPbmProfileType struct { - PbmProfileType []PbmProfileType `xml:"PbmProfileType,omitempty"` + PbmProfileType []PbmProfileType `xml:"PbmProfileType,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmProfileType", reflect.TypeOf((*ArrayOfPbmProfileType)(nil)).Elem()) } +// A boxed array of `PbmQueryProfileResult`. To be used in `Any` placeholders. type ArrayOfPbmQueryProfileResult struct { - PbmQueryProfileResult []PbmQueryProfileResult `xml:"PbmQueryProfileResult,omitempty"` + PbmQueryProfileResult []PbmQueryProfileResult `xml:"PbmQueryProfileResult,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmQueryProfileResult", reflect.TypeOf((*ArrayOfPbmQueryProfileResult)(nil)).Elem()) } +// A boxed array of `PbmQueryReplicationGroupResult`. To be used in `Any` placeholders. type ArrayOfPbmQueryReplicationGroupResult struct { - PbmQueryReplicationGroupResult []PbmQueryReplicationGroupResult `xml:"PbmQueryReplicationGroupResult,omitempty"` + PbmQueryReplicationGroupResult []PbmQueryReplicationGroupResult `xml:"PbmQueryReplicationGroupResult,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmQueryReplicationGroupResult", reflect.TypeOf((*ArrayOfPbmQueryReplicationGroupResult)(nil)).Elem()) } +// A boxed array of `PbmRollupComplianceResult`. To be used in `Any` placeholders. type ArrayOfPbmRollupComplianceResult struct { - PbmRollupComplianceResult []PbmRollupComplianceResult `xml:"PbmRollupComplianceResult,omitempty"` + PbmRollupComplianceResult []PbmRollupComplianceResult `xml:"PbmRollupComplianceResult,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmRollupComplianceResult", reflect.TypeOf((*ArrayOfPbmRollupComplianceResult)(nil)).Elem()) } +// A boxed array of `PbmServerObjectRef`. To be used in `Any` placeholders. type ArrayOfPbmServerObjectRef struct { - PbmServerObjectRef []PbmServerObjectRef `xml:"PbmServerObjectRef,omitempty"` + PbmServerObjectRef []PbmServerObjectRef `xml:"PbmServerObjectRef,omitempty" json:"_value"` } func init() { types.Add("pbm:ArrayOfPbmServerObjectRef", reflect.TypeOf((*ArrayOfPbmServerObjectRef)(nil)).Elem()) } +// The `PbmAboutInfo` data object stores identifying data +// about the Storage Policy Server. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmAboutInfo struct { types.DynamicData - Name string `xml:"name"` - Version string `xml:"version"` - InstanceUuid string `xml:"instanceUuid"` + // Name of the server. + Name string `xml:"name" json:"name"` + // Version number. + Version string `xml:"version" json:"version"` + // Globally unique identifier associated with this server instance. + InstanceUuid string `xml:"instanceUuid" json:"instanceUuid"` } func init() { types.Add("pbm:PbmAboutInfo", reflect.TypeOf((*PbmAboutInfo)(nil)).Elem()) } +// An AlreadyExists fault is thrown when an attempt is made to add an element to +// a collection, if the element's key, name, or identifier already exists in +// that collection. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmAlreadyExists struct { PbmFault - Name string `xml:"name,omitempty"` + Name string `xml:"name,omitempty" json:"name,omitempty"` } func init() { @@ -281,10 +339,13 @@ func init() { types.Add("pbm:PbmAssignDefaultRequirementProfile", reflect.TypeOf((*PbmAssignDefaultRequirementProfile)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmAssignDefaultRequirementProfile`. type PbmAssignDefaultRequirementProfileRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Profile PbmProfileId `xml:"profile"` - Datastores []PbmPlacementHub `xml:"datastores"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // The profile that needs to be made default profile. + Profile PbmProfileId `xml:"profile" json:"profile"` + // The datastores for which the profile needs to be made as default profile. + Datastores []PbmPlacementHub `xml:"datastores" json:"datastores"` } func init() { @@ -294,16 +355,26 @@ func init() { type PbmAssignDefaultRequirementProfileResponse struct { } +// Constraints on the properties for a single occurrence of a capability. +// +// All properties must satisfy their respective constraints to be compliant. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityConstraintInstance struct { types.DynamicData - PropertyInstance []PbmCapabilityPropertyInstance `xml:"propertyInstance"` + // Property instance array for this constraint + PropertyInstance []PbmCapabilityPropertyInstance `xml:"propertyInstance" json:"propertyInstance"` } func init() { types.Add("pbm:PbmCapabilityConstraintInstance", reflect.TypeOf((*PbmCapabilityConstraintInstance)(nil)).Elem()) } +// The `PbmCapabilityConstraints` data object is the base +// object for capability subprofile constraints. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityConstraints struct { types.DynamicData } @@ -312,69 +383,161 @@ func init() { types.Add("pbm:PbmCapabilityConstraints", reflect.TypeOf((*PbmCapabilityConstraints)(nil)).Elem()) } +// A property value with description. +// +// It can be repeated under DiscreteSet. +// E.g., set of tags, each with description and tag name. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityDescription struct { types.DynamicData - Description PbmExtendedElementDescription `xml:"description"` - Value types.AnyType `xml:"value,typeattr"` + // Description of the property value + Description PbmExtendedElementDescription `xml:"description" json:"description"` + // Values for the set. + // + // must be one of the supported datatypes as + // defined in `PbmBuiltinType_enum` + // Must only contain unique values to comply with the Set semantics + Value types.AnyType `xml:"value,typeattr" json:"value"` } func init() { types.Add("pbm:PbmCapabilityDescription", reflect.TypeOf((*PbmCapabilityDescription)(nil)).Elem()) } +// The `PbmCapabilityDiscreteSet` data object defines a set of values +// for storage profile property instances (`PbmCapabilityPropertyInstance`). +// +// Use the discrete set type to define a set of values of a supported builtin type +// (`PbmBuiltinType_enum`), for example a set of integers +// (XSD\_INT) or a set of unsigned long values (XSD\_LONG). +// See `PbmBuiltinGenericType_enum*.*VMW_SET`. +// +// A discrete set of values is declared as an array of xsd:anyType values. +// - When you define a property instance for a storage profile requirement +// and pass an array of values to the Server, you must set the array elements +// to values of the appropriate datatype. +// - When you read a discrete set from a property instance for a storage profile +// capability, you must cast the xsd:anyType array element values +// to the appropriate datatype. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityDiscreteSet struct { types.DynamicData - Values []types.AnyType `xml:"values,typeattr"` + // Array of values for the set. + // + // The values must be one of the supported datatypes + // as defined in `PbmBuiltinType_enum` or `PbmBuiltinGenericType_enum`. + Values []types.AnyType `xml:"values,typeattr" json:"values"` } func init() { types.Add("pbm:PbmCapabilityDiscreteSet", reflect.TypeOf((*PbmCapabilityDiscreteSet)(nil)).Elem()) } +// Generic type definition for capabilities. +// +// Indicates how a collection of values of a specific datatype +// (`PbmCapabilityTypeInfo.typeName`) +// will be interpreted. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityGenericTypeInfo struct { PbmCapabilityTypeInfo - GenericTypeName string `xml:"genericTypeName"` + // Name of the generic type. + // + // Must correspond to one of the values defined in + // `PbmBuiltinGenericType_enum`. + GenericTypeName string `xml:"genericTypeName" json:"genericTypeName"` } func init() { types.Add("pbm:PbmCapabilityGenericTypeInfo", reflect.TypeOf((*PbmCapabilityGenericTypeInfo)(nil)).Elem()) } +// The `PbmCapabilityInstance` data object defines a storage capability instance. +// +// Metadata for the capability is described in `PbmCapabilityMetadata`. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityInstance struct { types.DynamicData - Id PbmCapabilityMetadataUniqueId `xml:"id"` - Constraint []PbmCapabilityConstraintInstance `xml:"constraint"` + // Identifier for the capability. + // + // The identifier value corresponds to + // `PbmCapabilityMetadata*.*PbmCapabilityMetadata.id`. + Id PbmCapabilityMetadataUniqueId `xml:"id" json:"id"` + // Constraints on the properties that comprise this capability. + // + // Each entry represents a constraint on one or more of the properties that + // constitute this capability. A datum must meet one of the + // constraints to be compliant. + Constraint []PbmCapabilityConstraintInstance `xml:"constraint" json:"constraint"` } func init() { types.Add("pbm:PbmCapabilityInstance", reflect.TypeOf((*PbmCapabilityInstance)(nil)).Elem()) } +// Metadata for a single unique setting defined by a provider. +// +// A simple setting is a setting with one property. +// A complex setting contains more than one property. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityMetadata struct { types.DynamicData - Id PbmCapabilityMetadataUniqueId `xml:"id"` - Summary PbmExtendedElementDescription `xml:"summary"` - Mandatory *bool `xml:"mandatory"` - Hint *bool `xml:"hint"` - KeyId string `xml:"keyId,omitempty"` - AllowMultipleConstraints *bool `xml:"allowMultipleConstraints"` - PropertyMetadata []PbmCapabilityPropertyMetadata `xml:"propertyMetadata"` + // Unique identifier for the capability. + Id PbmCapabilityMetadataUniqueId `xml:"id" json:"id"` + // Capability name and description + Summary PbmExtendedElementDescription `xml:"summary" json:"summary"` + // Indicates whether incorporating given capability is mandatory during creation of + // profile. + Mandatory *bool `xml:"mandatory" json:"mandatory,omitempty"` + // The flag hint dictates the interpretation of constraints specified for this capability + // in a storage policy profile. + // + // If hint is false, then constraints will affect placement. + // If hint is true, constraints will not affect placement, + // but will still be passed to provisioning operations if the provider understands the + // relevant namespace. Optional property, false if not set. + Hint *bool `xml:"hint" json:"hint,omitempty"` + // Property Id of the key property, if this capability represents a key + // value pair. + // + // Value is empty string if not set. + KeyId string `xml:"keyId,omitempty" json:"keyId,omitempty"` + // Flag to indicate if multiple constraints are allowed in the capability + // instance. + // + // False if not set. + AllowMultipleConstraints *bool `xml:"allowMultipleConstraints" json:"allowMultipleConstraints,omitempty"` + // Metadata for the properties that comprise this capability. + PropertyMetadata []PbmCapabilityPropertyMetadata `xml:"propertyMetadata" json:"propertyMetadata"` } func init() { types.Add("pbm:PbmCapabilityMetadata", reflect.TypeOf((*PbmCapabilityMetadata)(nil)).Elem()) } +// The `PbmCapabilityMetadataPerCategory` +// data object defines capability metadata for a profile subcategory. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityMetadataPerCategory struct { types.DynamicData - SubCategory string `xml:"subCategory"` - CapabilityMetadata []PbmCapabilityMetadata `xml:"capabilityMetadata"` + // Profile subcategory to which the capability metadata belongs. + // + // The subcategory is specified by the storage provider. + SubCategory string `xml:"subCategory" json:"subCategory"` + // Capability metadata for this category + CapabilityMetadata []PbmCapabilityMetadata `xml:"capabilityMetadata" json:"capabilityMetadata"` } func init() { @@ -384,60 +547,162 @@ func init() { type PbmCapabilityMetadataUniqueId struct { types.DynamicData - Namespace string `xml:"namespace"` - Id string `xml:"id"` + // Namespace to which this capability belongs. + // + // Must be the same as + // { @link CapabilityObjectSchema#namespace } defined for this + // capability + Namespace string `xml:"namespace" json:"namespace"` + // unique identifier for this capability within given namespace + Id string `xml:"id" json:"id"` } func init() { types.Add("pbm:PbmCapabilityMetadataUniqueId", reflect.TypeOf((*PbmCapabilityMetadataUniqueId)(nil)).Elem()) } +// Name space information for the capability metadata schema. +// +// NOTE: Name spaces are required to be globally unique across resource types. +// A same vendor can register multiple name spaces for same resource type or +// for different resource type, but the schema namespace URL must be unique +// for each of these cases. +// A CapabilityMetadata object is uniquely identified based on the namespace +// it belongs to and it's unique identifier within that namespace. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityNamespaceInfo struct { types.DynamicData - Version string `xml:"version"` - Namespace string `xml:"namespace"` - Info *PbmExtendedElementDescription `xml:"info,omitempty"` + // Schema version + Version string `xml:"version" json:"version"` + // Schema namespace. + Namespace string `xml:"namespace" json:"namespace"` + Info *PbmExtendedElementDescription `xml:"info,omitempty" json:"info,omitempty"` } func init() { types.Add("pbm:PbmCapabilityNamespaceInfo", reflect.TypeOf((*PbmCapabilityNamespaceInfo)(nil)).Elem()) } +// The `PbmCapabilityProfile` data object defines +// capability-based profiles. +// +// A capability-based profile is derived +// from tag-based storage capabilities or from vSAN storage capabilities. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityProfile struct { PbmProfile - ProfileCategory string `xml:"profileCategory"` - ResourceType PbmProfileResourceType `xml:"resourceType"` - Constraints BasePbmCapabilityConstraints `xml:"constraints,typeattr"` - GenerationId int64 `xml:"generationId,omitempty"` - IsDefault bool `xml:"isDefault"` - SystemCreatedProfileType string `xml:"systemCreatedProfileType,omitempty"` - LineOfService string `xml:"lineOfService,omitempty"` + // Indicates whether the profile is requirement + // profile, a resource profile or a data service profile. + // + // The profileCategory + // is a string value that corresponds to one of the + // `PbmProfileCategoryEnum_enum` values. + // - REQUIREMENT profile - Defines the storage constraints applied + // to virtual machine placement. Requirements are defined by + // the user and can be associated with virtual machines and virtual + // disks. During provisioning, you can use a requirements profile + // for compliance and placement checking to support + // selection and configuration of resources. + // - RESOURCE profile - Specifies system-defined storage capabilities. + // You cannot modify a resource profile. You cannot associate a resource + // profile with vSphere entities, use it during provisioning, or target + // entities for resource selection or configuration. + // This type of profile gives the user visibility into the capabilities + // supported by the storage provider. + // + // DATA\_SERVICE\_POLICY - Indicates a data service policy that can + // be embedded into another storage policy. Policies of this type can't + // be assigned to Virtual Machines or Virtual Disks. This policy cannot + // be used for compliance checking. + ProfileCategory string `xml:"profileCategory" json:"profileCategory"` + // Type of the target resource to which the capability information applies. + // + // A fixed enum that defines resource types for which capabilities can be defined + // see `PbmProfileResourceType`, `PbmProfileResourceTypeEnum_enum` + ResourceType PbmProfileResourceType `xml:"resourceType" json:"resourceType"` + // Subprofiles that describe storage requirements or storage provider capabilities, + // depending on the profile category (REQUIREMENT or RESOURCE). + Constraints BasePbmCapabilityConstraints `xml:"constraints,typeattr" json:"constraints"` + // Generation ID is used to communicate the current version of the profile to VASA + // providers. + // + // It is only applicable to REQUIREMENT profile types. Every time a + // requirement profile is edited, the Server will increment the generationId. You + // do not need to set the generationID. When an object is created (or + // reconfigured), the Server will send the requirement profile content, profile ID and + // the generationID to VASA provider. + GenerationId int64 `xml:"generationId,omitempty" json:"generationId,omitempty"` + // Deprecated since it is not supported. + // + // Not supported in this release. + IsDefault bool `xml:"isDefault" json:"isDefault"` + // Indicates the type of system pre-created default profile. + // + // This will be set only for system pre-created default profiles. And + // this is not set for RESOURCE profiles. + SystemCreatedProfileType string `xml:"systemCreatedProfileType,omitempty" json:"systemCreatedProfileType,omitempty"` + // This property is set only for data service policy. + // + // Indicates the line of service + // `PbmLineOfServiceInfoLineOfServiceEnum_enum` of the data service policy. + LineOfService string `xml:"lineOfService,omitempty" json:"lineOfService,omitempty"` } func init() { types.Add("pbm:PbmCapabilityProfile", reflect.TypeOf((*PbmCapabilityProfile)(nil)).Elem()) } +// The `PbmCapabilityProfileCreateSpec` describes storage requirements. +// +// Use this data object to create a `PbmCapabilityProfile`. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityProfileCreateSpec struct { types.DynamicData - Name string `xml:"name"` - Description string `xml:"description,omitempty"` - Category string `xml:"category,omitempty"` - ResourceType PbmProfileResourceType `xml:"resourceType"` - Constraints BasePbmCapabilityConstraints `xml:"constraints,typeattr"` + // Name of the capability based profile to be created. + // + // The maximum length of the name is 80 characters. + Name string `xml:"name" json:"name"` + // Text description associated with the profile. + Description string `xml:"description,omitempty" json:"description,omitempty"` + // Category specifies the type of policy to be created. + // + // This can be REQUIREMENT from + // `PbmProfileCategoryEnum_enum` + // or null when creating a storage policy. And it can be DATA\_SERVICE\_POLICY from + // `PbmProfileCategoryEnum_enum` + // when creating a data service policy. RESOURCE from `PbmProfileCategoryEnum_enum` + // is not allowed as resource profile is created by the system. + Category string `xml:"category,omitempty" json:"category,omitempty"` + // Deprecated as of vSphere API 6.5. + // + // Specifies the type of resource to which the profile applies. + // + // The only legal value is STORAGE - deprecated. + ResourceType PbmProfileResourceType `xml:"resourceType" json:"resourceType"` + // Set of subprofiles that define the storage requirements. + // + // A subprofile corresponds to a rule set in the vSphere Web Client. + Constraints BasePbmCapabilityConstraints `xml:"constraints,typeattr" json:"constraints"` } func init() { types.Add("pbm:PbmCapabilityProfileCreateSpec", reflect.TypeOf((*PbmCapabilityProfileCreateSpec)(nil)).Elem()) } +// Fault used when a datastore doesnt match the capability profile property instance in requirements profile. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityProfilePropertyMismatchFault struct { PbmPropertyMismatchFault - ResourcePropertyInstance PbmCapabilityPropertyInstance `xml:"resourcePropertyInstance"` + // The property instance in the resource profile that does not match. + ResourcePropertyInstance PbmCapabilityPropertyInstance `xml:"resourcePropertyInstance" json:"resourcePropertyInstance"` } func init() { @@ -450,118 +715,347 @@ func init() { types.Add("pbm:PbmCapabilityProfilePropertyMismatchFaultFault", reflect.TypeOf((*PbmCapabilityProfilePropertyMismatchFaultFault)(nil)).Elem()) } +// The `PbmCapabilityProfileUpdateSpec` data object +// contains data that you use to update a storage profile. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityProfileUpdateSpec struct { types.DynamicData - Name string `xml:"name,omitempty"` - Description string `xml:"description,omitempty"` - Constraints BasePbmCapabilityConstraints `xml:"constraints,omitempty,typeattr"` + // Specifies a new profile name. + Name string `xml:"name,omitempty" json:"name,omitempty"` + // Specifies a new profile description. + Description string `xml:"description,omitempty" json:"description,omitempty"` + // Specifies one or more subprofiles. + // + // A subprofile defines one or more + // storage requirements. + Constraints BasePbmCapabilityConstraints `xml:"constraints,omitempty,typeattr" json:"constraints,omitempty"` } func init() { types.Add("pbm:PbmCapabilityProfileUpdateSpec", reflect.TypeOf((*PbmCapabilityProfileUpdateSpec)(nil)).Elem()) } +// The `PbmCapabilityPropertyInstance` data object describes a virtual machine +// storage requirement. +// +// A storage requirement is based on the storage capability +// described in the `PbmCapabilityPropertyMetadata` and in the +// datastore profile property instance. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityPropertyInstance struct { types.DynamicData - Id string `xml:"id"` - Operator string `xml:"operator,omitempty"` - Value types.AnyType `xml:"value,typeattr"` + // Requirement property identifier. + // + // This identifier corresponds to the + // storage capability metadata identifier + // (`PbmCapabilityPropertyMetadata*.*PbmCapabilityPropertyMetadata.id`). + Id string `xml:"id" json:"id"` + // Operator for the values. + // + // Currently only support NOT operator for + // tag namespace + // See operator definition in (`PbmCapabilityOperator_enum`). + Operator string `xml:"operator,omitempty" json:"operator,omitempty"` + // Property value. + // + // You must specify the value. + // A property value is one value or a collection of values. + // - A single property value is expressed as a scalar value. + // - A collection of values is expressed as a `PbmCapabilityDiscreteSet` + // or a `PbmCapabilityRange` of values. + // + // The datatype of each value must be one of the + // `PbmBuiltinType_enum` datatypes. + // If the property consists of a collection of values, + // the interpretation of those values is determined by the + // `PbmCapabilityGenericTypeInfo`. + // + // Type information for a property instance is described in the property metadata + // (`PbmCapabilityPropertyMetadata*.*PbmCapabilityPropertyMetadata.type`). + Value types.AnyType `xml:"value,typeattr" json:"value"` } func init() { types.Add("pbm:PbmCapabilityPropertyInstance", reflect.TypeOf((*PbmCapabilityPropertyInstance)(nil)).Elem()) } +// The `PbmCapabilityPropertyMetadata` data object describes storage capability. +// +// An instance of property metadata may apply to many property instances +// (`PbmCapabilityPropertyInstance`). +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityPropertyMetadata struct { types.DynamicData - Id string `xml:"id"` - Summary PbmExtendedElementDescription `xml:"summary"` - Mandatory bool `xml:"mandatory"` - Type BasePbmCapabilityTypeInfo `xml:"type,omitempty,typeattr"` - DefaultValue types.AnyType `xml:"defaultValue,omitempty,typeattr"` - AllowedValue types.AnyType `xml:"allowedValue,omitempty,typeattr"` - RequirementsTypeHint string `xml:"requirementsTypeHint,omitempty"` + // Property identifier. + // + // Should be unique within the definition of the + // capability. Property instances refer to this identifier + // (`PbmCapabilityPropertyInstance*.*PbmCapabilityPropertyInstance.id`). + Id string `xml:"id" json:"id"` + // Property name and description. + // - The summary.label property + // (`PbmExtendedElementDescription.label`) + // contains property 'name' in server locale. + // - The summary.summary property + // (`PbmExtendedElementDescription.summary`) + // contains property 'description' in server locale. + // - The summary.messageCatalogKeyPrefix property + // (`PbmExtendedElementDescription.messageCatalogKeyPrefix`) + // contains unique prefix for this property within given message catalog. + // Prefix format: <capability\_unique\_identifier.<property\_id + // capability\_unique\_identifier -- string representation of + // `PbmCapabilityMetadataUniqueId` which globally identifies given + // capability metadata definition uniquely. + // property\_id -- 'id' of this property `PbmCapabilityPropertyMetadata.id` + // Eg www.emc.com.storage.Recovery.Recovery\_site + // www.emc.com.storage.Recovery.RPO + // www.emc.com.storage.Recovery.RTO + Summary PbmExtendedElementDescription `xml:"summary" json:"summary"` + // Indicates whether incorporating given capability is mandatory during creation of + // profile. + Mandatory bool `xml:"mandatory" json:"mandatory"` + // Type information for the capability. + // + // The type of a property value + // (`PbmCapabilityPropertyInstance*.*PbmCapabilityPropertyInstance.value`) + // is specified as a builtin datatype and may also specify the interpretation of a + // collection of values of that datatype. + // - `PbmCapabilityPropertyMetadata.type*.*PbmCapabilityTypeInfo.typeName` + // specifies the `PbmBuiltinType_enum`. + // - `PbmCapabilityPropertyMetadata.type*.*PbmCapabilityGenericTypeInfo.genericTypeName` + // indicates how a collection of values of the specified datatype will be interpreted + // (`PbmBuiltinGenericType_enum`). + Type BasePbmCapabilityTypeInfo `xml:"type,omitempty,typeattr" json:"type,omitempty"` + // Default value, if any, that the property will assume when not + // constrained by requirements. + // + // This object must be of the + // `PbmCapabilityPropertyMetadata.type` + // defined for the property. + DefaultValue types.AnyType `xml:"defaultValue,omitempty,typeattr" json:"defaultValue,omitempty"` + // All legal values that the property may take on, across all + // implementations of the property. + // + // This definition of legal values is not + // determined by any particular resource configuration; rather it is + // inherent to the definition of the property. If undefined, then any value + // of the correct type is legal. This object must be a generic container for + // the `PbmCapabilityPropertyMetadata.type` + // defined for the property; + // see `PbmBuiltinGenericType_enum` + // for the supported generic container types. + AllowedValue types.AnyType `xml:"allowedValue,omitempty,typeattr" json:"allowedValue,omitempty"` + // A hint for data-driven systems that assist in authoring requirements + // constraints. + // + // Acceptable values defined by + // `PbmBuiltinGenericType_enum`. + // A property will typically only have constraints of a given type in + // requirement profiles, even if it is likely to use constraints of + // different types across capability profiles. This value, if specified, + // specifies the expected kind of constraint used in requirement profiles. + // Considerations for using this information: + // - This is only a hint; any properly formed constraint + // (see `PbmCapabilityPropertyInstance.value`) + // is still valid for a requirement profile. + // - If VMW\_SET is hinted, then a single value matching the property metadata type is + // also an expected form of constraint, as the latter is an allowed convenience + // for expressing a single-member set. + // - If this hint is not specified, then the authoring system may default to a form of + // constraint determined by its own criteria. + RequirementsTypeHint string `xml:"requirementsTypeHint,omitempty" json:"requirementsTypeHint,omitempty"` } func init() { types.Add("pbm:PbmCapabilityPropertyMetadata", reflect.TypeOf((*PbmCapabilityPropertyMetadata)(nil)).Elem()) } +// The `PbmCapabilityRange` data object defines a range of values for storage property +// instances (`PbmCapabilityPropertyInstance`). +// +// Use the range type to define a range of values of a supported builtin type, +// for example range<int>, range<long>, or range<timespan>. +// You can specify a partial range by omitting one of the properties, min or max. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityRange struct { types.DynamicData - Min types.AnyType `xml:"min,typeattr"` - Max types.AnyType `xml:"max,typeattr"` + // Minimum value of range. + // + // Must be one of the supported + // datatypes as defined in `PbmBuiltinType_enum`. + // Must be the same datatype as min. + Min types.AnyType `xml:"min,typeattr" json:"min"` + // Maximum value of range. + // + // Must be one of the supported + // datatypes as defined in `PbmBuiltinType_enum`. + // Must be the same datatype as max. + Max types.AnyType `xml:"max,typeattr" json:"max"` } func init() { types.Add("pbm:PbmCapabilityRange", reflect.TypeOf((*PbmCapabilityRange)(nil)).Elem()) } +// Capability Schema information +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilitySchema struct { types.DynamicData - VendorInfo PbmCapabilitySchemaVendorInfo `xml:"vendorInfo"` - NamespaceInfo PbmCapabilityNamespaceInfo `xml:"namespaceInfo"` - LineOfService BasePbmLineOfServiceInfo `xml:"lineOfService,omitempty,typeattr"` - CapabilityMetadataPerCategory []PbmCapabilityMetadataPerCategory `xml:"capabilityMetadataPerCategory"` + VendorInfo PbmCapabilitySchemaVendorInfo `xml:"vendorInfo" json:"vendorInfo"` + NamespaceInfo PbmCapabilityNamespaceInfo `xml:"namespaceInfo" json:"namespaceInfo"` + // Service type for the schema. + // + // Do not use Category as each service needs to have its own schema version. + // + // If omitted, this schema specifies persistence capabilities. + LineOfService BasePbmLineOfServiceInfo `xml:"lineOfService,omitempty,typeattr" json:"lineOfService,omitempty"` + // Capability metadata organized by category + CapabilityMetadataPerCategory []PbmCapabilityMetadataPerCategory `xml:"capabilityMetadataPerCategory" json:"capabilityMetadataPerCategory"` } func init() { types.Add("pbm:PbmCapabilitySchema", reflect.TypeOf((*PbmCapabilitySchema)(nil)).Elem()) } +// Information about vendor/owner of the capability metadata schema +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilitySchemaVendorInfo struct { types.DynamicData - VendorUuid string `xml:"vendorUuid"` - Info PbmExtendedElementDescription `xml:"info"` + // Unique identifier for the vendor who owns the given capability + // schema definition + VendorUuid string `xml:"vendorUuid" json:"vendorUuid"` + // Captures name and description information about the vendor/owner of + // the schema. + // - The summary.label property + // (`PbmExtendedElementDescription.label`) + // contains vendor name information in server locale. + // - The summary.summary property + // (`PbmExtendedElementDescription.summary`) + // contains vendor description string in server locale. + // - The summary.messageCatalogKeyPrefix property + // (`PbmExtendedElementDescription.messageCatalogKeyPrefix`) + // contains unique prefix for the vendor information within given message + // catalog. + Info PbmExtendedElementDescription `xml:"info" json:"info"` } func init() { types.Add("pbm:PbmCapabilitySchemaVendorInfo", reflect.TypeOf((*PbmCapabilitySchemaVendorInfo)(nil)).Elem()) } +// A `PbmCapabilitySubProfile` +// is a section within a profile that aggregates one or more capability +// instances. +// +// Capability instances define storage constraints. +// +// All constraints within a subprofile are ANDed by default. +// When you perform compliance checking on a virtual machine or virtual +// disk, all of the constraints must be satisfied by the storage capabilities. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilitySubProfile struct { types.DynamicData - Name string `xml:"name"` - Capability []PbmCapabilityInstance `xml:"capability"` - ForceProvision *bool `xml:"forceProvision"` + // Subprofile name. + Name string `xml:"name" json:"name"` + // List of capability instances. + Capability []PbmCapabilityInstance `xml:"capability" json:"capability"` + // Indicates whether the source policy profile allows creating a virtual machine + // or virtual disk that may be non-compliant. + ForceProvision *bool `xml:"forceProvision" json:"forceProvision,omitempty"` } func init() { types.Add("pbm:PbmCapabilitySubProfile", reflect.TypeOf((*PbmCapabilitySubProfile)(nil)).Elem()) } +// The `PbmCapabilitySubProfileConstraints` data object defines a group +// of storage subprofiles. +// +// Subprofile usage depends on the type of profile +// (`PbmCapabilityProfile*.*PbmCapabilityProfile.profileCategory`). +// - For a REQUIREMENTS profile, each subprofile defines storage requirements. +// A Storage Policy API requirements subprofile corresponds to a vSphere Web Client +// rule set. +// - For a RESOURCE profile, each subprofile defines storage capabilities. +// Storage capabilities are read-only. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilitySubProfileConstraints struct { PbmCapabilityConstraints - SubProfiles []PbmCapabilitySubProfile `xml:"subProfiles"` + // Aggregation of one or more subprofiles. + // + // The relationship among all subprofiles is "OR". When you perform + // compliance checking on a profile that contains more than one subprofile, + // a non-compliant result for any one of the subprofiles will produce a + // non-compliant result for the operation. + SubProfiles []PbmCapabilitySubProfile `xml:"subProfiles" json:"subProfiles"` } func init() { types.Add("pbm:PbmCapabilitySubProfileConstraints", reflect.TypeOf((*PbmCapabilitySubProfileConstraints)(nil)).Elem()) } +// The `PbmCapabilityTimeSpan` data object defines a time value and time unit, +// for example 10 hours or 5 minutes. +// +// See +// `PbmBuiltinType_enum*.*VMW_TIMESPAN`. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityTimeSpan struct { types.DynamicData - Value int32 `xml:"value"` - Unit string `xml:"unit"` + // Time value. + // + // Must be a positive integer. + Value int32 `xml:"value" json:"value"` + // Unit value for time. + // + // The string value must correspond + // to one of the `PbmCapabilityTimeUnitType_enum` values. + Unit string `xml:"unit" json:"unit"` } func init() { types.Add("pbm:PbmCapabilityTimeSpan", reflect.TypeOf((*PbmCapabilityTimeSpan)(nil)).Elem()) } +// The `PbmCapabilityTypeInfo` data object defines the datatype for a requirement +// or capability property. +// +// See `PbmCapabilityPropertyMetadata`. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCapabilityTypeInfo struct { types.DynamicData - TypeName string `xml:"typeName"` + // Datatype for a property. + // + // Must be one of the types defined + // in `PbmBuiltinType_enum`. + // + // A property value might consist of a collection of values of the specified + // datatype. The interpretation of the collection is determined by the + // generic type (`PbmCapabilityGenericTypeInfo.genericTypeName`). + // The generic type indicates how a collection of values + // of the specified datatype will be interpreted. See the descriptions of the + // `PbmBuiltinType_enum` definitions. + TypeName string `xml:"typeName" json:"typeName"` } func init() { @@ -571,8 +1065,8 @@ func init() { type PbmCapabilityVendorNamespaceInfo struct { types.DynamicData - VendorInfo PbmCapabilitySchemaVendorInfo `xml:"vendorInfo"` - NamespaceInfo PbmCapabilityNamespaceInfo `xml:"namespaceInfo"` + VendorInfo PbmCapabilitySchemaVendorInfo `xml:"vendorInfo" json:"vendorInfo"` + NamespaceInfo PbmCapabilityNamespaceInfo `xml:"namespaceInfo" json:"namespaceInfo"` } func init() { @@ -582,8 +1076,14 @@ func init() { type PbmCapabilityVendorResourceTypeInfo struct { types.DynamicData - ResourceType string `xml:"resourceType"` - VendorNamespaceInfo []PbmCapabilityVendorNamespaceInfo `xml:"vendorNamespaceInfo"` + // Resource type for which given vendor has registered given namespace + // along with capability metadata that belongs to the namespace. + // + // Must match one of the values for enum `PbmProfileResourceTypeEnum_enum` + ResourceType string `xml:"resourceType" json:"resourceType"` + // List of all vendorInfo -- namespaceInfo tuples that are registered for + // given resource type + VendorNamespaceInfo []PbmCapabilityVendorNamespaceInfo `xml:"vendorNamespaceInfo" json:"vendorNamespaceInfo"` } func init() { @@ -596,10 +1096,16 @@ func init() { types.Add("pbm:PbmCheckCompatibility", reflect.TypeOf((*PbmCheckCompatibility)(nil)).Elem()) } +// The parameters of `PbmPlacementSolver.PbmCheckCompatibility`. type PbmCheckCompatibilityRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - HubsToSearch []PbmPlacementHub `xml:"hubsToSearch,omitempty"` - Profile PbmProfileId `xml:"profile"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Candidate list of hubs, either datastores or storage pods or a + // mix. If this parameter is not specified, the Server uses all + // of the datastores and storage pods for placement compatibility + // checking. + HubsToSearch []PbmPlacementHub `xml:"hubsToSearch,omitempty" json:"hubsToSearch,omitempty"` + // Storage requirement profile. + Profile PbmProfileId `xml:"profile" json:"profile"` } func init() { @@ -607,7 +1113,7 @@ func init() { } type PbmCheckCompatibilityResponse struct { - Returnval []PbmPlacementCompatibilityResult `xml:"returnval,omitempty"` + Returnval []PbmPlacementCompatibilityResult `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmCheckCompatibilityWithSpec PbmCheckCompatibilityWithSpecRequestType @@ -616,10 +1122,15 @@ func init() { types.Add("pbm:PbmCheckCompatibilityWithSpec", reflect.TypeOf((*PbmCheckCompatibilityWithSpec)(nil)).Elem()) } +// The parameters of `PbmPlacementSolver.PbmCheckCompatibilityWithSpec`. type PbmCheckCompatibilityWithSpecRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - HubsToSearch []PbmPlacementHub `xml:"hubsToSearch,omitempty"` - ProfileSpec PbmCapabilityProfileCreateSpec `xml:"profileSpec"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Candidate list of hubs, either datastores or storage pods + // or a mix. If this parameter is not specified, the Server uses all of the + // datastores and storage pods for placement compatibility checking. + HubsToSearch []PbmPlacementHub `xml:"hubsToSearch,omitempty" json:"hubsToSearch,omitempty"` + // Specification for a capability based profile. + ProfileSpec PbmCapabilityProfileCreateSpec `xml:"profileSpec" json:"profileSpec"` } func init() { @@ -627,7 +1138,7 @@ func init() { } type PbmCheckCompatibilityWithSpecResponse struct { - Returnval []PbmPlacementCompatibilityResult `xml:"returnval,omitempty"` + Returnval []PbmPlacementCompatibilityResult `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmCheckCompliance PbmCheckComplianceRequestType @@ -636,10 +1147,31 @@ func init() { types.Add("pbm:PbmCheckCompliance", reflect.TypeOf((*PbmCheckCompliance)(nil)).Elem()) } +// The parameters of `PbmComplianceManager.PbmCheckCompliance`. type PbmCheckComplianceRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Entities []PbmServerObjectRef `xml:"entities"` - Profile *PbmProfileId `xml:"profile,omitempty"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // One or more references to storage entities. + // You can specify virtual machines and virtual disks + // A maximum of 1000 virtual machines and/or virtual disks can be specified + // in a call. The results of calling the checkCompliance API with + // more than a 1000 entities is undefined. + // - If the list of entities also contains datastores, the Server + // will ignore the datastores. + // - If the list contains valid and invalid entities, the Server ignores + // the invalid entities and returns results for the valid entities. + // Invalid entities are entities that are not in the vCenter inventory. + // - If the list contains only datastores, the method throws + // an InvalidArgument fault. + // - If the list contains virtual machines and disks and the entities + // are invalid or have been deleted by the time of the request, the method + // throws an InvalidArgument fault. + // + // If an entity does not have an associated storage profile, the entity + // is removed from the list. + Entities []PbmServerObjectRef `xml:"entities" json:"entities"` + // Not used. If specified, the Server ignores the value. + // The Server uses the profiles associated with the specified entities. + Profile *PbmProfileId `xml:"profile,omitempty" json:"profile,omitempty"` } func init() { @@ -647,7 +1179,7 @@ func init() { } type PbmCheckComplianceResponse struct { - Returnval []PbmComplianceResult `xml:"returnval,omitempty"` + Returnval []PbmComplianceResult `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmCheckRequirements PbmCheckRequirementsRequestType @@ -656,11 +1188,27 @@ func init() { types.Add("pbm:PbmCheckRequirements", reflect.TypeOf((*PbmCheckRequirements)(nil)).Elem()) } +// The parameters of `PbmPlacementSolver.PbmCheckRequirements`. type PbmCheckRequirementsRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - HubsToSearch []PbmPlacementHub `xml:"hubsToSearch,omitempty"` - PlacementSubjectRef *PbmServerObjectRef `xml:"placementSubjectRef,omitempty"` - PlacementSubjectRequirement []BasePbmPlacementRequirement `xml:"placementSubjectRequirement,omitempty,typeattr"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Candidate list of hubs, either datastores or storage pods + // or a mix. If this parameter is not specified, the Server uses all of the + // datastores and storage pods for placement compatibility checking. + HubsToSearch []PbmPlacementHub `xml:"hubsToSearch,omitempty" json:"hubsToSearch,omitempty"` + // reference to the object being placed. Should be null when a new + // object is being provisioned. Should be specified when placement compatibility is being checked + // for an existing object. Supported objects are + // `virtualMachine`, + // `virtualMachineAndDisks`, + // `virtualDiskId`, + // `virtualDiskUUID` + PlacementSubjectRef *PbmServerObjectRef `xml:"placementSubjectRef,omitempty" json:"placementSubjectRef,omitempty"` + // Requirements including the policy requirements, compute + // requirements and capacity requirements. It is invalid to specify no requirements. It is also + // invalid to specify duplicate requirements or multiple conflicting requirements such as + // specifying both `PbmPlacementCapabilityConstraintsRequirement` and + // `PbmPlacementCapabilityProfileRequirement`. + PlacementSubjectRequirement []BasePbmPlacementRequirement `xml:"placementSubjectRequirement,omitempty,typeattr" json:"placementSubjectRequirement,omitempty"` } func init() { @@ -668,7 +1216,7 @@ func init() { } type PbmCheckRequirementsResponse struct { - Returnval []PbmPlacementCompatibilityResult `xml:"returnval,omitempty"` + Returnval []PbmPlacementCompatibilityResult `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmCheckRollupCompliance PbmCheckRollupComplianceRequestType @@ -677,9 +1225,14 @@ func init() { types.Add("pbm:PbmCheckRollupCompliance", reflect.TypeOf((*PbmCheckRollupCompliance)(nil)).Elem()) } +// The parameters of `PbmComplianceManager.PbmCheckRollupCompliance`. type PbmCheckRollupComplianceRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Entity []PbmServerObjectRef `xml:"entity"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // One or more references to virtual machines. + // A maximum of 1000 virtual machines can be specified + // in a call. The results of calling the checkRollupCompliance API with + // more than a 1000 entities is undefined. + Entity []PbmServerObjectRef `xml:"entity" json:"entity"` } func init() { @@ -687,13 +1240,17 @@ func init() { } type PbmCheckRollupComplianceResponse struct { - Returnval []PbmRollupComplianceResult `xml:"returnval,omitempty"` + Returnval []PbmRollupComplianceResult `xml:"returnval,omitempty" json:"returnval,omitempty"` } +// Super class for all compatibility check faults. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCompatibilityCheckFault struct { PbmFault - Hub PbmPlacementHub `xml:"hub"` + // Placement Hub + Hub PbmPlacementHub `xml:"hub" json:"hub"` } func init() { @@ -706,43 +1263,124 @@ func init() { types.Add("pbm:PbmCompatibilityCheckFaultFault", reflect.TypeOf((*PbmCompatibilityCheckFaultFault)(nil)).Elem()) } +// Additional information on the effects of backend resources and +// operations on the storage object. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmComplianceOperationalStatus struct { types.DynamicData - Healthy *bool `xml:"healthy"` - OperationETA *time.Time `xml:"operationETA"` - OperationProgress int64 `xml:"operationProgress,omitempty"` - Transitional *bool `xml:"transitional"` + // Whether the object is currently affected by the failure of backend + // storage resources. + // + // Optional property. + Healthy *bool `xml:"healthy" json:"healthy,omitempty"` + // Estimated completion time of a backend operation affecting the object. + // + // If set, then "transitional" will be true. + // Optional property. + OperationETA *time.Time `xml:"operationETA" json:"operationETA,omitempty"` + // Percent progress of a backend operation affecting the object. + // + // If set, then "transitional" will be true. + // Optional property. + OperationProgress int64 `xml:"operationProgress,omitempty" json:"operationProgress,omitempty"` + // Whether an object is undergoing a backend operation that may affect + // its performance. + // + // This may be a rebalancing the resources of a healthy + // object or recovery tasks for an unhealthy object. + // Optional property. + Transitional *bool `xml:"transitional" json:"transitional,omitempty"` } func init() { types.Add("pbm:PbmComplianceOperationalStatus", reflect.TypeOf((*PbmComplianceOperationalStatus)(nil)).Elem()) } +// The `PbmCompliancePolicyStatus` data object provides information +// when compliance checking produces non-compliant results. +// +// See +// `PbmComplianceResult*.*PbmComplianceResult.violatedPolicies`. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmCompliancePolicyStatus struct { types.DynamicData - ExpectedValue PbmCapabilityInstance `xml:"expectedValue"` - CurrentValue *PbmCapabilityInstance `xml:"currentValue,omitempty"` + // Expected storage capability values of profile policies defined + // by a storage provider. + ExpectedValue PbmCapabilityInstance `xml:"expectedValue" json:"expectedValue"` + // Current storage requirement values of the profile policies + // specified for the virtual machine or virtual disk. + CurrentValue *PbmCapabilityInstance `xml:"currentValue,omitempty" json:"currentValue,omitempty"` } func init() { types.Add("pbm:PbmCompliancePolicyStatus", reflect.TypeOf((*PbmCompliancePolicyStatus)(nil)).Elem()) } +// The `PbmComplianceResult` data object describes the results of profile compliance +// checking for a virtual machine or virtual disk. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmComplianceResult struct { types.DynamicData - CheckTime time.Time `xml:"checkTime"` - Entity PbmServerObjectRef `xml:"entity"` - Profile *PbmProfileId `xml:"profile,omitempty"` - ComplianceTaskStatus string `xml:"complianceTaskStatus,omitempty"` - ComplianceStatus string `xml:"complianceStatus"` - Mismatch bool `xml:"mismatch"` - ViolatedPolicies []PbmCompliancePolicyStatus `xml:"violatedPolicies,omitempty"` - ErrorCause []types.LocalizedMethodFault `xml:"errorCause,omitempty"` - OperationalStatus *PbmComplianceOperationalStatus `xml:"operationalStatus,omitempty"` - Info *PbmExtendedElementDescription `xml:"info,omitempty"` + // Time when the compliance was checked. + CheckTime time.Time `xml:"checkTime" json:"checkTime"` + // Virtual machine or virtual disk for which compliance was checked. + Entity PbmServerObjectRef `xml:"entity" json:"entity"` + // Requirement profile with which the compliance was checked. + Profile *PbmProfileId `xml:"profile,omitempty" json:"profile,omitempty"` + // Status of the current running compliance operation. + // + // If there is no + // compliance check operation triggered, this indicates the last compliance + // task status. complianceTaskStatus is a string value that + // corresponds to one of the + // `PbmComplianceResultComplianceTaskStatus_enum` values. + ComplianceTaskStatus string `xml:"complianceTaskStatus,omitempty" json:"complianceTaskStatus,omitempty"` + // Status of the compliance operation. + // + // complianceStatus is a + // string value that corresponds to one of the + // `PbmComplianceStatus_enum` values. + // + // When you perform compliance checking on an entity whose associated profile + // contains more than one subprofile ( + // `PbmCapabilityProfile` . + // `PbmCapabilityProfile.constraints`), a compliant + // result for any one of the subprofiles will produce a compliant result + // for the operation. + ComplianceStatus string `xml:"complianceStatus" json:"complianceStatus"` + // Deprecated as of vSphere 2016, use + // `PbmComplianceStatus_enum` to + // know if a mismatch has occurred. If + // `PbmComplianceResult.complianceStatus` value + // is outOfDate, mismatch has occurred. + // + // Set to true if there is a profile version mismatch between the Storage + // Profile Server and the storage provider. + // + // If you receive a result that + // indicates a mismatch, you must use the vSphere API to update the profile + // associated with the virtual machine or virtual disk. + Mismatch bool `xml:"mismatch" json:"mismatch"` + // Values for capabilities that are known to be non-compliant with the specified constraints. + ViolatedPolicies []PbmCompliancePolicyStatus `xml:"violatedPolicies,omitempty" json:"violatedPolicies,omitempty"` + // This property is set if the compliance task fails with errors. + // + // There can be + // more than one error since a policy containing multiple blobs can return + // multiple failures, one for each blob. + ErrorCause []types.LocalizedMethodFault `xml:"errorCause,omitempty" json:"errorCause,omitempty"` + // Additional information on the effects of backend resources and + // operations on the storage object. + OperationalStatus *PbmComplianceOperationalStatus `xml:"operationalStatus,omitempty" json:"operationalStatus,omitempty"` + // Informational localized messages provided by the VASA provider in + // addition to the violatedPolicy. + Info *PbmExtendedElementDescription `xml:"info,omitempty" json:"info,omitempty"` } func init() { @@ -755,9 +1393,11 @@ func init() { types.Add("pbm:PbmCreate", reflect.TypeOf((*PbmCreate)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmCreate`. type PbmCreateRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - CreateSpec PbmCapabilityProfileCreateSpec `xml:"createSpec"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Capability-based profile specification. + CreateSpec PbmCapabilityProfileCreateSpec `xml:"createSpec" json:"createSpec"` } func init() { @@ -765,48 +1405,87 @@ func init() { } type PbmCreateResponse struct { - Returnval PbmProfileId `xml:"returnval"` + Returnval PbmProfileId `xml:"returnval" json:"returnval"` } +// DataServiceToProfilesMap maps the data service policy to the parent storage policies +// if referred. +// +// This is returned from the API call +// `ProfileManager#queryParentStoragePolicies(ProfileId[])` +// +// This structure may be used only with operations rendered under `/pbm`. type PbmDataServiceToPoliciesMap struct { types.DynamicData - DataServicePolicy PbmProfileId `xml:"dataServicePolicy"` - ParentStoragePolicies []PbmProfileId `xml:"parentStoragePolicies,omitempty"` - Fault *types.LocalizedMethodFault `xml:"fault,omitempty"` + // Denotes a Data Service Policy Id. + DataServicePolicy PbmProfileId `xml:"dataServicePolicy" json:"dataServicePolicy"` + // Storage Policies that refer to the Data Service Policy given by + // `PbmDataServiceToPoliciesMap.dataServicePolicy`. + ParentStoragePolicies []PbmProfileId `xml:"parentStoragePolicies,omitempty" json:"parentStoragePolicies,omitempty"` + // The fault is set in case of error conditions and this property will + // have the reason. + Fault *types.LocalizedMethodFault `xml:"fault,omitempty" json:"fault,omitempty"` } func init() { types.Add("pbm:PbmDataServiceToPoliciesMap", reflect.TypeOf((*PbmDataServiceToPoliciesMap)(nil)).Elem()) } +// Space stats for datastore +// +// This structure may be used only with operations rendered under `/pbm`. type PbmDatastoreSpaceStatistics struct { types.DynamicData - ProfileId string `xml:"profileId,omitempty"` - PhysicalTotalInMB int64 `xml:"physicalTotalInMB"` - PhysicalFreeInMB int64 `xml:"physicalFreeInMB"` - PhysicalUsedInMB int64 `xml:"physicalUsedInMB"` - LogicalLimitInMB int64 `xml:"logicalLimitInMB,omitempty"` - LogicalFreeInMB int64 `xml:"logicalFreeInMB"` - LogicalUsedInMB int64 `xml:"logicalUsedInMB"` + // Capability profile id. + // + // It is null when the statistics are for the entire + // datastore. + ProfileId string `xml:"profileId,omitempty" json:"profileId,omitempty"` + // Total physical space in MB. + PhysicalTotalInMB int64 `xml:"physicalTotalInMB" json:"physicalTotalInMB"` + // Total physical free space in MB. + PhysicalFreeInMB int64 `xml:"physicalFreeInMB" json:"physicalFreeInMB"` + // Used physical storage space in MB. + PhysicalUsedInMB int64 `xml:"physicalUsedInMB" json:"physicalUsedInMB"` + // Logical space limit set by the storage admin in MB. + // + // Omitted if there is no Logical space limit. + LogicalLimitInMB int64 `xml:"logicalLimitInMB,omitempty" json:"logicalLimitInMB,omitempty"` + // Free logical storage space in MB. + LogicalFreeInMB int64 `xml:"logicalFreeInMB" json:"logicalFreeInMB"` + // Used logical storage space in MB. + LogicalUsedInMB int64 `xml:"logicalUsedInMB" json:"logicalUsedInMB"` } func init() { types.Add("pbm:PbmDatastoreSpaceStatistics", reflect.TypeOf((*PbmDatastoreSpaceStatistics)(nil)).Elem()) } +// Not supported in this release. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmDefaultCapabilityProfile struct { PbmCapabilityProfile - VvolType []string `xml:"vvolType"` - ContainerId string `xml:"containerId"` + // Not supported in this release. + VvolType []string `xml:"vvolType" json:"vvolType"` + // Not supported in this release. + ContainerId string `xml:"containerId" json:"containerId"` } func init() { types.Add("pbm:PbmDefaultCapabilityProfile", reflect.TypeOf((*PbmDefaultCapabilityProfile)(nil)).Elem()) } +// Warning fault used to indicate that the vendor specific datastore matches the tag in the +// requirements profile that does not have a vendor specific rule set. +// +// In such case, +// an empty blob is sent to the vendor specific datastore and the default profile would apply. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmDefaultProfileAppliesFault struct { PbmCompatibilityCheckFault } @@ -821,11 +1500,20 @@ func init() { types.Add("pbm:PbmDefaultProfileAppliesFaultFault", reflect.TypeOf((*PbmDefaultProfileAppliesFaultFault)(nil)).Elem()) } +// Data structure that stores the default profile for datastores. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmDefaultProfileInfo struct { types.DynamicData - Datastores []PbmPlacementHub `xml:"datastores"` - DefaultProfile BasePbmProfile `xml:"defaultProfile,omitempty,typeattr"` + // Datastores + Datastores []PbmPlacementHub `xml:"datastores" json:"datastores"` + // Default requirements profile. + // + // It is set to null if the datastores are not associated with any default profile. + DefaultProfile BasePbmProfile `xml:"defaultProfile,omitempty,typeattr" json:"defaultProfile,omitempty"` + // NoPermission fault if default profile is not permitted. + MethodFault *types.LocalizedMethodFault `xml:"methodFault,omitempty" json:"methodFault,omitempty"` } func init() { @@ -838,9 +1526,11 @@ func init() { types.Add("pbm:PbmDelete", reflect.TypeOf((*PbmDelete)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmDelete`. type PbmDeleteRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - ProfileId []PbmProfileId `xml:"profileId"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Array of profile identifiers. + ProfileId []PbmProfileId `xml:"profileId" json:"profileId"` } func init() { @@ -848,13 +1538,18 @@ func init() { } type PbmDeleteResponse struct { - Returnval []PbmProfileOperationOutcome `xml:"returnval,omitempty"` + Returnval []PbmProfileOperationOutcome `xml:"returnval,omitempty" json:"returnval,omitempty"` } +// A DuplicateName exception is thrown because a name already exists +// in the same name space. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmDuplicateName struct { PbmFault - Name string `xml:"name"` + // The name that is already bound in the name space. + Name string `xml:"name" json:"name"` } func init() { @@ -870,17 +1565,38 @@ func init() { type PbmExtendedElementDescription struct { types.DynamicData - Label string `xml:"label"` - Summary string `xml:"summary"` - Key string `xml:"key"` - MessageCatalogKeyPrefix string `xml:"messageCatalogKeyPrefix"` - MessageArg []types.KeyAnyValue `xml:"messageArg,omitempty"` + // Display label. + Label string `xml:"label" json:"label"` + // Summary description. + Summary string `xml:"summary" json:"summary"` + // Enumeration or literal ID being described. + Key string `xml:"key" json:"key"` + // Key to the localized message string in the catalog. + // + // If the localized string contains parameters, values to the + // parameters will be provided in #messageArg. + // E.g: If the message in the catalog is + // "IP address is {address}", value for "address" + // will be provided by #messageArg. + // Both summary and label in ElementDescription will have a corresponding + // entry in the message catalog with the keys + // .summary and .label + // respectively. + // ElementDescription.summary and ElementDescription.label will contain + // the strings in server locale. + MessageCatalogKeyPrefix string `xml:"messageCatalogKeyPrefix" json:"messageCatalogKeyPrefix"` + // Provides named arguments that can be used to localize the + // message in the catalog. + MessageArg []types.KeyAnyValue `xml:"messageArg,omitempty" json:"messageArg,omitempty"` } func init() { types.Add("pbm:PbmExtendedElementDescription", reflect.TypeOf((*PbmExtendedElementDescription)(nil)).Elem()) } +// The super class for all pbm faults. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmFault struct { types.MethodFault } @@ -895,6 +1611,10 @@ func init() { types.Add("pbm:PbmFaultFault", reflect.TypeOf((*PbmFaultFault)(nil)).Elem()) } +// Thrown when login fails due to token not provided or token could not be +// validated. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmFaultInvalidLogin struct { PbmFault } @@ -909,17 +1629,51 @@ func init() { types.Add("pbm:PbmFaultInvalidLoginFault", reflect.TypeOf((*PbmFaultInvalidLoginFault)(nil)).Elem()) } +// Thrown when an operation is denied because of a privilege +// not held on a storage profile. +// +// This structure may be used only with operations rendered under `/pbm`. +type PbmFaultNoPermission struct { + types.SecurityError + + // List of profile ids and missing privileges for each profile + MissingPrivileges []PbmFaultNoPermissionEntityPrivileges `xml:"missingPrivileges,omitempty" json:"missingPrivileges,omitempty"` +} + +func init() { + types.Add("pbm:PbmFaultNoPermission", reflect.TypeOf((*PbmFaultNoPermission)(nil)).Elem()) +} + type PbmFaultNoPermissionEntityPrivileges struct { types.DynamicData - ProfileId *PbmProfileId `xml:"profileId,omitempty"` - PrivilegeIds []string `xml:"privilegeIds,omitempty"` + ProfileId *PbmProfileId `xml:"profileId,omitempty" json:"profileId,omitempty"` + PrivilegeIds []string `xml:"privilegeIds,omitempty" json:"privilegeIds,omitempty"` } func init() { types.Add("pbm:PbmFaultNoPermissionEntityPrivileges", reflect.TypeOf((*PbmFaultNoPermissionEntityPrivileges)(nil)).Elem()) } +type PbmFaultNoPermissionFault PbmFaultNoPermission + +func init() { + types.Add("pbm:PbmFaultNoPermissionFault", reflect.TypeOf((*PbmFaultNoPermissionFault)(nil)).Elem()) +} + +// A NotFound error occurs when a referenced component of a managed +// object cannot be found. +// +// The referenced component can be a data +// object type (such as a role or permission) or a primitive +// (such as a string). +// +// For example, if the missing referenced component is a data object, such as +// VirtualSwitch, the NotFound error is +// thrown. The NotFound error is also thrown if the data object is found, but the referenced name +// (for example, "vswitch0") is not. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmFaultNotFound struct { PbmFault } @@ -954,10 +1708,19 @@ func init() { types.Add("pbm:PbmFetchCapabilityMetadata", reflect.TypeOf((*PbmFetchCapabilityMetadata)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmFetchCapabilityMetadata`. type PbmFetchCapabilityMetadataRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - ResourceType *PbmProfileResourceType `xml:"resourceType,omitempty"` - VendorUuid string `xml:"vendorUuid,omitempty"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Type of profile resource. The Server supports the "STORAGE" resource + // type only. If not specified, this method will return capability metadata for the storage + // resources. Any other resourceType is considered invalid. + ResourceType *PbmProfileResourceType `xml:"resourceType,omitempty" json:"resourceType,omitempty"` + // Unique identifier for the vendor/owner of capability + // metadata. The specified vendor ID must match + // `PbmCapabilitySchemaVendorInfo*.*PbmCapabilitySchemaVendorInfo.vendorUuid`. + // If omitted, the Server searchs all capability metadata registered with the system. If a + // vendorUuid unknown to the Server is specified, empty results will be returned. + VendorUuid string `xml:"vendorUuid,omitempty" json:"vendorUuid,omitempty"` } func init() { @@ -965,7 +1728,7 @@ func init() { } type PbmFetchCapabilityMetadataResponse struct { - Returnval []PbmCapabilityMetadataPerCategory `xml:"returnval,omitempty"` + Returnval []PbmCapabilityMetadataPerCategory `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmFetchCapabilitySchema PbmFetchCapabilitySchemaRequestType @@ -974,10 +1737,20 @@ func init() { types.Add("pbm:PbmFetchCapabilitySchema", reflect.TypeOf((*PbmFetchCapabilitySchema)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmFetchCapabilitySchema`. type PbmFetchCapabilitySchemaRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - VendorUuid string `xml:"vendorUuid,omitempty"` - LineOfService []string `xml:"lineOfService,omitempty"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Unique identifier for the vendor/owner of capability metadata. + // If omitted, the server searchs all capability metadata registered + // with the system. The specified vendor ID must match + // `PbmCapabilitySchemaVendorInfo*.*PbmCapabilitySchemaVendorInfo.vendorUuid`. + VendorUuid string `xml:"vendorUuid,omitempty" json:"vendorUuid,omitempty"` + // Optional line of service that must match `PbmLineOfServiceInfoLineOfServiceEnum_enum`. + // If specified, the capability schema objects + // are returned for the given lineOfServices. If null, then all + // capability schema objects that may or may not have data service capabilities + // are returned. + LineOfService []string `xml:"lineOfService,omitempty" json:"lineOfService,omitempty"` } func init() { @@ -985,7 +1758,7 @@ func init() { } type PbmFetchCapabilitySchemaResponse struct { - Returnval []PbmCapabilitySchema `xml:"returnval,omitempty"` + Returnval []PbmCapabilitySchema `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmFetchComplianceResult PbmFetchComplianceResultRequestType @@ -994,10 +1767,24 @@ func init() { types.Add("pbm:PbmFetchComplianceResult", reflect.TypeOf((*PbmFetchComplianceResult)(nil)).Elem()) } +// The parameters of `PbmComplianceManager.PbmFetchComplianceResult`. type PbmFetchComplianceResultRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Entities []PbmServerObjectRef `xml:"entities"` - Profile *PbmProfileId `xml:"profile,omitempty"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // One or more references to storage entities. + // A maximum of 1000 virtual machines and/or virtual disks can be specified + // in a call. The results of calling the fetchComplianceResult API with + // more than a 1000 entities is undefined. + // - If the list of entities also contains datastores, the Server + // will ignore the datastores. + // - If the list contains valid and invalid entities, the Server ignores + // the invalid entities and returns results for the valid entities. + // Invalid entities are entities that are not in the vCenter inventory. + // - If the list contains only datastores, the method throws + // an InvalidArgument fault. + Entities []PbmServerObjectRef `xml:"entities" json:"entities"` + // Not used. if specified, the Server ignores the value. + // The Server uses the profiles associated with the specified entities. + Profile *PbmProfileId `xml:"profile,omitempty" json:"profile,omitempty"` } func init() { @@ -1005,14 +1792,22 @@ func init() { } type PbmFetchComplianceResultResponse struct { - Returnval []PbmComplianceResult `xml:"returnval,omitempty"` + Returnval []PbmComplianceResult `xml:"returnval,omitempty" json:"returnval,omitempty"` } +// The `PbmFetchEntityHealthStatusSpec` data object contains +// the arguments required for +// `PbmComplianceManager.PbmFetchEntityHealthStatusExt`. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmFetchEntityHealthStatusSpec struct { types.DynamicData - ObjectRef PbmServerObjectRef `xml:"objectRef"` - BackingId string `xml:"backingId,omitempty"` + // `PbmServerObjectRef` for which the healthStatus is required + ObjectRef PbmServerObjectRef `xml:"objectRef" json:"objectRef"` + // BackingId for the ServerObjectRef + // BackingId is mandatory for FCD on vSAN + BackingId string `xml:"backingId,omitempty" json:"backingId,omitempty"` } func init() { @@ -1026,7 +1821,7 @@ func init() { } type PbmFetchResourceTypeRequestType struct { - This types.ManagedObjectReference `xml:"_this"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` } func init() { @@ -1034,7 +1829,7 @@ func init() { } type PbmFetchResourceTypeResponse struct { - Returnval []PbmProfileResourceType `xml:"returnval,omitempty"` + Returnval []PbmProfileResourceType `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmFetchRollupComplianceResult PbmFetchRollupComplianceResultRequestType @@ -1043,9 +1838,14 @@ func init() { types.Add("pbm:PbmFetchRollupComplianceResult", reflect.TypeOf((*PbmFetchRollupComplianceResult)(nil)).Elem()) } +// The parameters of `PbmComplianceManager.PbmFetchRollupComplianceResult`. type PbmFetchRollupComplianceResultRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Entity []PbmServerObjectRef `xml:"entity"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // One or more virtual machines. + // A maximum of 1000 virtual machines can be specified + // in a call. The results of calling the fetchRollupComplianceResult API with + // more than a 1000 entity objects is undefined. + Entity []PbmServerObjectRef `xml:"entity" json:"entity"` } func init() { @@ -1053,7 +1853,7 @@ func init() { } type PbmFetchRollupComplianceResultResponse struct { - Returnval []PbmRollupComplianceResult `xml:"returnval,omitempty"` + Returnval []PbmRollupComplianceResult `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmFetchVendorInfo PbmFetchVendorInfoRequestType @@ -1062,9 +1862,13 @@ func init() { types.Add("pbm:PbmFetchVendorInfo", reflect.TypeOf((*PbmFetchVendorInfo)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmFetchVendorInfo`. type PbmFetchVendorInfoRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - ResourceType *PbmProfileResourceType `xml:"resourceType,omitempty"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Specifies the resource type. The Server supports the STORAGE resource + // type only. If not specified, server defaults to STORAGE resource type. Any other + // resourceType is considered invalid. + ResourceType *PbmProfileResourceType `xml:"resourceType,omitempty" json:"resourceType,omitempty"` } func init() { @@ -1072,7 +1876,7 @@ func init() { } type PbmFetchVendorInfoResponse struct { - Returnval []PbmCapabilityVendorResourceTypeInfo `xml:"returnval,omitempty"` + Returnval []PbmCapabilityVendorResourceTypeInfo `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmFindApplicableDefaultProfile PbmFindApplicableDefaultProfileRequestType @@ -1081,9 +1885,12 @@ func init() { types.Add("pbm:PbmFindApplicableDefaultProfile", reflect.TypeOf((*PbmFindApplicableDefaultProfile)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmFindApplicableDefaultProfile`. type PbmFindApplicableDefaultProfileRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Datastores []PbmPlacementHub `xml:"datastores"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Datastores for which the default profile is found out. Note that + // the datastore pods/clusters are not supported. + Datastores []PbmPlacementHub `xml:"datastores" json:"datastores"` } func init() { @@ -1091,9 +1898,13 @@ func init() { } type PbmFindApplicableDefaultProfileResponse struct { - Returnval []BasePbmProfile `xml:"returnval,omitempty,typeattr"` + Returnval []BasePbmProfile `xml:"returnval,omitempty,typeattr" json:"returnval,omitempty"` } +// Warning fault used to indicate that the vendor specific datastore matches the tag in the +// requirements profile but doesnt match the vendor specific rule set in the requirements profile. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmIncompatibleVendorSpecificRuleSet struct { PbmCapabilityProfilePropertyMismatchFault } @@ -1108,10 +1919,19 @@ func init() { types.Add("pbm:PbmIncompatibleVendorSpecificRuleSetFault", reflect.TypeOf((*PbmIncompatibleVendorSpecificRuleSetFault)(nil)).Elem()) } +// LegacyHubsNotSupported fault is thrown to indicate the legacy hubs that are not supported. +// +// For storage, legacy hubs or datastores are VMFS and NFS datastores. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmLegacyHubsNotSupported struct { PbmFault - Hubs []PbmPlacementHub `xml:"hubs"` + // Legacy hubs that are not supported. + // + // Only datastores will be populated in this fault. Datastore clusters + // are not allowed. + Hubs []PbmPlacementHub `xml:"hubs" json:"hubs"` } func init() { @@ -1124,12 +1944,21 @@ func init() { types.Add("pbm:PbmLegacyHubsNotSupportedFault", reflect.TypeOf((*PbmLegacyHubsNotSupportedFault)(nil)).Elem()) } +// Describes Line of Service of a capability provider. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmLineOfServiceInfo struct { types.DynamicData - LineOfService string `xml:"lineOfService"` - Name PbmExtendedElementDescription `xml:"name"` - Description *PbmExtendedElementDescription `xml:"description,omitempty"` + // `PbmLineOfServiceInfoLineOfServiceEnum_enum` - must be one of the values + // for enum `PbmLineOfServiceInfoLineOfServiceEnum_enum`. + LineOfService string `xml:"lineOfService" json:"lineOfService"` + // Name of the service - for informational + // purposes only. + Name PbmExtendedElementDescription `xml:"name" json:"name"` + // Description of the service - for informational + // purposes only. + Description *PbmExtendedElementDescription `xml:"description,omitempty" json:"description,omitempty"` } func init() { @@ -1139,18 +1968,22 @@ func init() { type PbmLoggingConfiguration struct { types.DynamicData - Component string `xml:"component"` - LogLevel string `xml:"logLevel"` + Component string `xml:"component" json:"component"` + LogLevel string `xml:"logLevel" json:"logLevel"` } func init() { types.Add("pbm:PbmLoggingConfiguration", reflect.TypeOf((*PbmLoggingConfiguration)(nil)).Elem()) } +// NonExistentHubs is thrown to indicate that some non existent datastores are used. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmNonExistentHubs struct { PbmFault - Hubs []PbmPlacementHub `xml:"hubs"` + // Legacy hubs that do not exist. + Hubs []PbmPlacementHub `xml:"hubs" json:"hubs"` } func init() { @@ -1163,72 +1996,140 @@ func init() { types.Add("pbm:PbmNonExistentHubsFault", reflect.TypeOf((*PbmNonExistentHubsFault)(nil)).Elem()) } +// Describes the data services provided by the storage arrays. +// +// In addition to storing bits, some VASA providers may also want to separate +// their capabilities into lines of service to let vSphere manage finer grain +// policies. For example an array may support replication natively, and may +// want vSphere policies to be defined for the replication aspect separately +// and compose them with persistence related policies. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmPersistenceBasedDataServiceInfo struct { PbmLineOfServiceInfo - CompatiblePersistenceSchemaNamespace []string `xml:"compatiblePersistenceSchemaNamespace,omitempty"` + // This property should be set with compatible schema namespaces exposed by + // the vendor provider. + // + // If not specified, vSphere assumes all Data Service + // provider schemas are compatible with all persistence provider namespaces + // advertised by the VASA provider. + CompatiblePersistenceSchemaNamespace []string `xml:"compatiblePersistenceSchemaNamespace,omitempty" json:"compatiblePersistenceSchemaNamespace,omitempty"` } func init() { types.Add("pbm:PbmPersistenceBasedDataServiceInfo", reflect.TypeOf((*PbmPersistenceBasedDataServiceInfo)(nil)).Elem()) } +// Requirement type containing capability constraints +// +// This structure may be used only with operations rendered under `/pbm`. type PbmPlacementCapabilityConstraintsRequirement struct { PbmPlacementRequirement - Constraints BasePbmCapabilityConstraints `xml:"constraints,typeattr"` + // Capability constraints + Constraints BasePbmCapabilityConstraints `xml:"constraints,typeattr" json:"constraints"` } func init() { types.Add("pbm:PbmPlacementCapabilityConstraintsRequirement", reflect.TypeOf((*PbmPlacementCapabilityConstraintsRequirement)(nil)).Elem()) } +// A Requirement for a particular `PbmCapabilityProfile`. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmPlacementCapabilityProfileRequirement struct { PbmPlacementRequirement - ProfileId PbmProfileId `xml:"profileId"` + // Reference to the capability profile being used as a requirement + ProfileId PbmProfileId `xml:"profileId" json:"profileId"` } func init() { types.Add("pbm:PbmPlacementCapabilityProfileRequirement", reflect.TypeOf((*PbmPlacementCapabilityProfileRequirement)(nil)).Elem()) } +// The `PbmPlacementCompatibilityResult` data object +// contains the compatibility result of a placement request. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmPlacementCompatibilityResult struct { types.DynamicData - Hub PbmPlacementHub `xml:"hub"` - MatchingResources []BasePbmPlacementMatchingResources `xml:"matchingResources,omitempty,typeattr"` - HowMany int64 `xml:"howMany,omitempty"` - Utilization []PbmPlacementResourceUtilization `xml:"utilization,omitempty"` - Warning []types.LocalizedMethodFault `xml:"warning,omitempty"` - Error []types.LocalizedMethodFault `xml:"error,omitempty"` + // The Datastore or StoragePod under consideration + // as a location for virtual machine files. + Hub PbmPlacementHub `xml:"hub" json:"hub"` + // Resources that match the policy. + // + // If populated, signifies that there are + // specific resources that match the policy for `PbmPlacementCompatibilityResult.hub`. If null, + // signifies that all resources (for example, hosts connected to the + // datastore or storage pod) are compatible. + MatchingResources []BasePbmPlacementMatchingResources `xml:"matchingResources,omitempty,typeattr" json:"matchingResources,omitempty"` + // How many objects of the kind requested can be provisioned on this + // `PbmPlacementCompatibilityResult.hub`. + HowMany int64 `xml:"howMany,omitempty" json:"howMany,omitempty"` + // This field is not populated if there is no size in the query, i.e. + // + // if the request carries only policy and no size requirements, this + // will not be populated. + Utilization []PbmPlacementResourceUtilization `xml:"utilization,omitempty" json:"utilization,omitempty"` + // Array of faults that describe issues that may affect profile compatibility. + // + // Users should consider these issues before using this Datastore + // or StoragePod and a connected Hosts. + Warning []types.LocalizedMethodFault `xml:"warning,omitempty" json:"warning,omitempty"` + // Array of faults that prevent this datastore or storage pod from being compatible with the + // specified profile, including if no host connected to this `PbmPlacementCompatibilityResult.hub` is compatible. + Error []types.LocalizedMethodFault `xml:"error,omitempty" json:"error,omitempty"` } func init() { types.Add("pbm:PbmPlacementCompatibilityResult", reflect.TypeOf((*PbmPlacementCompatibilityResult)(nil)).Elem()) } +// A `PbmPlacementHub` data object identifies a storage location +// where virtual machine files can be placed. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmPlacementHub struct { types.DynamicData - HubType string `xml:"hubType"` - HubId string `xml:"hubId"` + // Type of the hub. + // + // Currently ManagedObject is the only supported type. + HubType string `xml:"hubType" json:"hubType"` + // Hub identifier; a ManagedObjectReference to a datastore or a storage pod. + HubId string `xml:"hubId" json:"hubId"` } func init() { types.Add("pbm:PbmPlacementHub", reflect.TypeOf((*PbmPlacementHub)(nil)).Elem()) } +// Describes the collection of replication related resources that satisfy a +// policy, for a specific datastore. +// +// This class is returned only when the policy contains replication capabilities. +// For a storage pod, only those replication groups that are common across +// all datastores in the storage pod are considered compatible. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmPlacementMatchingReplicationResources struct { PbmPlacementMatchingResources - ReplicationGroup []types.ReplicationGroupId `xml:"replicationGroup,omitempty"` + // Replication groups that match the policy. + ReplicationGroup []types.ReplicationGroupId `xml:"replicationGroup,omitempty" json:"replicationGroup,omitempty"` } func init() { types.Add("pbm:PbmPlacementMatchingReplicationResources", reflect.TypeOf((*PbmPlacementMatchingReplicationResources)(nil)).Elem()) } +// Describes the collection of resources (for example, hosts) that satisfy a +// policy, for a specific datastore. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmPlacementMatchingResources struct { types.DynamicData } @@ -1237,6 +2138,9 @@ func init() { types.Add("pbm:PbmPlacementMatchingResources", reflect.TypeOf((*PbmPlacementMatchingResources)(nil)).Elem()) } +// Defines a constraint for placing objects onto `PbmPlacementHub`s. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmPlacementRequirement struct { types.DynamicData } @@ -1245,82 +2149,156 @@ func init() { types.Add("pbm:PbmPlacementRequirement", reflect.TypeOf((*PbmPlacementRequirement)(nil)).Elem()) } +// Describes the resource utilization metrics of a datastore. +// +// These results are not to be treated as a guaranteed availability, +// they are useful to estimate the effects of a change of policy +// or the effects of a provisioning action. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmPlacementResourceUtilization struct { types.DynamicData - Name PbmExtendedElementDescription `xml:"name"` - Description PbmExtendedElementDescription `xml:"description"` - AvailableBefore int64 `xml:"availableBefore,omitempty"` - AvailableAfter int64 `xml:"availableAfter,omitempty"` - Total int64 `xml:"total,omitempty"` + // Name of the resource. + Name PbmExtendedElementDescription `xml:"name" json:"name"` + // Description of the resource. + Description PbmExtendedElementDescription `xml:"description" json:"description"` + // Currently available (i.e. + // + // before the provisioning step). + AvailableBefore int64 `xml:"availableBefore,omitempty" json:"availableBefore,omitempty"` + // Available after the provisioning step. + AvailableAfter int64 `xml:"availableAfter,omitempty" json:"availableAfter,omitempty"` + // Total resource availability + Total int64 `xml:"total,omitempty" json:"total,omitempty"` } func init() { types.Add("pbm:PbmPlacementResourceUtilization", reflect.TypeOf((*PbmPlacementResourceUtilization)(nil)).Elem()) } +// The `PbmProfile` data object is the base object +// for storage capability profiles. +// +// This object defines metadata +// for the profile. The derived capability profile represents the +// user's intent for selection and configuration of storage resources +// and/or services that support deployment of virtual machines +// and virtual disks. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmProfile struct { types.DynamicData - ProfileId PbmProfileId `xml:"profileId"` - Name string `xml:"name"` - Description string `xml:"description,omitempty"` - CreationTime time.Time `xml:"creationTime"` - CreatedBy string `xml:"createdBy"` - LastUpdatedTime time.Time `xml:"lastUpdatedTime"` - LastUpdatedBy string `xml:"lastUpdatedBy"` + // Unique identifier for the profile. + ProfileId PbmProfileId `xml:"profileId" json:"profileId"` + Name string `xml:"name" json:"name"` + // Profile description. + Description string `xml:"description,omitempty" json:"description,omitempty"` + // Time stamp of profile creation. + CreationTime time.Time `xml:"creationTime" json:"creationTime"` + // User name of the profile creator. + // + // Set during creation time. + CreatedBy string `xml:"createdBy" json:"createdBy"` + // Time stamp of latest modification to the profile. + LastUpdatedTime time.Time `xml:"lastUpdatedTime" json:"lastUpdatedTime"` + // Name of the user performing the latest modification of the profile. + LastUpdatedBy string `xml:"lastUpdatedBy" json:"lastUpdatedBy"` } func init() { types.Add("pbm:PbmProfile", reflect.TypeOf((*PbmProfile)(nil)).Elem()) } +// Profile unique identifier. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmProfileId struct { types.DynamicData - UniqueId string `xml:"uniqueId"` + // Unique identifier of the profile. + UniqueId string `xml:"uniqueId" json:"uniqueId"` } func init() { types.Add("pbm:PbmProfileId", reflect.TypeOf((*PbmProfileId)(nil)).Elem()) } +// The `PbmProfileOperationOutcome` data object describes the result +// of a `PbmProfileProfileManager` operation. +// +// If there was an +// error during the operation, the object identifies the fault. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmProfileOperationOutcome struct { types.DynamicData - ProfileId PbmProfileId `xml:"profileId"` - Fault *types.LocalizedMethodFault `xml:"fault,omitempty"` + // Identifies the profile specified for the operation. + ProfileId PbmProfileId `xml:"profileId" json:"profileId"` + // One of the `PbmFault` objects. + Fault *types.LocalizedMethodFault `xml:"fault,omitempty" json:"fault,omitempty"` } func init() { types.Add("pbm:PbmProfileOperationOutcome", reflect.TypeOf((*PbmProfileOperationOutcome)(nil)).Elem()) } +// The `PbmProfileResourceType` data object defines the vSphere resource type +// that is supported for profile management. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmProfileResourceType struct { types.DynamicData - ResourceType string `xml:"resourceType"` + // Type of resource to which capability information applies. + // + // resourceType is a string value that corresponds to + // a `PbmProfileResourceTypeEnum_enum` enumeration value. + // Only the STORAGE resource type is supported. + ResourceType string `xml:"resourceType" json:"resourceType"` } func init() { types.Add("pbm:PbmProfileResourceType", reflect.TypeOf((*PbmProfileResourceType)(nil)).Elem()) } +// The `PbmProfileType` identifier is defined by storage providers +// to distinguish between different types of profiles plugged into the system. +// +// An example of a system supported profile type is "CapabilityBasedProfileType" +// which will be the type used for all capability-based profiles created by +// the system using capability metadata information published to the system. +// +// For internal use only. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmProfileType struct { types.DynamicData - UniqueId string `xml:"uniqueId"` + // Unique type identifier for this profile type. + // + // eg "CapabilityBased", or other. + UniqueId string `xml:"uniqueId" json:"uniqueId"` } func init() { types.Add("pbm:PbmProfileType", reflect.TypeOf((*PbmProfileType)(nil)).Elem()) } +// Fault used to indicate which property instance in requirements profile that does not +// match. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmPropertyMismatchFault struct { PbmCompatibilityCheckFault - CapabilityInstanceId PbmCapabilityMetadataUniqueId `xml:"capabilityInstanceId"` - RequirementPropertyInstance PbmCapabilityPropertyInstance `xml:"requirementPropertyInstance"` + // Id of the CapabilityInstance in requirements profile that + // does not match. + CapabilityInstanceId PbmCapabilityMetadataUniqueId `xml:"capabilityInstanceId" json:"capabilityInstanceId"` + // The property instance in requirement profile that does not match. + RequirementPropertyInstance PbmCapabilityPropertyInstance `xml:"requirementPropertyInstance" json:"requirementPropertyInstance"` } func init() { @@ -1339,9 +2317,11 @@ func init() { types.Add("pbm:PbmQueryAssociatedEntities", reflect.TypeOf((*PbmQueryAssociatedEntities)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmQueryAssociatedEntities`. type PbmQueryAssociatedEntitiesRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Profiles []PbmProfileId `xml:"profiles,omitempty"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Storage policy array. + Profiles []PbmProfileId `xml:"profiles,omitempty" json:"profiles,omitempty"` } func init() { @@ -1349,7 +2329,7 @@ func init() { } type PbmQueryAssociatedEntitiesResponse struct { - Returnval []PbmQueryProfileResult `xml:"returnval,omitempty"` + Returnval []PbmQueryProfileResult `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmQueryAssociatedEntity PbmQueryAssociatedEntityRequestType @@ -1358,10 +2338,16 @@ func init() { types.Add("pbm:PbmQueryAssociatedEntity", reflect.TypeOf((*PbmQueryAssociatedEntity)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmQueryAssociatedEntity`. type PbmQueryAssociatedEntityRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Profile PbmProfileId `xml:"profile"` - EntityType string `xml:"entityType,omitempty"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Profile identifier. + Profile PbmProfileId `xml:"profile" json:"profile"` + // If specified, the method returns only those entities + // which match the type. The entityType string value must match + // one of the `PbmObjectType_enum` values. + // If not specified, the method returns all entities associated with the profile. + EntityType string `xml:"entityType,omitempty" json:"entityType,omitempty"` } func init() { @@ -1369,7 +2355,7 @@ func init() { } type PbmQueryAssociatedEntityResponse struct { - Returnval []PbmServerObjectRef `xml:"returnval,omitempty"` + Returnval []PbmServerObjectRef `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmQueryAssociatedProfile PbmQueryAssociatedProfileRequestType @@ -1378,9 +2364,11 @@ func init() { types.Add("pbm:PbmQueryAssociatedProfile", reflect.TypeOf((*PbmQueryAssociatedProfile)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmQueryAssociatedProfile`. type PbmQueryAssociatedProfileRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Entity PbmServerObjectRef `xml:"entity"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Reference to a virtual machine, virtual disk, or datastore. + Entity PbmServerObjectRef `xml:"entity" json:"entity"` } func init() { @@ -1388,7 +2376,7 @@ func init() { } type PbmQueryAssociatedProfileResponse struct { - Returnval []PbmProfileId `xml:"returnval,omitempty"` + Returnval []PbmProfileId `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmQueryAssociatedProfiles PbmQueryAssociatedProfilesRequestType @@ -1397,9 +2385,11 @@ func init() { types.Add("pbm:PbmQueryAssociatedProfiles", reflect.TypeOf((*PbmQueryAssociatedProfiles)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmQueryAssociatedProfiles`. type PbmQueryAssociatedProfilesRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Entities []PbmServerObjectRef `xml:"entities"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Array of server object references. + Entities []PbmServerObjectRef `xml:"entities" json:"entities"` } func init() { @@ -1407,7 +2397,7 @@ func init() { } type PbmQueryAssociatedProfilesResponse struct { - Returnval []PbmQueryProfileResult `xml:"returnval,omitempty"` + Returnval []PbmQueryProfileResult `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmQueryByRollupComplianceStatus PbmQueryByRollupComplianceStatusRequestType @@ -1416,9 +2406,11 @@ func init() { types.Add("pbm:PbmQueryByRollupComplianceStatus", reflect.TypeOf((*PbmQueryByRollupComplianceStatus)(nil)).Elem()) } +// The parameters of `PbmComplianceManager.PbmQueryByRollupComplianceStatus`. type PbmQueryByRollupComplianceStatusRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Status string `xml:"status"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // `PbmComplianceStatus_enum` + Status string `xml:"status" json:"status"` } func init() { @@ -1426,7 +2418,7 @@ func init() { } type PbmQueryByRollupComplianceStatusResponse struct { - Returnval []PbmServerObjectRef `xml:"returnval,omitempty"` + Returnval []PbmServerObjectRef `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmQueryDefaultRequirementProfile PbmQueryDefaultRequirementProfileRequestType @@ -1435,9 +2427,11 @@ func init() { types.Add("pbm:PbmQueryDefaultRequirementProfile", reflect.TypeOf((*PbmQueryDefaultRequirementProfile)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmQueryDefaultRequirementProfile`. type PbmQueryDefaultRequirementProfileRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Hub PbmPlacementHub `xml:"hub"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Placement hub (i.e. datastore). + Hub PbmPlacementHub `xml:"hub" json:"hub"` } func init() { @@ -1445,7 +2439,7 @@ func init() { } type PbmQueryDefaultRequirementProfileResponse struct { - Returnval *PbmProfileId `xml:"returnval,omitempty"` + Returnval *PbmProfileId `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmQueryDefaultRequirementProfiles PbmQueryDefaultRequirementProfilesRequestType @@ -1454,9 +2448,13 @@ func init() { types.Add("pbm:PbmQueryDefaultRequirementProfiles", reflect.TypeOf((*PbmQueryDefaultRequirementProfiles)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmQueryDefaultRequirementProfiles`. type PbmQueryDefaultRequirementProfilesRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Datastores []PbmPlacementHub `xml:"datastores"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // The datastores for which the default profiles are requested. For + // legacy datastores we set + // `DefaultProfileInfo.defaultProfile` to `null`. + Datastores []PbmPlacementHub `xml:"datastores" json:"datastores"` } func init() { @@ -1464,7 +2462,7 @@ func init() { } type PbmQueryDefaultRequirementProfilesResponse struct { - Returnval []PbmDefaultProfileInfo `xml:"returnval"` + Returnval []PbmDefaultProfileInfo `xml:"returnval" json:"returnval"` } type PbmQueryMatchingHub PbmQueryMatchingHubRequestType @@ -1473,10 +2471,15 @@ func init() { types.Add("pbm:PbmQueryMatchingHub", reflect.TypeOf((*PbmQueryMatchingHub)(nil)).Elem()) } +// The parameters of `PbmPlacementSolver.PbmQueryMatchingHub`. type PbmQueryMatchingHubRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - HubsToSearch []PbmPlacementHub `xml:"hubsToSearch,omitempty"` - Profile PbmProfileId `xml:"profile"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Candidate list of hubs, either datastores or storage pods or a + // mix. If this parameter is not specified, the Server uses all + // of the datastores and storage pods. + HubsToSearch []PbmPlacementHub `xml:"hubsToSearch,omitempty" json:"hubsToSearch,omitempty"` + // Storage requirement profile. + Profile PbmProfileId `xml:"profile" json:"profile"` } func init() { @@ -1484,7 +2487,7 @@ func init() { } type PbmQueryMatchingHubResponse struct { - Returnval []PbmPlacementHub `xml:"returnval,omitempty"` + Returnval []PbmPlacementHub `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmQueryMatchingHubWithSpec PbmQueryMatchingHubWithSpecRequestType @@ -1493,10 +2496,15 @@ func init() { types.Add("pbm:PbmQueryMatchingHubWithSpec", reflect.TypeOf((*PbmQueryMatchingHubWithSpec)(nil)).Elem()) } +// The parameters of `PbmPlacementSolver.PbmQueryMatchingHubWithSpec`. type PbmQueryMatchingHubWithSpecRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - HubsToSearch []PbmPlacementHub `xml:"hubsToSearch,omitempty"` - CreateSpec PbmCapabilityProfileCreateSpec `xml:"createSpec"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Candidate list of hubs, either datastores or storage + // pods or a mix. If this parameter is not specified, the Server uses + // all of the datastores and storage pods for placement compatibility checking. + HubsToSearch []PbmPlacementHub `xml:"hubsToSearch,omitempty" json:"hubsToSearch,omitempty"` + // Storage profile creation specification. + CreateSpec PbmCapabilityProfileCreateSpec `xml:"createSpec" json:"createSpec"` } func init() { @@ -1504,7 +2512,7 @@ func init() { } type PbmQueryMatchingHubWithSpecResponse struct { - Returnval []PbmPlacementHub `xml:"returnval,omitempty"` + Returnval []PbmPlacementHub `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmQueryProfile PbmQueryProfileRequestType @@ -1513,10 +2521,16 @@ func init() { types.Add("pbm:PbmQueryProfile", reflect.TypeOf((*PbmQueryProfile)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmQueryProfile`. type PbmQueryProfileRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - ResourceType PbmProfileResourceType `xml:"resourceType"` - ProfileCategory string `xml:"profileCategory,omitempty"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Type of resource. You can specify only STORAGE. + ResourceType PbmProfileResourceType `xml:"resourceType" json:"resourceType"` + // Profile category. The string value must correspond + // to one of the `PbmProfileCategoryEnum_enum` values. + // If you do not specify a profile category, the method returns profiles in all + // categories. + ProfileCategory string `xml:"profileCategory,omitempty" json:"profileCategory,omitempty"` } func init() { @@ -1524,27 +2538,48 @@ func init() { } type PbmQueryProfileResponse struct { - Returnval []PbmProfileId `xml:"returnval,omitempty"` + Returnval []PbmProfileId `xml:"returnval,omitempty" json:"returnval,omitempty"` } +// The `PbmQueryProfileResult` data object +// identifies a virtual machine, virtual disk, or datastore +// and it lists the identifier(s) for the associated profile(s). +// +// This structure may be used only with operations rendered under `/pbm`. type PbmQueryProfileResult struct { types.DynamicData - Object PbmServerObjectRef `xml:"object"` - ProfileId []PbmProfileId `xml:"profileId,omitempty"` - Fault *types.LocalizedMethodFault `xml:"fault,omitempty"` + // Reference to the virtual machine, virtual disk, or + // datastore on which the query was performed. + Object PbmServerObjectRef `xml:"object" json:"object"` + // Array of identifiers for profiles which are associated with object. + ProfileId []PbmProfileId `xml:"profileId,omitempty" json:"profileId,omitempty"` + // Fault associated with the query, if there is one. + Fault *types.LocalizedMethodFault `xml:"fault,omitempty" json:"fault,omitempty"` } func init() { types.Add("pbm:PbmQueryProfileResult", reflect.TypeOf((*PbmQueryProfileResult)(nil)).Elem()) } +// The `PbmQueryReplicationGroupResult` data object +// identifies a virtual machine, or a virtual disk and lists the identifier(s) for the associated +// replication group. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmQueryReplicationGroupResult struct { types.DynamicData - Object PbmServerObjectRef `xml:"object"` - ReplicationGroupId *types.ReplicationGroupId `xml:"replicationGroupId,omitempty"` - Fault *types.LocalizedMethodFault `xml:"fault,omitempty"` + // Reference to the virtual machine or virtual disk on which the query was performed. + // + // If the + // query was performed for a virtual machine and all it's disks, this will reference each disk + // and the virtual machine config individually. + Object PbmServerObjectRef `xml:"object" json:"object"` + // Replication group identifier which is associated with object. + ReplicationGroupId *types.ReplicationGroupId `xml:"replicationGroupId,omitempty" json:"replicationGroupId,omitempty"` + // Fault associated with the query, if there is one. + Fault *types.LocalizedMethodFault `xml:"fault,omitempty" json:"fault,omitempty"` } func init() { @@ -1557,9 +2592,15 @@ func init() { types.Add("pbm:PbmQueryReplicationGroups", reflect.TypeOf((*PbmQueryReplicationGroups)(nil)).Elem()) } +// The parameters of `PbmReplicationManager.PbmQueryReplicationGroups`. type PbmQueryReplicationGroupsRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Entities []PbmServerObjectRef `xml:"entities,omitempty"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Array of server object references. Valid types are + // `virtualMachine`, + // `virtualMachineAndDisks`, + // `virtualDiskId`, + // `virtualDiskUUID` + Entities []PbmServerObjectRef `xml:"entities,omitempty" json:"entities,omitempty"` } func init() { @@ -1567,7 +2608,7 @@ func init() { } type PbmQueryReplicationGroupsResponse struct { - Returnval []PbmQueryReplicationGroupResult `xml:"returnval,omitempty"` + Returnval []PbmQueryReplicationGroupResult `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmQuerySpaceStatsForStorageContainer PbmQuerySpaceStatsForStorageContainerRequestType @@ -1576,10 +2617,15 @@ func init() { types.Add("pbm:PbmQuerySpaceStatsForStorageContainer", reflect.TypeOf((*PbmQuerySpaceStatsForStorageContainer)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmQuerySpaceStatsForStorageContainer`. type PbmQuerySpaceStatsForStorageContainerRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Datastore PbmServerObjectRef `xml:"datastore"` - CapabilityProfileId []PbmProfileId `xml:"capabilityProfileId,omitempty"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Entity for which space statistics are being requested i.e datastore. + Datastore PbmServerObjectRef `xml:"datastore" json:"datastore"` + // \- capability profile Ids. + // If omitted, the statistics for the container + // as a whole would be returned. + CapabilityProfileId []PbmProfileId `xml:"capabilityProfileId,omitempty" json:"capabilityProfileId,omitempty"` } func init() { @@ -1587,7 +2633,7 @@ func init() { } type PbmQuerySpaceStatsForStorageContainerResponse struct { - Returnval []PbmDatastoreSpaceStatistics `xml:"returnval,omitempty"` + Returnval []PbmDatastoreSpaceStatistics `xml:"returnval,omitempty" json:"returnval,omitempty"` } type PbmResetDefaultRequirementProfile PbmResetDefaultRequirementProfileRequestType @@ -1596,9 +2642,11 @@ func init() { types.Add("pbm:PbmResetDefaultRequirementProfile", reflect.TypeOf((*PbmResetDefaultRequirementProfile)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmResetDefaultRequirementProfile`. type PbmResetDefaultRequirementProfileRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - Profile *PbmProfileId `xml:"profile,omitempty"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Profile to reset. + Profile *PbmProfileId `xml:"profile,omitempty" json:"profile,omitempty"` } func init() { @@ -1615,7 +2663,7 @@ func init() { } type PbmResetVSanDefaultProfileRequestType struct { - This types.ManagedObjectReference `xml:"_this"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` } func init() { @@ -1625,11 +2673,20 @@ func init() { type PbmResetVSanDefaultProfileResponse struct { } +// A ResourceInUse fault indicating that some error has occurred because a +// resource was in use. +// +// Information about the resource that is in use may +// be supplied. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmResourceInUse struct { PbmFault - Type string `xml:"type,omitempty"` - Name string `xml:"name,omitempty"` + // Type of resource that is in use. + Type string `xml:"type,omitempty" json:"type,omitempty"` + // Name of the instance of the resource that is in use. + Name string `xml:"name,omitempty" json:"name,omitempty"` } func init() { @@ -1648,9 +2705,11 @@ func init() { types.Add("pbm:PbmRetrieveContent", reflect.TypeOf((*PbmRetrieveContent)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmRetrieveContent`. type PbmRetrieveContentRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - ProfileIds []PbmProfileId `xml:"profileIds"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Array of storage profile identifiers. + ProfileIds []PbmProfileId `xml:"profileIds" json:"profileIds"` } func init() { @@ -1658,7 +2717,7 @@ func init() { } type PbmRetrieveContentResponse struct { - Returnval []BasePbmProfile `xml:"returnval,typeattr"` + Returnval []BasePbmProfile `xml:"returnval,typeattr" json:"returnval"` } type PbmRetrieveServiceContent PbmRetrieveServiceContentRequestType @@ -1668,7 +2727,7 @@ func init() { } type PbmRetrieveServiceContentRequestType struct { - This types.ManagedObjectReference `xml:"_this"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` } func init() { @@ -1676,47 +2735,154 @@ func init() { } type PbmRetrieveServiceContentResponse struct { - Returnval PbmServiceInstanceContent `xml:"returnval"` + Returnval PbmServiceInstanceContent `xml:"returnval" json:"returnval"` } +// The `PbmRollupComplianceResult` data object identifies the virtual machine +// for which rollup compliance was checked, and it contains the overall status +// and a list of compliance result objects. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmRollupComplianceResult struct { types.DynamicData - OldestCheckTime time.Time `xml:"oldestCheckTime"` - Entity PbmServerObjectRef `xml:"entity"` - OverallComplianceStatus string `xml:"overallComplianceStatus"` - OverallComplianceTaskStatus string `xml:"overallComplianceTaskStatus,omitempty"` - Result []PbmComplianceResult `xml:"result,omitempty"` - ErrorCause []types.LocalizedMethodFault `xml:"errorCause,omitempty"` - ProfileMismatch bool `xml:"profileMismatch"` + // Indicates the earliest time that compliance was checked for any + // of the entities in the rollup compliance check. + // + // The compliance + // check time for a single entity is represented in the + // `PbmComplianceResult*.*PbmComplianceResult.checkTime` + // property. If the `PbmComplianceResult.checkTime` + // property is unset for any of the objects in the results + // array, the oldestCheckTime property will be unset. + OldestCheckTime time.Time `xml:"oldestCheckTime" json:"oldestCheckTime"` + // Virtual machine for which the rollup compliance was checked. + Entity PbmServerObjectRef `xml:"entity" json:"entity"` + // Overall compliance status of the virtual machine and its virtual disks. + // + // overallComplianceStatus is a string value that + // corresponds to one of the + // `PbmComplianceResult*.*PbmComplianceResult.complianceStatus` + // values. + // + // The overall compliance status is determined by the following rules, applied in the order + // listed: + // - If all the entities are compliant, the overall status is + // compliant. + // - Else if any entity's status is outOfDate, the overall status is + // outOfDate. + // - Else if any entity's status is nonCompliant, the overall status is + // nonCompliant. + // - Else if any entity's status is unknown, the overall status is + // unknown. + // - Else if any entity's status is notApplicable, the overall status is + // notApplicable. + OverallComplianceStatus string `xml:"overallComplianceStatus" json:"overallComplianceStatus"` + // Overall compliance task status of the virtual machine and its virtual + // disks. + // + // overallComplianceTaskStatus is a string value that + // corresponds to one of the `PbmComplianceResult`. + // `PbmComplianceResult.complianceTaskStatus` values. + OverallComplianceTaskStatus string `xml:"overallComplianceTaskStatus,omitempty" json:"overallComplianceTaskStatus,omitempty"` + // Individual compliance results that make up the rollup. + Result []PbmComplianceResult `xml:"result,omitempty" json:"result,omitempty"` + // This property is set if the overall compliance task fails with some error. + // + // This + // property indicates the causes of error. If there are multiple failures, it stores + // these failure in this array. + ErrorCause []types.LocalizedMethodFault `xml:"errorCause,omitempty" json:"errorCause,omitempty"` + // Deprecated as of vSphere 2016, use + // `PbmRollupComplianceResult.overallComplianceStatus` + // to know if profile mismatch has occurred. If + // overallComplianceStatus value is outOfDate, it means + // profileMismatch has occurred. + // + // True if and only if `PbmComplianceResult`. + // + // `PbmComplianceResult.mismatch` is true for at least one + // entity in the rollup compliance check. + ProfileMismatch bool `xml:"profileMismatch" json:"profileMismatch"` } func init() { types.Add("pbm:PbmRollupComplianceResult", reflect.TypeOf((*PbmRollupComplianceResult)(nil)).Elem()) } +// The `PbmServerObjectRef` data object identifies +// a virtual machine, +// virtual disk attached to a virtual machine, +// a first class storage object +// or a datastore. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmServerObjectRef struct { types.DynamicData - ObjectType string `xml:"objectType"` - Key string `xml:"key"` - ServerUuid string `xml:"serverUuid,omitempty"` + // Type of vSphere Server object. + // + // The value of the objectType string + // corresponds to one of the `PbmObjectType_enum` + // enumerated type values. + ObjectType string `xml:"objectType" json:"objectType"` + // Unique identifier for the object. + // + // The value of key depends + // on the objectType. + // + // + // + // + // + // + // + // + // + //
`*PbmObjectType***`key value**
virtualMachine_virtual-machine-MOR_
virtualDiskId_virtual-disk-MOR_:_VirtualDisk.key_
datastore_datastore-MOR_
MOR = ManagedObjectReference
+ Key string `xml:"key" json:"key"` + // vCenter Server UUID; the ServiceContent.about.instanceUuid + // property in the vSphere API. + ServerUuid string `xml:"serverUuid,omitempty" json:"serverUuid,omitempty"` } func init() { types.Add("pbm:PbmServerObjectRef", reflect.TypeOf((*PbmServerObjectRef)(nil)).Elem()) } +// The `PbmServiceInstanceContent` data object defines properties for the +// `PbmServiceInstance` managed object. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmServiceInstanceContent struct { types.DynamicData - AboutInfo PbmAboutInfo `xml:"aboutInfo"` - SessionManager types.ManagedObjectReference `xml:"sessionManager"` - CapabilityMetadataManager types.ManagedObjectReference `xml:"capabilityMetadataManager"` - ProfileManager types.ManagedObjectReference `xml:"profileManager"` - ComplianceManager types.ManagedObjectReference `xml:"complianceManager"` - PlacementSolver types.ManagedObjectReference `xml:"placementSolver"` - ReplicationManager *types.ManagedObjectReference `xml:"replicationManager,omitempty"` + // Contains information that identifies the Storage Policy service. + AboutInfo PbmAboutInfo `xml:"aboutInfo" json:"aboutInfo"` + // For internal use. + // + // Refers instance of `PbmSessionManager`. + SessionManager types.ManagedObjectReference `xml:"sessionManager" json:"sessionManager"` + // For internal use. + // + // Refers instance of `PbmCapabilityMetadataManager`. + CapabilityMetadataManager types.ManagedObjectReference `xml:"capabilityMetadataManager" json:"capabilityMetadataManager"` + // Provides access to the Storage Policy ProfileManager. + // + // Refers instance of `PbmProfileProfileManager`. + ProfileManager types.ManagedObjectReference `xml:"profileManager" json:"profileManager"` + // Provides access to the Storage Policy ComplianceManager. + // + // Refers instance of `PbmComplianceManager`. + ComplianceManager types.ManagedObjectReference `xml:"complianceManager" json:"complianceManager"` + // Provides access to the Storage Policy PlacementSolver. + // + // Refers instance of `PbmPlacementSolver`. + PlacementSolver types.ManagedObjectReference `xml:"placementSolver" json:"placementSolver"` + // Provides access to the Storage Policy ReplicationManager. + // + // Refers instance of `PbmReplicationManager`. + ReplicationManager *types.ManagedObjectReference `xml:"replicationManager,omitempty" json:"replicationManager,omitempty"` } func init() { @@ -1729,10 +2895,13 @@ func init() { types.Add("pbm:PbmUpdate", reflect.TypeOf((*PbmUpdate)(nil)).Elem()) } +// The parameters of `PbmProfileProfileManager.PbmUpdate`. type PbmUpdateRequestType struct { - This types.ManagedObjectReference `xml:"_this"` - ProfileId PbmProfileId `xml:"profileId"` - UpdateSpec PbmCapabilityProfileUpdateSpec `xml:"updateSpec"` + This types.ManagedObjectReference `xml:"_this" json:"_this"` + // Profile identifier. + ProfileId PbmProfileId `xml:"profileId" json:"profileId"` + // Capability-based update specification. + UpdateSpec PbmCapabilityProfileUpdateSpec `xml:"updateSpec" json:"updateSpec"` } func init() { @@ -1742,6 +2911,10 @@ func init() { type PbmUpdateResponse struct { } +// Information about a supported data service provided using +// vSphere APIs for IO Filtering (VAIO) data service provider. +// +// This structure may be used only with operations rendered under `/pbm`. type PbmVaioDataServiceInfo struct { PbmLineOfServiceInfo } diff --git a/vendor/github.com/vmware/govmomi/property/collector.go b/vendor/github.com/vmware/govmomi/property/collector.go index 8798ceacbf..16bf222669 100644 --- a/vendor/github.com/vmware/govmomi/property/collector.go +++ b/vendor/github.com/vmware/govmomi/property/collector.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2015 VMware, Inc. All Rights Reserved. +Copyright (c) 2015-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -31,7 +31,6 @@ import ( // // For more information, see: // http://pubs.vmware.com/vsphere-60/index.jsp?topic=%2Fcom.vmware.wssdk.apiref.doc%2Fvmodl.query.PropertyCollector.html -// type Collector struct { roundTripper soap.RoundTripper reference types.ManagedObjectReference diff --git a/vendor/github.com/vmware/govmomi/session/cache/session.go b/vendor/github.com/vmware/govmomi/session/cache/session.go new file mode 100644 index 0000000000..c6c3955c17 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/session/cache/session.go @@ -0,0 +1,365 @@ +/* +Copyright (c) 2020 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cache + +import ( + "context" + "crypto/sha1" + "encoding/json" + "fmt" + "net/url" + "os" + "os/user" + "path/filepath" + + "github.com/vmware/govmomi/session" + "github.com/vmware/govmomi/vapi/rest" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" +) + +// Client interface to support client session caching +type Client interface { + json.Marshaler + json.Unmarshaler + + Valid() bool + Path() string +} + +// Session provides methods to cache authenticated vim25.Client and rest.Client sessions. +// Use of session cache avoids the expense of creating and deleting vSphere sessions. +// It also helps avoid the problem of "leaking sessions", as Session.Login will only +// create a new authenticated session if the cached session does not exist or is invalid. +// By default, username/password authentication is used to create new sessions. +// The Session.Login{SOAP,REST} fields can be set to use other methods, +// such as SAML token authentication (see govc session.login for example). +// +// When Reauth is set to true, Login skips loading file cache and performs username/password +// authentication, which is helpful in the case that the password in URL is different than +// previously cached session. Comparing to `Passthrough`, the file cache will be updated after +// authentication is done. +type Session struct { + URL *url.URL // URL of a vCenter or ESXi instance + DirSOAP string // DirSOAP cache directory. Defaults to "$HOME/.govmomi/sessions" + DirREST string // DirREST cache directory. Defaults to "$HOME/.govmomi/rest_sessions" + Insecure bool // Insecure param for soap.NewClient (tls.Config.InsecureSkipVerify) + Passthrough bool // Passthrough disables caching when set to true + Reauth bool // Reauth skips loading of cached sessions when set to true + + LoginSOAP func(context.Context, *vim25.Client) error // LoginSOAP defaults to session.Manager.Login() + LoginREST func(context.Context, *rest.Client) error // LoginREST defaults to rest.Client.Login() +} + +var ( + home = os.Getenv("GOVMOMI_HOME") +) + +func init() { + if home == "" { + dir, err := os.UserHomeDir() + if err != nil { + dir = os.Getenv("HOME") + } + home = filepath.Join(dir, ".govmomi") + } +} + +// Endpoint returns a copy of the Session.URL with Password, Query and Fragment removed. +func (s *Session) Endpoint() *url.URL { + if s.URL == nil { + return nil + } + p := &url.URL{ + Scheme: s.URL.Scheme, + Host: s.URL.Host, + Path: s.URL.Path, + } + if u := s.URL.User; u != nil { + p.User = url.User(u.Username()) // Remove password + } + return p +} + +// key is a digest of the URL scheme + username + host + Client.Path() +func (s *Session) key(path string) string { + p := s.Endpoint() + p.Path = path + + // Key session file off of full URI and insecure setting. + // Hash key to get a predictable, canonical format. + key := fmt.Sprintf("%s#insecure=%t", p.String(), s.Insecure) + return fmt.Sprintf("%040x", sha1.Sum([]byte(key))) +} + +func (s *Session) file(p string) string { + dir := "" + + switch p { + case rest.Path: + dir = s.DirREST + if dir == "" { + dir = filepath.Join(home, "rest_sessions") + } + default: + dir = s.DirSOAP + if dir == "" { + dir = filepath.Join(home, "sessions") + } + } + + return filepath.Join(dir, s.key(p)) +} + +// Save a Client in the file cache. +// Session will not be saved if Session.Passthrough is true. +func (s *Session) Save(c Client) error { + if s.Passthrough { + return nil + } + + p := s.file(c.Path()) + + err := os.MkdirAll(filepath.Dir(p), 0700) + if err != nil { + return err + } + + f, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY, 0600) + if err != nil { + return err + } + + err = json.NewEncoder(f).Encode(c) + if err != nil { + _ = f.Close() + return err + } + + return f.Close() +} + +func (s *Session) get(c Client) (bool, error) { + f, err := os.Open(s.file(c.Path())) + if err != nil { + if os.IsNotExist(err) { + return false, nil + } + + return false, err + } + + dec := json.NewDecoder(f) + err = dec.Decode(c) + if err != nil { + _ = f.Close() + return false, err + } + + return c.Valid(), f.Close() +} + +func localTicket(ctx context.Context, m *session.Manager) (*url.Userinfo, error) { + name := os.Getenv("USER") + u, err := user.Current() + if err == nil { + name = u.Username + } + + ticket, err := m.AcquireLocalTicket(ctx, name) + if err != nil { + return nil, err + } + + password, err := os.ReadFile(ticket.PasswordFilePath) + if err != nil { + return nil, err + } + + return url.UserPassword(ticket.UserName, string(password)), nil +} + +func (s *Session) loginSOAP(ctx context.Context, c *vim25.Client) error { + m := session.NewManager(c) + u := s.URL.User + name := u.Username() + + if name == "" && !c.IsVC() { + // If no username is provided, try to acquire a local ticket. + // When invoked remotely, ESX returns an InvalidRequestFault. + // So, rather than return an error here, fallthrough to Login() with the original User to + // to avoid what would be a confusing error message. + luser, lerr := localTicket(ctx, m) + if lerr == nil { + // We are running directly on an ESX or Workstation host and can use the ticket with Login() + u = luser + name = u.Username() + } + } + if name == "" { + // ServiceContent does not require authentication + return nil + } + + return m.Login(ctx, u) +} + +func (s *Session) loginREST(ctx context.Context, c *rest.Client) error { + return c.Login(ctx, s.URL.User) +} + +func soapSessionValid(ctx context.Context, client *vim25.Client) (bool, error) { + m := session.NewManager(client) + u, err := m.UserSession(ctx) + if err != nil { + if soap.IsSoapFault(err) { + fault := soap.ToSoapFault(err).VimFault() + // If the PropertyCollector is not found, the saved session for this URL is not valid + if _, ok := fault.(types.ManagedObjectNotFound); ok { + return false, nil + } + } + + return false, err + } + + return u != nil, nil +} + +func restSessionValid(ctx context.Context, client *rest.Client) (bool, error) { + s, err := client.Session(ctx) + if err != nil { + return false, err + } + return s != nil, nil +} + +// Load a Client from the file cache. +// Returns false if no cache exists or is invalid. +// An error is returned if the file cannot be opened or is not json encoded. +// After loading the Client from the file: +// Returns true if the session is still valid, false otherwise indicating the client requires authentication. +// An error is returned if the session ID cannot be validated. +// Returns false if Session.Passthrough is true. +func (s *Session) Load(ctx context.Context, c Client, config func(*soap.Client) error) (bool, error) { + if s.Passthrough || s.Reauth { + return false, nil + } + + ok, err := s.get(c) + if err != nil { + return false, err + + } + if !ok { + return false, nil + } + + switch client := c.(type) { + case *vim25.Client: + if config != nil { + if err := config(client.Client); err != nil { + return false, err + } + } + return soapSessionValid(ctx, client) + case *rest.Client: + if config != nil { + if err := config(client.Client); err != nil { + return false, err + } + } + return restSessionValid(ctx, client) + default: + panic(fmt.Sprintf("unsupported client type=%T", client)) + } +} + +// Login returns a cached session via Load() if valid. +// Otherwise, creates a new authenticated session and saves to the cache. +// The config func can be used to apply soap.Client configuration, such as TLS settings. +// When Session.Passthrough is true, Login will always create a new session. +func (s *Session) Login(ctx context.Context, c Client, config func(*soap.Client) error) error { + ok, err := s.Load(ctx, c, config) + if err != nil { + return err + } + if ok { + return nil + } + + sc := soap.NewClient(s.URL, s.Insecure) + + if config != nil { + err = config(sc) + if err != nil { + return err + } + } + + switch client := c.(type) { + case *vim25.Client: + vc, err := vim25.NewClient(ctx, sc) + if err != nil { + return err + } + + login := s.loginSOAP + if s.LoginSOAP != nil { + login = s.LoginSOAP + } + if err = login(ctx, vc); err != nil { + return err + } + + *client = *vc + c = client + case *rest.Client: + client.Client = sc.NewServiceClient(rest.Path, "") + + login := s.loginREST + if s.LoginREST != nil { + login = s.LoginREST + } + if err = login(ctx, client); err != nil { + return err + } + + c = client + default: + panic(fmt.Sprintf("unsupported client type=%T", client)) + } + + return s.Save(c) +} + +// Login calls the Logout method for the given Client if Session.Passthrough is true. +// Otherwise returns nil. +func (s *Session) Logout(ctx context.Context, c Client) error { + if s.Passthrough { + switch client := c.(type) { + case *vim25.Client: + return session.NewManager(client).Logout(ctx) + case *rest.Client: + return client.Logout(ctx) + default: + panic(fmt.Sprintf("unsupported client type=%T", client)) + } + } + return nil +} diff --git a/vendor/github.com/vmware/govmomi/session/manager.go b/vendor/github.com/vmware/govmomi/session/manager.go index 8689acd504..e2d70a2f60 100644 --- a/vendor/github.com/vmware/govmomi/session/manager.go +++ b/vendor/github.com/vmware/govmomi/session/manager.go @@ -18,7 +18,6 @@ package session import ( "context" - "io/ioutil" "net/url" "os" "strings" @@ -47,7 +46,7 @@ func Secret(value string) (string, error) { if len(value) == 0 { return value, nil } - contents, err := ioutil.ReadFile(value) + contents, err := os.ReadFile(value) if err != nil { if os.IsPermission(err) { return "", err diff --git a/vendor/github.com/vmware/govmomi/simulator/cluster_compute_resource.go b/vendor/github.com/vmware/govmomi/simulator/cluster_compute_resource.go index 12f910b2e4..cf99285369 100644 --- a/vendor/github.com/vmware/govmomi/simulator/cluster_compute_resource.go +++ b/vendor/github.com/vmware/govmomi/simulator/cluster_compute_resource.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -66,10 +66,11 @@ func (add *addHost) Run(task *Task) (types.AnyType, types.BaseMethodFault) { } host := NewHostSystem(template) - host.configure(spec, add.req.AsConnected) + host.configure(task.ctx, spec, add.req.AsConnected) task.ctx.Map.PutEntity(cr, task.ctx.Map.NewEntity(host)) host.Summary.Host = &host.Self + host.Config.Host = host.Self cr.Host = append(cr.Host, host.Reference()) addComputeResource(cr.Summary.GetComputeResourceSummary(), host) @@ -85,6 +86,24 @@ func (c *ClusterComputeResource) AddHostTask(ctx *Context, add *types.AddHost_Ta } } +func (c *ClusterComputeResource) update(cfg *types.ClusterConfigInfoEx, cspec *types.ClusterConfigSpecEx) types.BaseMethodFault { + if cspec.DasConfig != nil { + if val := cspec.DasConfig.Enabled; val != nil { + cfg.DasConfig.Enabled = val + } + if val := cspec.DasConfig.AdmissionControlEnabled; val != nil { + cfg.DasConfig.AdmissionControlEnabled = val + } + } + if cspec.DrsConfig != nil { + if val := cspec.DrsConfig.Enabled; val != nil { + cfg.DrsConfig.Enabled = val + } + } + + return nil +} + func (c *ClusterComputeResource) updateRules(cfg *types.ClusterConfigInfoEx, cspec *types.ClusterConfigSpecEx) types.BaseMethodFault { for _, spec := range cspec.RulesSpec { var i int @@ -327,6 +346,7 @@ func (c *ClusterComputeResource) ReconfigureComputeResourceTask(ctx *Context, re } updates := []func(*types.ClusterConfigInfoEx, *types.ClusterConfigSpecEx) types.BaseMethodFault{ + c.update, c.updateRules, c.updateGroups, c.updateOverridesDAS, @@ -350,6 +370,40 @@ func (c *ClusterComputeResource) ReconfigureComputeResourceTask(ctx *Context, re } } +func (c *ClusterComputeResource) MoveIntoTask(ctx *Context, req *types.MoveInto_Task) soap.HasFault { + task := CreateTask(c, "moveInto", func(*Task) (types.AnyType, types.BaseMethodFault) { + for _, ref := range req.Host { + host := ctx.Map.Get(ref).(*HostSystem) + + if *host.Parent == c.Self { + return nil, new(types.DuplicateName) // host already in this cluster + } + + switch parent := ctx.Map.Get(*host.Parent).(type) { + case *ClusterComputeResource: + if !host.Runtime.InMaintenanceMode { + return nil, new(types.InvalidState) + } + + RemoveReference(&parent.Host, ref) + case *mo.ComputeResource: + ctx.Map.Remove(ctx, parent.Self) + } + + c.Host = append(c.Host, ref) + host.Parent = &c.Self + } + + return nil, nil + }) + + return &methods.MoveInto_TaskBody{ + Res: &types.MoveInto_TaskResponse{ + Returnval: task.Run(ctx), + }, + } +} + func (c *ClusterComputeResource) PlaceVm(ctx *Context, req *types.PlaceVm) soap.HasFault { body := new(methods.PlaceVmBody) diff --git a/vendor/github.com/vmware/govmomi/simulator/container.go b/vendor/github.com/vmware/govmomi/simulator/container.go index 96f4fd10cc..f39ef99702 100644 --- a/vendor/github.com/vmware/govmomi/simulator/container.go +++ b/vendor/github.com/vmware/govmomi/simulator/container.go @@ -18,29 +18,32 @@ package simulator import ( "archive/tar" + "bufio" "bytes" - "encoding/hex" + "context" "encoding/json" + "errors" "fmt" "io" "log" - "net/http" + "net" "os" "os/exec" "path" "regexp" - "strconv" "strings" + "sync" "time" - - "github.com/google/uuid" - - "github.com/vmware/govmomi/vim25/methods" - "github.com/vmware/govmomi/vim25/types" ) var ( - shell = "/bin/sh" + shell = "/bin/sh" + eventWatch eventWatcher +) + +const ( + deleteWithContainer = "lifecycle=container" + createdByVcsim = "createdBy=vcsim" ) func init() { @@ -49,10 +52,26 @@ func init() { } } +type eventWatcher struct { + sync.Mutex + + stdin io.WriteCloser + stdout io.ReadCloser + process *os.Process + + // watches is a map of container IDs to container objects + watches map[string]*container +} + // container provides methods to manage a container within a simulator VM lifecycle. type container struct { + sync.Mutex + id string name string + + cancelWatch context.CancelFunc + changes chan struct{} } type networkSettings struct { @@ -62,524 +81,753 @@ type networkSettings struct { MacAddress string } -// inspect applies container network settings to vm.Guest properties. -func (c *container) inspect(vm *VirtualMachine) error { - if c.id == "" { - return nil +type containerDetails struct { + State struct { + Running bool + Paused bool } + NetworkSettings struct { + networkSettings + Networks map[string]networkSettings + } +} - var objects []struct { - State struct { - Running bool - Paused bool - } - NetworkSettings struct { - networkSettings - Networks map[string]networkSettings - } +type unknownContainer error +type uninitializedContainer error + +var sanitizeNameRx = regexp.MustCompile(`[\(\)\s]`) + +func sanitizeName(name string) string { + return sanitizeNameRx.ReplaceAllString(name, "-") +} + +func constructContainerName(name, uid string) string { + return fmt.Sprintf("vcsim-%s-%s", sanitizeName(name), uid) +} + +func constructVolumeName(containerName, uid, volumeName string) string { + return constructContainerName(containerName, uid) + "--" + sanitizeName(volumeName) +} + +func extractNameAndUid(containerName string) (name string, uid string, err error) { + parts := strings.Split(strings.TrimPrefix(containerName, "vcsim-"), "-") + if len(parts) != 2 { + err = fmt.Errorf("container name does not match expected vcsim-name-uid format: %s", containerName) + return } - cmd := exec.Command("docker", "inspect", c.id) - out, err := cmd.Output() + return parts[0], parts[1], nil +} + +func prefixToMask(prefix int) string { + mask := net.CIDRMask(prefix, 32) + return fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3]) +} + +type tarEntry struct { + header *tar.Header + content []byte +} + +// From https://docs.docker.com/engine/reference/commandline/cp/ : +// > It is not possible to copy certain system files such as resources under /proc, /sys, /dev, tmpfs, and mounts created by the user in the container. +// > However, you can still copy such files by manually running tar in docker exec. +func copyToGuest(id string, dest string, length int64, reader io.Reader) error { + cmd := exec.Command("docker", "exec", "-i", id, "tar", "Cxf", path.Dir(dest), "-") + cmd.Stderr = os.Stderr + stdin, err := cmd.StdinPipe() if err != nil { return err } - if err = json.NewDecoder(bytes.NewReader(out)).Decode(&objects); err != nil { + + err = cmd.Start() + if err != nil { return err } - vm.Config.Annotation = strings.Join(cmd.Args, " ") - vm.logPrintf("%s: %s", vm.Config.Annotation, string(out)) - - for _, o := range objects { - s := o.NetworkSettings.networkSettings + tw := tar.NewWriter(stdin) + _ = tw.WriteHeader(&tar.Header{ + Name: path.Base(dest), + Size: length, + Mode: 0444, + ModTime: time.Now(), + }) - for _, n := range o.NetworkSettings.Networks { - s = n - break - } + _, err = io.Copy(tw, reader) - if o.State.Paused { - vm.Runtime.PowerState = types.VirtualMachinePowerStateSuspended - } else if o.State.Running { - vm.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOn - } else { - vm.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOff - } + twErr := tw.Close() + stdinErr := stdin.Close() - vm.Guest.IpAddress = s.IPAddress - vm.Summary.Guest.IpAddress = s.IPAddress - - if len(vm.Guest.Net) != 0 { - net := &vm.Guest.Net[0] - net.IpAddress = []string{s.IPAddress} - net.MacAddress = s.MacAddress - net.IpConfig = &types.NetIpConfigInfo{ - IpAddress: []types.NetIpConfigInfoIpAddress{{ - IpAddress: s.IPAddress, - PrefixLength: int32(s.IPPrefixLen), - State: string(types.NetIpConfigInfoIpAddressStatusPreferred), - }}, - } - } + waitErr := cmd.Wait() - for _, d := range vm.Config.Hardware.Device { - if eth, ok := d.(types.BaseVirtualEthernetCard); ok { - eth.GetVirtualEthernetCard().MacAddress = s.MacAddress - break - } - } + if err != nil || twErr != nil || stdinErr != nil || waitErr != nil { + return fmt.Errorf("copy: {%s}, tw: {%s}, stdin: {%s}, wait: {%s}", err, twErr, stdinErr, waitErr) } return nil } -func (c *container) prepareGuestOperation( - vm *VirtualMachine, - auth types.BaseGuestAuthentication) types.BaseMethodFault { - - if c.id == "" { - return new(types.GuestOperationsUnavailable) +func copyFromGuest(id string, src string, sink func(int64, io.Reader) error) error { + cmd := exec.Command("docker", "exec", id, "tar", "Ccf", path.Dir(src), "-", path.Base(src)) + cmd.Stderr = os.Stderr + stdout, err := cmd.StdoutPipe() + if err != nil { + return err } - if vm.Runtime.PowerState != types.VirtualMachinePowerStatePoweredOn { - return &types.InvalidPowerState{ - RequestedState: types.VirtualMachinePowerStatePoweredOn, - ExistingState: vm.Runtime.PowerState, - } + if err = cmd.Start(); err != nil { + return err } - switch creds := auth.(type) { - case *types.NamePasswordAuthentication: - if creds.Username == "" || creds.Password == "" { - return new(types.InvalidGuestLogin) - } - default: - return new(types.InvalidGuestLogin) + + tr := tar.NewReader(stdout) + header, err := tr.Next() + if err != nil { + return err } - return nil -} -var sanitizeNameRx = regexp.MustCompile(`[\(\)\s]`) + err = sink(header.Size, tr) + waitErr := cmd.Wait() -func sanitizeName(name string) string { - return sanitizeNameRx.ReplaceAllString(name, "-") + if err != nil || waitErr != nil { + return fmt.Errorf("err: {%s}, wait: {%s}", err, waitErr) + } + + return nil } -// createDMI writes BIOS UUID DMI files to a container volume -func (c *container) createDMI(vm *VirtualMachine, name string) error { +// createVolume creates a volume populated with the provided files +// If the header.Size is omitted or set to zero, then len(content+1) is used. +// Docker appears to treat this volume create command as idempotent so long as it's identical +// to an existing volume, so we can use this both for creating volumes inline in container create (for labelling) and +// for population after. +// returns: +// +// uid - string +// err - error or nil +func createVolume(volumeName string, labels []string, files []tarEntry) (string, error) { image := os.Getenv("VCSIM_BUSYBOX") if image == "" { image = "busybox" } - cmd := exec.Command("docker", "run", "--rm", "-i", "-v", name+":"+"/"+name, image, "tar", "-C", "/"+name, "-xf", "-") + name := sanitizeName(volumeName) + uid := "" + + // label the volume if specified - this requires the volume be created before use + if len(labels) > 0 { + run := []string{"volume", "create"} + for i := range labels { + run = append(run, "--label", labels[i]) + } + run = append(run, name) + cmd := exec.Command("docker", run...) + out, err := cmd.Output() + if err != nil { + return "", err + } + uid = strings.TrimSpace(string(out)) + + if name == "" { + name = uid + } + } + + run := []string{"run", "--rm", "-i"} + run = append(run, "-v", name+":/"+name) + run = append(run, image, "tar", "-C", "/"+name, "-xf", "-") + cmd := exec.Command("docker", run...) stdin, err := cmd.StdinPipe() if err != nil { - return err + return uid, err } err = cmd.Start() if err != nil { - return err + return uid, err } tw := tar.NewWriter(stdin) - dmi := []struct { - name string - val func(uuid.UUID) string - }{ - {"product_uuid", productUUID}, - {"product_serial", productSerial}, - } + for _, file := range files { + header := file.header - for _, file := range dmi { - val := file.val(vm.uid) - _ = tw.WriteHeader(&tar.Header{ - Name: file.name, - Size: int64(len(val) + 1), - Mode: 0444, - ModTime: time.Now(), - }) - _, _ = fmt.Fprintln(tw, val) + if header.Size == 0 && len(file.content) > 0 { + header.Size = int64(len(file.content)) + } + + if header.ModTime.IsZero() { + header.ModTime = time.Now() + } + + if header.Mode == 0 { + header.Mode = 0444 + } + + tarErr := tw.WriteHeader(header) + if tarErr == nil { + _, tarErr = tw.Write(file.content) + } } - _ = tw.Close() - _ = stdin.Close() + err = nil + twErr := tw.Close() + stdinErr := stdin.Close() + if twErr != nil || stdinErr != nil { + err = fmt.Errorf("tw: {%s}, stdin: {%s}", twErr, stdinErr) + } - if err := cmd.Wait(); err != nil { + if waitErr := cmd.Wait(); waitErr != nil { stderr := "" - if xerr, ok := err.(*exec.ExitError); ok { + if xerr, ok := waitErr.(*exec.ExitError); ok { stderr = string(xerr.Stderr) } - log.Printf("%s %s: %s %s", vm.Name, cmd.Args, err, stderr) - return err + log.Printf("%s %s: %s %s", name, cmd.Args, waitErr, stderr) + + err = fmt.Errorf("%s, wait: {%s}", err, waitErr) + return uid, err } - return nil + return uid, err } -var ( - toolsRunning = []types.PropertyChange{ - {Name: "guest.toolsStatus", Val: types.VirtualMachineToolsStatusToolsOk}, - {Name: "guest.toolsRunningStatus", Val: string(types.VirtualMachineToolsRunningStatusGuestToolsRunning)}, +func getBridge(bridgeName string) (string, error) { + // {"CreatedAt":"2023-07-11 19:22:25.45027052 +0000 UTC","Driver":"bridge","ID":"fe52c7502c5d","IPv6":"false","Internal":"false","Labels":"goodbye=,hello=","Name":"testnet","Scope":"local"} + // podman has distinctly different fields at v4.4.1 so commented out fields that don't match. We only actually care about ID + type bridgeNet struct { + // CreatedAt string + Driver string + ID string + // IPv6 string + // Internal string + // Labels string + Name string + // Scope string + } + + // if the underlay bridge already exists, return that + // we don't check for a specific label or similar so that it's possible to use a bridge created by other frameworks for composite testing + var bridge bridgeNet + cmd := exec.Command("docker", "network", "ls", "--format={{json .}}", "-f", fmt.Sprintf("name=%s$", bridgeName)) + out, err := cmd.Output() + if err != nil { + log.Printf("vcsim %s: %s, %s", cmd.Args, err, out) + return "", err } - toolsNotRunning = []types.PropertyChange{ - {Name: "guest.toolsStatus", Val: types.VirtualMachineToolsStatusToolsNotRunning}, - {Name: "guest.toolsRunningStatus", Val: string(types.VirtualMachineToolsRunningStatusGuestToolsNotRunning)}, + // unfortunately docker returns an empty string not an empty json doc and podman returns '[]' + // podman also returns an array of matches even when there's only one, so we normalize. + str := strings.TrimSpace(string(out)) + str = strings.TrimPrefix(str, "[") + str = strings.TrimSuffix(str, "]") + if len(str) == 0 { + return "", nil } -) -// start runs the container if specified by the RUN.container extraConfig property. -func (c *container) start(ctx *Context, vm *VirtualMachine) { - if c.id != "" { - start := "start" - if vm.Runtime.PowerState == types.VirtualMachinePowerStateSuspended { - start = "unpause" - } - cmd := exec.Command("docker", start, c.id) - err := cmd.Run() - if err != nil { - log.Printf("%s %s: %s", vm.Name, cmd.Args, err) - } else { - ctx.Map.Update(vm, toolsRunning) - } - return + err = json.Unmarshal([]byte(str), &bridge) + if err != nil { + log.Printf("vcsim %s: %s, %s", cmd.Args, err, str) + return "", err } - var args []string - var env []string + return bridge.ID, nil +} - for _, opt := range vm.Config.ExtraConfig { - val := opt.GetOptionValue() - if val.Key == "RUN.container" { - run := val.Value.(string) - err := json.Unmarshal([]byte(run), &args) - if err != nil { - args = []string{run} - } +// createBridge creates a bridge network if one does not already exist +// returns: +// +// uid - string +// err - error or nil +func createBridge(bridgeName string, labels ...string) (string, error) { - continue - } - if strings.HasPrefix(val.Key, "guestinfo.") { - key := strings.Replace(strings.ToUpper(val.Key), ".", "_", -1) - env = append(env, "--env", fmt.Sprintf("VMX_%s=%s", key, val.Value.(string))) - } + id, err := getBridge(bridgeName) + if err != nil { + return "", err } - if len(args) == 0 { - return + if id != "" { + return id, nil } - if len(env) != 0 { - // Configure env as the data access method for cloud-init-vmware-guestinfo - env = append(env, "--env", "VMX_GUESTINFO=true") + + run := []string{"network", "create", "--label", createdByVcsim} + for i := range labels { + run = append(run, "--label", labels[i]) } + run = append(run, bridgeName) - c.name = fmt.Sprintf("vcsim-%s-%s", sanitizeName(vm.Name), vm.uid) - run := append([]string{"docker", "run", "-d", "--name", c.name}, env...) + cmd := exec.Command("docker", run...) + out, err := cmd.Output() + if err != nil { + log.Printf("vcsim %s: %s: %s", cmd.Args, out, err) + return "", err + } - if err := c.createDMI(vm, c.name); err != nil { - return + // docker returns the ID regardless of whether you supply a name when creating the network, however + // podman returns the pretty name, so we have to normalize + id, err = getBridge(bridgeName) + if err != nil { + return "", err } - run = append(run, "-v", fmt.Sprintf("%s:%s:ro", c.name, "/sys/class/dmi/id")) - args = append(run, args...) - cmd := exec.Command(shell, "-c", strings.Join(args, " ")) + return id, nil +} + +// create +// - name - pretty name, eg. vm name +// - id - uuid or similar - this is merged into container name rather than dictating containerID +// - networks - set of bridges to connect the container to +// - volumes - colon separated tuple of volume name to mount path. Passed directly to docker via -v so mount options can be postfixed. +// - env - array of environment vairables in name=value form +// - optsAndImage - pass-though options and must include at least the container image to use, including tag if necessary +// - args - the command+args to pass to the container +func create(ctx *Context, name string, id string, networks []string, volumes []string, ports []string, env []string, image string, args []string) (*container, error) { + if len(image) == 0 { + return nil, errors.New("cannot create container backing without an image") + } + + var c container + c.name = constructContainerName(name, id) + c.changes = make(chan struct{}) + + for i := range volumes { + // we'll pre-create anonymous volumes, simply for labelling consistency + volName := strings.Split(volumes[i], ":") + createVolume(volName[0], []string{deleteWithContainer, "container=" + c.name}, nil) + } + + // assemble env + var dockerNet []string + var dockerVol []string + var dockerPort []string + var dockerEnv []string + + for i := range env { + dockerEnv = append(dockerEnv, "--env", env[i]) + } + + for i := range volumes { + dockerVol = append(dockerVol, "-v", volumes[i]) + } + + for i := range ports { + dockerPort = append(dockerPort, "-p", ports[i]) + } + + for i := range networks { + dockerNet = append(dockerNet, "--network", networks[i]) + } + + run := []string{"docker", "create", "--name", c.name} + run = append(run, dockerNet...) + run = append(run, dockerVol...) + run = append(run, dockerPort...) + run = append(run, dockerEnv...) + run = append(run, image) + run = append(run, args...) + + // this combines all the run options into a single string that's passed to /bin/bash -c as the single argument to force bash parsing. + // TODO: make this configurable behaviour so users also have the option of not escaping everything for bash + cmd := exec.Command(shell, "-c", strings.Join(run, " ")) out, err := cmd.Output() if err != nil { stderr := "" if xerr, ok := err.(*exec.ExitError); ok { stderr = string(xerr.Stderr) } - log.Printf("%s %s: %s %s", vm.Name, cmd.Args, err, stderr) - return + log.Printf("%s %s: %s %s", name, cmd.Args, err, stderr) + + return nil, err } - ctx.Map.Update(vm, toolsRunning) c.id = strings.TrimSpace(string(out)) - vm.logPrintf("%s %s: %s", cmd.Path, cmd.Args, c.id) - if err = c.inspect(vm); err != nil { - log.Printf("%s inspect %s: %s", vm.Name, c.id, err) - } - - // Start watching the container resource. - go c.watchContainer(vm) + return &c, nil } -// watchContainer monitors the underlying container and updates the VM -// properties based on the container status. This occurs until either -// the container or the VM is removed. -func (c *container) watchContainer(vm *VirtualMachine) { +// createVolume takes the specified files and writes them into a volume named for the container. +func (c *container) createVolume(name string, labels []string, files []tarEntry) (string, error) { + return createVolume(c.name+"--"+name, append(labels, "container="+c.name), files) +} - inspectInterval := time.Duration(5 * time.Second) - if d, err := time.ParseDuration(os.Getenv("VCSIM_INSPECT_INTERVAL")); err == nil { - inspectInterval = d +// inspect retrieves and parses container properties into directly usable struct +// returns: +// +// out - the stdout of the command +// detail - basic struct populated with container details +// err: +// * if c.id is empty, or docker returns "No such object", will return an uninitializedContainer error +// * err from either execution or parsing of json output +func (c *container) inspect() (out []byte, detail containerDetails, err error) { + c.Lock() + id := c.id + c.Unlock() + + if id == "" { + err = uninitializedContainer(errors.New("inspect of uninitialized container")) + return } - var ( - ctx = SpoofContext() - done = make(chan struct{}) - ticker = time.NewTicker(inspectInterval) - ) + var details []containerDetails - stopUpdatingVmFromContainer := func() { - ticker.Stop() - close(done) + cmd := exec.Command("docker", "inspect", c.id) + out, err = cmd.Output() + if eErr, ok := err.(*exec.ExitError); ok { + if strings.Contains(string(eErr.Stderr), "No such object") { + err = uninitializedContainer(errors.New("inspect of uninitialized container")) + } } - destroyVm := func() { - // If the container cannot be found then destroy this VM. - taskRef := vm.DestroyTask(ctx, &types.Destroy_Task{ - This: vm.Self, - }).(*methods.Destroy_TaskBody).Res.Returnval - task := ctx.Map.Get(taskRef).(*Task) + if err != nil { + return + } - // Wait for the task to complete and see if there is an error. - task.Wait() - if task.Info.Error != nil { - vm.logPrintf("failed to destroy vm: err=%v", *task.Info.Error) - } + if err = json.NewDecoder(bytes.NewReader(out)).Decode(&details); err != nil { + return } - updateVmFromContainer := func() { - // Exit the monitor loop if the VM was removed from the API side. - if c.id == "" { - stopUpdatingVmFromContainer() - return - } + if len(details) != 1 { + err = fmt.Errorf("multiple containers (%d) match ID: %s", len(details), c.id) + return + } - if err := c.inspect(vm); err != nil { - // If there is an error inspecting the container because it no - // longer exists, then destroy the VM as well. Please note the - // reason this logic does not invoke stopUpdatingVmFromContainer - // is because that will be handled the next time this function - // is entered and c.id is empty. - if err, ok := err.(*exec.ExitError); ok { - if strings.Contains(string(err.Stderr), "No such object") { - destroyVm() - } - } - } + detail = details[0] + return +} + +// start +// - if the container already exists, start it or unpause it. +func (c *container) start(ctx *Context) error { + c.Lock() + id := c.id + c.Unlock() + + if id == "" { + return uninitializedContainer(errors.New("start of uninitialized container")) } - // Update the VM from the container at regular intervals until the done - // channel is closed. - for { - select { - case <-ticker.C: - ctx.WithLock(vm, updateVmFromContainer) - case <-done: - return - } + start := "start" + _, detail, err := c.inspect() + if err != nil { + return err } -} -// stop the container (if any) for the given vm. -func (c *container) stop(ctx *Context, vm *VirtualMachine) { - if c.id == "" { - return + if detail.State.Paused { + start = "unpause" } - cmd := exec.Command("docker", "stop", c.id) - err := cmd.Run() + cmd := exec.Command("docker", start, c.id) + err = cmd.Run() if err != nil { - log.Printf("%s %s: %s", vm.Name, cmd.Args, err) - } else { - ctx.Map.Update(vm, toolsNotRunning) + log.Printf("%s %s: %s", c.name, cmd.Args, err) } + + return err } // pause the container (if any) for the given vm. -func (c *container) pause(ctx *Context, vm *VirtualMachine) { - if c.id == "" { - return +func (c *container) pause(ctx *Context) error { + c.Lock() + id := c.id + c.Unlock() + + if id == "" { + return uninitializedContainer(errors.New("pause of uninitialized container")) } cmd := exec.Command("docker", "pause", c.id) err := cmd.Run() if err != nil { - log.Printf("%s %s: %s", vm.Name, cmd.Args, err) - } else { - ctx.Map.Update(vm, toolsNotRunning) + log.Printf("%s %s: %s", c.name, cmd.Args, err) } + + return err } // restart the container (if any) for the given vm. -func (c *container) restart(ctx *Context, vm *VirtualMachine) { - if c.id == "" { - return +func (c *container) restart(ctx *Context) error { + c.Lock() + id := c.id + c.Unlock() + + if id == "" { + return uninitializedContainer(errors.New("restart of uninitialized container")) } cmd := exec.Command("docker", "restart", c.id) err := cmd.Run() if err != nil { - log.Printf("%s %s: %s", vm.Name, cmd.Args, err) - } else { - ctx.Map.Update(vm, toolsRunning) + log.Printf("%s %s: %s", c.name, cmd.Args, err) } + + return err } -// remove the container (if any) for the given vm. -func (c *container) remove(vm *VirtualMachine) { - if c.id == "" { - return - } +// stop the container (if any) for the given vm. +func (c *container) stop(ctx *Context) error { + c.Lock() + id := c.id + c.Unlock() - args := [][]string{ - {"rm", "-v", "-f", c.id}, - {"volume", "rm", "-f", c.name}, + if id == "" { + return uninitializedContainer(errors.New("stop of uninitialized container")) } - for i := range args { - cmd := exec.Command("docker", args[i]...) - err := cmd.Run() - if err != nil { - log.Printf("%s %s: %s", vm.Name, cmd.Args, err) - } + cmd := exec.Command("docker", "stop", c.id) + err := cmd.Run() + if err != nil { + log.Printf("%s %s: %s", c.name, cmd.Args, err) } - c.id = "" + return err } -func (c *container) exec(ctx *Context, vm *VirtualMachine, auth types.BaseGuestAuthentication, args []string) (string, types.BaseMethodFault) { - fault := vm.run.prepareGuestOperation(vm, auth) - if fault != nil { - return "", fault +// exec invokes the specified command, with executable being the first of the args, in the specified container +// returns +// +// string - combined stdout and stderr from command +// err +// * uninitializedContainer error - if c.id is empty +// * err from cmd execution +func (c *container) exec(ctx *Context, args []string) (string, error) { + c.Lock() + id := c.id + c.Unlock() + + if id == "" { + return "", uninitializedContainer(errors.New("exec into uninitialized container")) } - args = append([]string{"exec", vm.run.id}, args...) + args = append([]string{"exec", c.id}, args...) cmd := exec.Command("docker", args...) - res, err := cmd.CombinedOutput() if err != nil { - log.Printf("%s: %s (%s)", vm.Self, cmd.Args, string(res)) - return "", new(types.GuestOperationsFault) + log.Printf("%s: %s (%s)", c.name, cmd.Args, string(res)) + return "", err } return strings.TrimSpace(string(res)), nil } -// From https://docs.docker.com/engine/reference/commandline/cp/ : -// > It is not possible to copy certain system files such as resources under /proc, /sys, /dev, tmpfs, and mounts created by the user in the container. -// > However, you can still copy such files by manually running tar in docker exec. -func guestUpload(id string, file string, r *http.Request) error { - cmd := exec.Command("docker", "exec", "-i", id, "tar", "Cxf", path.Dir(file), "-") - cmd.Stderr = os.Stderr - stdin, err := cmd.StdinPipe() +// remove the container (if any) for the given vm. Considers removal of an uninitialized container success. +// Also removes volumes and networks that indicate they are lifecycle coupled with this container. +// returns: +// +// err - joined err from deletion of container and any volumes or networks that have coupled lifecycle +func (c *container) remove(ctx *Context) error { + c.Lock() + defer c.Unlock() + + if c.id == "" { + // consider absence success + return nil + } + + cmd := exec.Command("docker", "rm", "-v", "-f", c.id) + err := cmd.Run() if err != nil { + log.Printf("%s %s: %s", c.name, cmd.Args, err) return err } - if err = cmd.Start(); err != nil { - return err + + cmd = exec.Command("docker", "volume", "ls", "-q", "--filter", "label=container="+c.name, "--filter", "label="+deleteWithContainer) + volumesToReap, lsverr := cmd.Output() + if lsverr != nil { + log.Printf("%s %s: %s", c.name, cmd.Args, lsverr) } + log.Printf("%s volumes: %s", c.name, volumesToReap) - tw := tar.NewWriter(stdin) - _ = tw.WriteHeader(&tar.Header{ - Name: path.Base(file), - Size: r.ContentLength, - Mode: 0444, - ModTime: time.Now(), - }) + var rmverr error + if len(volumesToReap) > 0 { + run := []string{"volume", "rm", "-f"} + run = append(run, strings.Split(string(volumesToReap), "\n")...) + cmd = exec.Command("docker", run...) + out, rmverr := cmd.Output() + if rmverr != nil { + log.Printf("%s %s: %s, %s", c.name, cmd.Args, rmverr, out) + } + } + + cmd = exec.Command("docker", "network", "ls", "-q", "--filter", "label=container="+c.name, "--filter", "label="+deleteWithContainer) + networksToReap, lsnerr := cmd.Output() + if lsnerr != nil { + log.Printf("%s %s: %s", c.name, cmd.Args, lsnerr) + } - _, _ = io.Copy(tw, r.Body) + var rmnerr error + if len(networksToReap) > 0 { + run := []string{"network", "rm", "-f"} + run = append(run, strings.Split(string(volumesToReap), "\n")...) + cmd = exec.Command("docker", run...) + rmnerr = cmd.Run() + if rmnerr != nil { + log.Printf("%s %s: %s", c.name, cmd.Args, rmnerr) + } + } - _ = tw.Close() - _ = stdin.Close() - _ = r.Body.Close() + if err != nil || lsverr != nil || rmverr != nil || lsnerr != nil || rmnerr != nil { + return fmt.Errorf("err: {%s}, lsverr: {%s}, rmverr: {%s}, lsnerr:{%s}, rmerr: {%s}", err, lsverr, rmverr, lsnerr, rmnerr) + } - return cmd.Wait() + if c.cancelWatch != nil { + c.cancelWatch() + eventWatch.ignore(c) + } + c.id = "" + return nil } -func guestDownload(id string, file string, w http.ResponseWriter) error { - cmd := exec.Command("docker", "exec", id, "tar", "Ccf", path.Dir(file), "-", path.Base(file)) - cmd.Stderr = os.Stderr - stdout, err := cmd.StdoutPipe() - if err != nil { - return err +// updated is a simple trigger allowing a caller to indicate that something has likely changed about the container +// and interested parties should re-inspect as needed. +func (c *container) updated() { + consolidationWindow := 250 * time.Millisecond + if d, err := time.ParseDuration(os.Getenv("VCSIM_EVENT_CONSOLIDATION_WINDOW")); err == nil { + consolidationWindow = d } - if err = cmd.Start(); err != nil { - return err + + select { + case c.changes <- struct{}{}: + time.Sleep(consolidationWindow) + // as this is only a hint to avoid waiting for the full inspect interval, we don't care about accumulating + // multiple triggers. We do pause to allow large numbers of sequential updates to consolidate + default: } +} - tr := tar.NewReader(stdout) - header, err := tr.Next() - if err != nil { - return err +// watchContainer monitors the underlying container and updates +// properties based on the container status. This occurs until either +// the container or the VM is removed. +// returns: +// +// err - uninitializedContainer error - if c.id is empty +func (c *container) watchContainer(ctx context.Context, updateFn func(*containerDetails, *container) error) error { + c.Lock() + defer c.Unlock() + + if c.id == "" { + return uninitializedContainer(errors.New("Attempt to watch uninitialized container")) } - w.Header().Set("Content-Length", strconv.FormatInt(header.Size, 10)) - _, _ = io.Copy(w, tr) + eventWatch.watch(c) + + cancelCtx, cancelFunc := context.WithCancel(ctx) + c.cancelWatch = cancelFunc + + // Update the VM from the container at regular intervals until the done + // channel is closed. + go func() { + inspectInterval := 10 * time.Second + if d, err := time.ParseDuration(os.Getenv("VCSIM_INSPECT_INTERVAL")); err == nil { + inspectInterval = d + } + ticker := time.NewTicker(inspectInterval) + + update := func() { + _, details, err := c.inspect() + var rmErr error + var removing bool + if _, ok := err.(uninitializedContainer); ok { + removing = true + rmErr = c.remove(SpoofContext()) + } + + updateErr := updateFn(&details, c) + // if we don't succeed we want to re-try + if removing && rmErr == nil && updateErr == nil { + ticker.Stop() + return + } + if updateErr != nil { + log.Printf("vcsim container watch: %s %s", c.id, updateErr) + } + } + + for { + select { + case <-c.changes: + update() + case <-ticker.C: + update() + case <-cancelCtx.Done(): + return + } + } + }() - return cmd.Wait() + return nil } -const guestPrefix = "/guestFile/" +func (w *eventWatcher) watch(c *container) { + w.Lock() + defer w.Unlock() -// ServeGuest handles container guest file upload/download -func ServeGuest(w http.ResponseWriter, r *http.Request) { - // Real vCenter form: /guestFile?id=139&token=... - // vcsim form: /guestFile/tmp/foo/bar?id=ebc8837b8cb6&token=... + if w.watches == nil { + w.watches = make(map[string]*container) + } - id := r.URL.Query().Get("id") - file := strings.TrimPrefix(r.URL.Path, guestPrefix[:len(guestPrefix)-1]) - var err error + w.watches[c.id] = c - switch r.Method { - case http.MethodPut: - err = guestUpload(id, file, r) - case http.MethodGet: - err = guestDownload(id, file, w) - default: - w.WriteHeader(http.StatusMethodNotAllowed) - return + if w.stdin == nil { + cmd := exec.Command("docker", "events", "--format", "'{{.ID}}'", "--filter", "Type=container") + w.stdout, _ = cmd.StdoutPipe() + w.stdin, _ = cmd.StdinPipe() + err := cmd.Start() + if err != nil { + log.Printf("docker event watcher: %s %s", cmd.Args, err) + w.stdin = nil + w.stdout = nil + w.process = nil + + return + } + + w.process = cmd.Process + + go w.monitor() } +} - if err != nil { - log.Printf("%s %s: %s", r.Method, r.URL, err) - w.WriteHeader(http.StatusInternalServerError) +func (w *eventWatcher) ignore(c *container) { + w.Lock() + + delete(w.watches, c.id) + + if len(w.watches) == 0 && w.stdin != nil { + w.stop() } + + w.Unlock() } -// productSerial returns the uuid in /sys/class/dmi/id/product_serial format -func productSerial(id uuid.UUID) string { - var dst [len(id)*2 + len(id) - 1]byte - - j := 0 - for i := 0; i < len(id); i++ { - hex.Encode(dst[j:j+2], id[i:i+1]) - j += 3 - if j < len(dst) { - s := j - 1 - if s == len(dst)/2 { - dst[s] = '-' - } else { - dst[s] = ' ' - } - } +func (w *eventWatcher) monitor() { + w.Lock() + watches := len(w.watches) + w.Unlock() + + if watches == 0 { + return } - return fmt.Sprintf("VMware-%s", string(dst[:])) + scanner := bufio.NewScanner(w.stdout) + for scanner.Scan() { + id := strings.TrimSpace(scanner.Text()) + + w.Lock() + container := w.watches[id] + w.Unlock() + + if container != nil { + // this is called in a routine to allow an event consolidation window + go container.updated() + } + } } -// productUUID returns the uuid in /sys/class/dmi/id/product_uuid format -func productUUID(id uuid.UUID) string { - var dst [36]byte - - hex.Encode(dst[0:2], id[3:4]) - hex.Encode(dst[2:4], id[2:3]) - hex.Encode(dst[4:6], id[1:2]) - hex.Encode(dst[6:8], id[0:1]) - dst[8] = '-' - hex.Encode(dst[9:11], id[5:6]) - hex.Encode(dst[11:13], id[4:5]) - dst[13] = '-' - hex.Encode(dst[14:16], id[7:8]) - hex.Encode(dst[16:18], id[6:7]) - dst[18] = '-' - hex.Encode(dst[19:23], id[8:10]) - dst[23] = '-' - hex.Encode(dst[24:], id[10:]) - - return strings.ToUpper(string(dst[:])) +func (w *eventWatcher) stop() { + if w.stdin != nil { + w.stdin.Close() + w.stdin = nil + } + if w.stdout != nil { + w.stdout.Close() + w.stdout = nil + } + w.process.Kill() } diff --git a/vendor/github.com/vmware/govmomi/simulator/container_host_system.go b/vendor/github.com/vmware/govmomi/simulator/container_host_system.go new file mode 100644 index 0000000000..c3d283abb7 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/simulator/container_host_system.go @@ -0,0 +1,351 @@ +/* +Copyright (c) 2023-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package simulator + +import ( + "fmt" + "strings" + + "github.com/vmware/govmomi/units" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +const ( + advOptPrefixPnicToUnderlayPrefix = "RUN.underlay." + advOptContainerBackingImage = "RUN.container" + defaultUnderlayBridgeName = "vcsim-underlay" +) + +type simHost struct { + host *HostSystem + c *container +} + +// createSimHostMounts iterates over the provide filesystem mount info, creating docker volumes. It does _not_ delete volumes +// already created if creation of one fails. +// Returns: +// volume mounts: mount options suitable to pass directly to docker +// exec commands: a set of commands to run in the sim host after creation +// error: if construction of the above outputs fails +func createSimHostMounts(ctx *Context, containerName string, mounts []types.HostFileSystemMountInfo) ([]string, [][]string, error) { + var dockerVol []string + var symlinkCmds [][]string + + for i := range mounts { + info := &mounts[i] + name := info.Volume.GetHostFileSystemVolume().Name + + // NOTE: if we ever need persistence cross-invocation we can look at encoding the disk info as a label + labels := []string{"name=" + name, "container=" + containerName, deleteWithContainer} + dockerUuid, err := createVolume("", labels, nil) + if err != nil { + return nil, nil, err + } + + uuid := volumeIDtoHostVolumeUUID(dockerUuid) + name = strings.Replace(name, uuidToken, uuid, -1) + + switch vol := info.Volume.(type) { + case *types.HostVmfsVolume: + vol.BlockSizeMb = 1 + vol.BlockSize = units.KB + vol.UnmapGranularity = units.KB + vol.UnmapPriority = "low" + vol.MajorVersion = 6 + vol.Version = "6.82" + vol.Uuid = uuid + vol.HostFileSystemVolume.Name = name + for e := range vol.Extent { + vol.Extent[e].DiskName = "____simulated_volume_____" + if vol.Extent[e].Partition == 0 { + // HACK: this should be unique within the diskname, but for now this will suffice + // partitions start at 1 + vol.Extent[e].Partition = int32(e + 1) + } + } + vol.Ssd = types.NewBool(true) + vol.Local = types.NewBool(true) + case *types.HostVfatVolume: + vol.HostFileSystemVolume.Name = name + } + + info.VStorageSupport = "vStorageUnsupported" + + info.MountInfo.Path = "/vmfs/volumes/" + uuid + info.MountInfo.Mounted = types.NewBool(true) + info.MountInfo.Accessible = types.NewBool(true) + if info.MountInfo.AccessMode == "" { + info.MountInfo.AccessMode = "readWrite" + } + + opt := "rw" + if info.MountInfo.AccessMode == "readOnly" { + opt = "ro" + } + + dockerVol = append(dockerVol, fmt.Sprintf("%s:/vmfs/volumes/%s:%s", dockerUuid, uuid, opt)) + + // create symlinks from /vmfs/volumes/ for the Volume Name - the direct mount (path) is only the uuid + // ? can we do this via a script in the ESX image instead of via exec? + // ? are the volume names exposed in any manner inside the host? They must be because these mounts exist but where does that come from? Chicken and egg problem? ConfigStore? + symlinkCmds = append(symlinkCmds, []string{"ln", "-s", fmt.Sprintf("/vmfs/volumes/%s", uuid), fmt.Sprintf("/vmfs/volumes/%s", name)}) + if strings.HasPrefix(name, "OSDATA") { + symlinkCmds = append(symlinkCmds, []string{"mkdir", "-p", "/var/lib/vmware"}) + symlinkCmds = append(symlinkCmds, []string{"ln", "-s", fmt.Sprintf("/vmfs/volumes/%s", uuid), "/var/lib/vmware/osdata"}) + } + } + + return dockerVol, symlinkCmds, nil +} + +// createSimHostNetworks creates the networks for the host if not already created. Because we expect multiple hosts on the same network to act as a cluster +// it's likely that only the first host will create networks. +// This includes: +// * bridge network per-pNIC +// * bridge network per-DVS +// +// Returns: +// * array of networks to attach to +// * array of commands to run +// * error +// +// TODO: implement bridge network per DVS - not needed until container backed VMs are "created" on container backed "hosts" +func createSimHostNetworks(ctx *Context, containerName string, networkInfo *types.HostNetworkInfo, advOpts *OptionManager) ([]string, [][]string, error) { + var dockerNet []string + var cmds [][]string + + existingNets := make(map[string]string) + + // a pnic does not have an IP so this is purely a connectivity statement, not a network identity, however this is not how docker works + // so we're going to end up with a veth (our pnic) that does have an IP assigned. That IP will end up being used in a NetConfig structure associated + // with the pNIC. See HostSystem.getNetConfigInterface. + for i := range networkInfo.Pnic { + pnicName := networkInfo.Pnic[i].Device + + bridge := getPnicUnderlay(advOpts, pnicName) + + if pnic, attached := existingNets[bridge]; attached { + return nil, nil, fmt.Errorf("cannot attach multiple pNICs to the same underlay: %s and %s both attempting to connect to %s for %s", pnic, pnicName, bridge, containerName) + } + + _, err := createBridge(bridge) + if err != nil { + return nil, nil, err + } + + dockerNet = append(dockerNet, bridge) + existingNets[bridge] = pnicName + } + + return dockerNet, cmds, nil +} + +func getPnicUnderlay(advOpts *OptionManager, pnicName string) string { + queryRes := advOpts.QueryOptions(&types.QueryOptions{Name: advOptPrefixPnicToUnderlayPrefix + pnicName}).(*methods.QueryOptionsBody).Res + return queryRes.Returnval[0].GetOptionValue().Value.(string) +} + +// createSimulationHostcreates a simHost binding if the host.ConfigManager.AdvancedOption set contains a key "RUN.container". +// If the set does not contain that key, this returns nil. +// Methods on the simHost type are written to check for nil object so the return from this call can be blindly +// assigned and invoked without the caller caring about whether a binding for a backing container was warranted. +// +// The created simhost is based off of the details of the supplied host system. +// VMFS locations are created based on FileSystemMountInfo +// Bridge networks are created to simulate underlay networks - one per pNIC. You cannot connect two pNICs to the same underlay. +// +// On Network connectivity - initially this is using docker network constructs. This means we cannot easily use nested "ip netns" so we cannot +// have a perfect representation of the ESX structure: pnic(veth)->vswtich(bridge)->{vmk,vnic}(veth) +// Instead we have the following: +// * bridge network per underlay - everything connects directly to the underlay +// * VMs/CRXs connect to the underlay dictated by the Uplink pNIC attached to their vSwitch +// * hostd vmknic gets the "host" container IP - we don't currently support multiple vmknics with different IPs +// * no support for mocking VLANs +func createSimulationHost(ctx *Context, host *HostSystem) (*simHost, error) { + sh := &simHost{ + host: host, + } + + advOpts := ctx.Map.Get(host.ConfigManager.AdvancedOption.Reference()).(*OptionManager) + fault := advOpts.QueryOptions(&types.QueryOptions{Name: "RUN.container"}).(*methods.QueryOptionsBody).Fault() + if fault != nil { + if _, ok := fault.VimFault().(*types.InvalidName); ok { + return nil, nil + } + return nil, fmt.Errorf("errror retrieving container backing from host config manager: %+v", fault.VimFault()) + } + + // assemble env + var dockerEnv []string + + var execCmds [][]string + + var err error + + hName := host.Summary.Config.Name + hUuid := host.Summary.Hardware.Uuid + containerName := constructContainerName(hName, hUuid) + + // create volumes and mounts + dockerVol, volCmds, err := createSimHostMounts(ctx, containerName, host.Config.FileSystemVolume.MountInfo) + if err != nil { + return nil, err + } + execCmds = append(execCmds, volCmds...) + + // create networks + dockerNet, netCmds, err := createSimHostNetworks(ctx, containerName, host.Config.Network, advOpts) + if err != nil { + return nil, err + } + execCmds = append(execCmds, netCmds...) + + // create the container + sh.c, err = create(ctx, hName, hUuid, dockerNet, dockerVol, nil, dockerEnv, "alpine", []string{"sleep", "infinity"}) + if err != nil { + return nil, err + } + + // start the container + err = sh.c.start(ctx) + if err != nil { + return nil, err + } + + // run post-creation steps + for _, cmd := range execCmds { + _, err := sh.c.exec(ctx, cmd) + if err != nil { + return nil, err + } + } + + _, detail, err := sh.c.inspect() + + for i := range host.Config.Network.Pnic { + pnic := &host.Config.Network.Pnic[i] + bridge := getPnicUnderlay(advOpts, pnic.Device) + settings := detail.NetworkSettings.Networks[bridge] + + // it doesn't really make sense at an ESX level to set this information as IP bindings are associated with + // vnics (VMs) or vmknics (daemons such as hostd). + // However it's a useful location to stash this info in a manner that can be retrieved at a later date. + pnic.Spec.Ip.IpAddress = settings.IPAddress + pnic.Spec.Ip.SubnetMask = prefixToMask(settings.IPPrefixLen) + + pnic.Mac = settings.MacAddress + } + + // update the active "management" nicType with the container IP for vmnic0 + netconfig, err := host.getNetConfigInterface(ctx, "management") + if err != nil { + return nil, err + } + netconfig.vmk.Spec.Ip.IpAddress = netconfig.uplink.Spec.Ip.IpAddress + netconfig.vmk.Spec.Ip.SubnetMask = netconfig.uplink.Spec.Ip.SubnetMask + netconfig.vmk.Spec.Mac = netconfig.uplink.Mac + + return sh, nil +} + +// remove destroys the container associated with the host and any volumes with labels specifying their lifecycle +// is coupled with the container +func (sh *simHost) remove(ctx *Context) error { + if sh == nil { + return nil + } + + return sh.c.remove(ctx) +} + +// volumeIDtoHostVolumeUUID takes the 64 char docker uuid and converts it into a 32char ESX form of 8-8-4-12 +// Perhaps we should do this using an md5 rehash, but instead we just take the first 32char for ease of cross-reference. +func volumeIDtoHostVolumeUUID(id string) string { + return fmt.Sprintf("%s-%s-%s-%s", id[0:8], id[8:16], id[16:20], id[20:32]) +} + +// By reference to physical system, partition numbering tends to work out like this: +// 1. EFI System (100 MB) +// Free space (1.97 MB) +// 5. Basic Data (4 GB) (bootbank1) +// 6. Basic Data (4 GB) (bootbank2) +// 7. VMFSL (119.9 GB) (os-data) +// 8. VMFS (1 TB) (datastore1) +// I assume the jump from 1 -> 5 harks back to the primary/logical partitions from MBT days +const uuidToken = "%__UUID__%" + +var defaultSimVolumes = []types.HostFileSystemMountInfo{ + { + MountInfo: types.HostMountInfo{ + AccessMode: "readWrite", + }, + Volume: &types.HostVmfsVolume{ + HostFileSystemVolume: types.HostFileSystemVolume{ + Type: "VMFS", + Name: "datastore1", + Capacity: 1 * units.TB, + }, + Extent: []types.HostScsiDiskPartition{ + { + Partition: 8, + }, + }, + }, + }, + { + MountInfo: types.HostMountInfo{ + AccessMode: "readWrite", + }, + Volume: &types.HostVmfsVolume{ + HostFileSystemVolume: types.HostFileSystemVolume{ + Type: "OTHER", + Name: "OSDATA-%__UUID__%", + Capacity: 128 * units.GB, + }, + Extent: []types.HostScsiDiskPartition{ + { + Partition: 7, + }, + }, + }, + }, + { + MountInfo: types.HostMountInfo{ + AccessMode: "readOnly", + }, + Volume: &types.HostVfatVolume{ + HostFileSystemVolume: types.HostFileSystemVolume{ + Type: "OTHER", + Name: "BOOTBANK1", + Capacity: 4 * units.GB, + }, + }, + }, + { + MountInfo: types.HostMountInfo{ + AccessMode: "readOnly", + }, + Volume: &types.HostVfatVolume{ + HostFileSystemVolume: types.HostFileSystemVolume{ + Type: "OTHER", + Name: "BOOTBANK2", + Capacity: 4 * units.GB, + }, + }, + }, +} diff --git a/vendor/github.com/vmware/govmomi/simulator/container_virtual_machine.go b/vendor/github.com/vmware/govmomi/simulator/container_virtual_machine.go new file mode 100644 index 0000000000..a44ad8b977 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/simulator/container_virtual_machine.go @@ -0,0 +1,511 @@ +/* +Copyright (c) 2023-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package simulator + +import ( + "archive/tar" + "context" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "log" + "net/http" + "strconv" + "strings" + + "github.com/google/uuid" + + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" +) + +const ContainerBackingOptionKey = "RUN.container" + +var ( + toolsRunning = []types.PropertyChange{ + {Name: "guest.toolsStatus", Val: types.VirtualMachineToolsStatusToolsOk}, + {Name: "guest.toolsRunningStatus", Val: string(types.VirtualMachineToolsRunningStatusGuestToolsRunning)}, + } + + toolsNotRunning = []types.PropertyChange{ + {Name: "guest.toolsStatus", Val: types.VirtualMachineToolsStatusToolsNotRunning}, + {Name: "guest.toolsRunningStatus", Val: string(types.VirtualMachineToolsRunningStatusGuestToolsNotRunning)}, + } +) + +type simVM struct { + vm *VirtualMachine + c *container +} + +// createSimulationVM inspects the provided VirtualMachine and creates a simVM binding for it if +// the vm.Config.ExtraConfig set contains a key "RUN.container". +// If the ExtraConfig set does not contain that key, this returns nil. +// Methods on the simVM type are written to check for nil object so the return from this call can be blindly +// assigned and invoked without the caller caring about whether a binding for a backing container was warranted. +func createSimulationVM(vm *VirtualMachine) *simVM { + svm := &simVM{ + vm: vm, + } + + for _, opt := range vm.Config.ExtraConfig { + val := opt.GetOptionValue() + if val.Key == ContainerBackingOptionKey { + return svm + } + } + + return nil +} + +// applies container network settings to vm.Guest properties. +func (svm *simVM) syncNetworkConfigToVMGuestProperties() error { + if svm == nil { + return nil + } + + out, detail, err := svm.c.inspect() + if err != nil { + return err + } + + svm.vm.Config.Annotation = "inspect" + svm.vm.logPrintf("%s: %s", svm.vm.Config.Annotation, string(out)) + + netS := detail.NetworkSettings.networkSettings + + // ? Why is this valid - we're taking the first entry while iterating over a MAP + for _, n := range detail.NetworkSettings.Networks { + netS = n + break + } + + if detail.State.Paused { + svm.vm.Runtime.PowerState = types.VirtualMachinePowerStateSuspended + } else if detail.State.Running { + svm.vm.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOn + } else { + svm.vm.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOff + } + + svm.vm.Guest.IpAddress = netS.IPAddress + svm.vm.Summary.Guest.IpAddress = netS.IPAddress + + if len(svm.vm.Guest.Net) != 0 { + net := &svm.vm.Guest.Net[0] + net.IpAddress = []string{netS.IPAddress} + net.MacAddress = netS.MacAddress + net.IpConfig = &types.NetIpConfigInfo{ + IpAddress: []types.NetIpConfigInfoIpAddress{{ + IpAddress: netS.IPAddress, + PrefixLength: int32(netS.IPPrefixLen), + State: string(types.NetIpConfigInfoIpAddressStatusPreferred), + }}, + } + } + + for _, d := range svm.vm.Config.Hardware.Device { + if eth, ok := d.(types.BaseVirtualEthernetCard); ok { + eth.GetVirtualEthernetCard().MacAddress = netS.MacAddress + break + } + } + + return nil +} + +func (svm *simVM) prepareGuestOperation(auth types.BaseGuestAuthentication) types.BaseMethodFault { + if svm == nil || svm.c == nil || svm.c.id == "" { + return new(types.GuestOperationsUnavailable) + } + + if svm.vm.Runtime.PowerState != types.VirtualMachinePowerStatePoweredOn { + return &types.InvalidPowerState{ + RequestedState: types.VirtualMachinePowerStatePoweredOn, + ExistingState: svm.vm.Runtime.PowerState, + } + } + + switch creds := auth.(type) { + case *types.NamePasswordAuthentication: + if creds.Username == "" || creds.Password == "" { + return new(types.InvalidGuestLogin) + } + default: + return new(types.InvalidGuestLogin) + } + + return nil +} + +// populateDMI writes BIOS UUID DMI files to a container volume +func (svm *simVM) populateDMI() error { + if svm.c == nil { + return nil + } + + files := []tarEntry{ + { + &tar.Header{ + Name: "product_uuid", + Mode: 0444, + }, + []byte(productUUID(svm.vm.uid)), + }, + { + &tar.Header{ + Name: "product_serial", + Mode: 0444, + }, + []byte(productSerial(svm.vm.uid)), + }, + } + + _, err := svm.c.createVolume("dmi", []string{deleteWithContainer}, files) + return err +} + +// start runs the container if specified by the RUN.container extraConfig property. +// lazily creates a container backing if specified by an ExtraConfig property with key "RUN.container" +func (svm *simVM) start(ctx *Context) error { + if svm == nil { + return nil + } + + if svm.c != nil && svm.c.id != "" { + err := svm.c.start(ctx) + if err != nil { + log.Printf("%s %s: %s", svm.vm.Name, "start", err) + } else { + ctx.Map.Update(svm.vm, toolsRunning) + } + + return err + } + + var args []string + var env []string + var ports []string + mountDMI := true + + for _, opt := range svm.vm.Config.ExtraConfig { + val := opt.GetOptionValue() + if val.Key == ContainerBackingOptionKey { + run := val.Value.(string) + err := json.Unmarshal([]byte(run), &args) + if err != nil { + args = []string{run} + } + + continue + } + + if val.Key == "RUN.mountdmi" { + var mount bool + err := json.Unmarshal([]byte(val.Value.(string)), &mount) + if err == nil { + mountDMI = mount + } + + continue + } + + if strings.HasPrefix(val.Key, "RUN.port.") { + // ? would this not make more sense as a set of tuples in the value? + // or inlined into the RUN.container freeform string as is the case with the nginx volume in the examples? + sKey := strings.Split(val.Key, ".") + containerPort := sKey[len(sKey)-1] + ports = append(ports, fmt.Sprintf("%s:%s", val.Value.(string), containerPort)) + + continue + } + + if strings.HasPrefix(val.Key, "RUN.env.") { + sKey := strings.Split(val.Key, ".") + envKey := sKey[len(sKey)-1] + env = append(env, fmt.Sprintf("%s=%s", envKey, val.Value.(string))) + } + + if strings.HasPrefix(val.Key, "guestinfo.") { + key := strings.Replace(strings.ToUpper(val.Key), ".", "_", -1) + env = append(env, fmt.Sprintf("VMX_%s=%s", key, val.Value.(string))) + + continue + } + } + + if len(args) == 0 { + // not an error - it's simply a simVM that shouldn't be backed by a container + return nil + } + + if len(env) != 0 { + // Configure env as the data access method for cloud-init-vmware-guestinfo + env = append(env, "VMX_GUESTINFO=true") + } + + volumes := []string{} + if mountDMI { + volumes = append(volumes, constructVolumeName(svm.vm.Name, svm.vm.uid.String(), "dmi")+":/sys/class/dmi/id") + } + + var err error + svm.c, err = create(ctx, svm.vm.Name, svm.vm.uid.String(), nil, volumes, ports, env, args[0], args[1:]) + if err != nil { + return err + } + + if mountDMI { + // not combined with the test assembling volumes because we want to have the container name first. + // cannot add a label to a volume after creation, so if we want to associate with the container ID the + // container must come first + err = svm.populateDMI() + if err != nil { + return err + } + } + + err = svm.c.start(ctx) + if err != nil { + log.Printf("%s %s: %s %s", svm.vm.Name, "start", args, err) + return err + } + + ctx.Map.Update(svm.vm, toolsRunning) + + svm.vm.logPrintf("%s: %s", args, svm.c.id) + + if err = svm.syncNetworkConfigToVMGuestProperties(); err != nil { + log.Printf("%s inspect %s: %s", svm.vm.Name, svm.c.id, err) + } + + callback := func(details *containerDetails, c *container) error { + spoofctx := SpoofContext() + + if c.id == "" && svm.vm != nil { + // If the container cannot be found then destroy this VM unless the VM is no longer configured for container backing (svm.vm == nil) + taskRef := svm.vm.DestroyTask(spoofctx, &types.Destroy_Task{This: svm.vm.Self}).(*methods.Destroy_TaskBody).Res.Returnval + task, ok := spoofctx.Map.Get(taskRef).(*Task) + if !ok { + panic(fmt.Sprintf("couldn't retrieve task for moref %+q while deleting VM %s", taskRef, svm.vm.Name)) + } + + // Wait for the task to complete and see if there is an error. + task.Wait() + if task.Info.Error != nil { + msg := fmt.Sprintf("failed to destroy vm: err=%v", *task.Info.Error) + svm.vm.logPrintf(msg) + + return errors.New(msg) + } + } + + return svm.syncNetworkConfigToVMGuestProperties() + } + + // Start watching the container resource. + err = svm.c.watchContainer(context.Background(), callback) + if _, ok := err.(uninitializedContainer); ok { + // the container has been deleted before we could watch, despite successful launch so clean up. + callback(nil, svm.c) + + // successful launch so nil the error + return nil + } + + return err +} + +// stop the container (if any) for the given vm. +func (svm *simVM) stop(ctx *Context) error { + if svm == nil || svm.c == nil { + return nil + } + + err := svm.c.stop(ctx) + if err != nil { + log.Printf("%s %s: %s", svm.vm.Name, "stop", err) + + return err + } + + ctx.Map.Update(svm.vm, toolsNotRunning) + + return nil +} + +// pause the container (if any) for the given vm. +func (svm *simVM) pause(ctx *Context) error { + if svm == nil || svm.c == nil { + return nil + } + + err := svm.c.pause(ctx) + if err != nil { + log.Printf("%s %s: %s", svm.vm.Name, "pause", err) + + return err + } + + ctx.Map.Update(svm.vm, toolsNotRunning) + + return nil +} + +// restart the container (if any) for the given vm. +func (svm *simVM) restart(ctx *Context) error { + if svm == nil || svm.c == nil { + return nil + } + + err := svm.c.restart(ctx) + if err != nil { + log.Printf("%s %s: %s", svm.vm.Name, "restart", err) + + return err + } + + ctx.Map.Update(svm.vm, toolsRunning) + + return nil +} + +// remove the container (if any) for the given vm. +func (svm *simVM) remove(ctx *Context) error { + if svm == nil || svm.c == nil { + return nil + } + + err := svm.c.remove(ctx) + if err != nil { + log.Printf("%s %s: %s", svm.vm.Name, "remove", err) + + return err + } + + return nil +} + +func (svm *simVM) exec(ctx *Context, auth types.BaseGuestAuthentication, args []string) (string, types.BaseMethodFault) { + if svm == nil || svm.c == nil { + return "", nil + } + + fault := svm.prepareGuestOperation(auth) + if fault != nil { + return "", fault + } + + out, err := svm.c.exec(ctx, args) + if err != nil { + log.Printf("%s: %s (%s)", svm.vm.Name, args, string(out)) + return "", new(types.GuestOperationsFault) + } + + return strings.TrimSpace(string(out)), nil +} + +func guestUpload(id string, file string, r *http.Request) error { + // TODO: decide behaviour for no container + err := copyToGuest(id, file, r.ContentLength, r.Body) + _ = r.Body.Close() + return err +} + +func guestDownload(id string, file string, w http.ResponseWriter) error { + // TODO: decide behaviour for no container + sink := func(len int64, r io.Reader) error { + w.Header().Set("Content-Length", strconv.FormatInt(len, 10)) + _, err := io.Copy(w, r) + return err + } + + err := copyFromGuest(id, file, sink) + return err +} + +const guestPrefix = "/guestFile/" + +// ServeGuest handles container guest file upload/download +func ServeGuest(w http.ResponseWriter, r *http.Request) { + // Real vCenter form: /guestFile?id=139&token=... + // vcsim form: /guestFile/tmp/foo/bar?id=ebc8837b8cb6&token=... + + id := r.URL.Query().Get("id") + file := strings.TrimPrefix(r.URL.Path, guestPrefix[:len(guestPrefix)-1]) + var err error + + switch r.Method { + case http.MethodPut: + err = guestUpload(id, file, r) + case http.MethodGet: + err = guestDownload(id, file, w) + default: + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + if err != nil { + log.Printf("%s %s: %s", r.Method, r.URL, err) + w.WriteHeader(http.StatusInternalServerError) + } +} + +// productSerial returns the uuid in /sys/class/dmi/id/product_serial format +func productSerial(id uuid.UUID) string { + var dst [len(id)*2 + len(id) - 1]byte + + j := 0 + for i := 0; i < len(id); i++ { + hex.Encode(dst[j:j+2], id[i:i+1]) + j += 3 + if j < len(dst) { + s := j - 1 + if s == len(dst)/2 { + dst[s] = '-' + } else { + dst[s] = ' ' + } + } + } + + return fmt.Sprintf("VMware-%s", string(dst[:])) +} + +// productUUID returns the uuid in /sys/class/dmi/id/product_uuid format +func productUUID(id uuid.UUID) string { + var dst [36]byte + + hex.Encode(dst[0:2], id[3:4]) + hex.Encode(dst[2:4], id[2:3]) + hex.Encode(dst[4:6], id[1:2]) + hex.Encode(dst[6:8], id[0:1]) + dst[8] = '-' + hex.Encode(dst[9:11], id[5:6]) + hex.Encode(dst[11:13], id[4:5]) + dst[13] = '-' + hex.Encode(dst[14:16], id[7:8]) + hex.Encode(dst[16:18], id[6:7]) + dst[18] = '-' + hex.Encode(dst[19:23], id[8:10]) + dst[23] = '-' + hex.Encode(dst[24:], id[10:]) + + return strings.ToUpper(string(dst[:])) +} diff --git a/vendor/github.com/vmware/govmomi/simulator/dataset.go b/vendor/github.com/vmware/govmomi/simulator/dataset.go new file mode 100644 index 0000000000..0a1b0627ee --- /dev/null +++ b/vendor/github.com/vmware/govmomi/simulator/dataset.go @@ -0,0 +1,65 @@ +/* +Copyright (c) 2023-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package simulator + +import ( + "github.com/vmware/govmomi/vapi/vm/dataset" +) + +type DataSet struct { + *dataset.Info + ID string + Entries map[string]string +} + +func copyDataSetsForVmClone(src map[string]*DataSet) map[string]*DataSet { + copy := make(map[string]*DataSet, len(src)) + for k, v := range src { + if v.OmitFromSnapshotAndClone { + continue + } + copy[k] = copyDataSet(v) + } + return copy +} + +func copyDataSet(src *DataSet) *DataSet { + if src == nil { + return nil + } + copy := &DataSet{ + Info: &dataset.Info{ + Name: src.Name, + Description: src.Description, + Host: src.Host, + Guest: src.Guest, + Used: src.Used, + OmitFromSnapshotAndClone: src.OmitFromSnapshotAndClone, + }, + ID: src.ID, + Entries: copyEntries(src.Entries), + } + return copy +} + +func copyEntries(src map[string]string) map[string]string { + copy := make(map[string]string, len(src)) + for k, v := range src { + copy[k] = v + } + return copy +} diff --git a/vendor/github.com/vmware/govmomi/simulator/datastore.go b/vendor/github.com/vmware/govmomi/simulator/datastore.go index f341bdd174..277674afef 100644 --- a/vendor/github.com/vmware/govmomi/simulator/datastore.go +++ b/vendor/github.com/vmware/govmomi/simulator/datastore.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -83,6 +83,7 @@ func (ds *Datastore) RefreshDatastore(*types.RefreshDatastore) soap.HasFault { info.Timestamp = types.NewTime(time.Now()) + r.Res = &types.RefreshDatastoreResponse{} return r } diff --git a/vendor/github.com/vmware/govmomi/simulator/doc.go b/vendor/github.com/vmware/govmomi/simulator/doc.go index 441e9a0e7f..61635c32c1 100644 --- a/vendor/github.com/vmware/govmomi/simulator/doc.go +++ b/vendor/github.com/vmware/govmomi/simulator/doc.go @@ -17,6 +17,6 @@ limitations under the License. /* Package simulator is a mock framework for the vSphere API. -See also: https://github.com/vmware/govmomi/blob/master/vcsim/README.md +See also: https://github.com/vmware/govmomi/blob/main/vcsim/README.md */ package simulator diff --git a/vendor/github.com/vmware/govmomi/simulator/environment_browser.go b/vendor/github.com/vmware/govmomi/simulator/environment_browser.go index 4f8ba8ed9e..31b50939ab 100644 --- a/vendor/github.com/vmware/govmomi/simulator/environment_browser.go +++ b/vendor/github.com/vmware/govmomi/simulator/environment_browser.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2019 VMware, Inc. All Rights Reserved. +Copyright (c) 2019-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -29,7 +29,10 @@ import ( type EnvironmentBrowser struct { mo.EnvironmentBrowser - types.QueryConfigOptionResponse + QueryConfigTargetResponse types.QueryConfigTargetResponse + QueryConfigOptionResponse types.QueryConfigOptionResponse + QueryConfigOptionDescriptorResponse types.QueryConfigOptionDescriptorResponse + QueryTargetCapabilitiesResponse types.QueryTargetCapabilitiesResponse } func newEnvironmentBrowser() *types.ManagedObjectReference { @@ -135,7 +138,13 @@ func (b *EnvironmentBrowser) QueryConfigOptionEx(req *types.QueryConfigOptionEx) func (b *EnvironmentBrowser) QueryConfigOptionDescriptor(ctx *Context, req *types.QueryConfigOptionDescriptor) soap.HasFault { body := &methods.QueryConfigOptionDescriptorBody{ - Res: new(types.QueryConfigOptionDescriptorResponse), + Res: &types.QueryConfigOptionDescriptorResponse{ + Returnval: b.QueryConfigOptionDescriptorResponse.Returnval, + }, + } + + if body.Res.Returnval != nil { + return body } body.Res.Returnval = []types.VirtualMachineConfigOptionDescriptor{{ @@ -154,12 +163,18 @@ func (b *EnvironmentBrowser) QueryConfigOptionDescriptor(ctx *Context, req *type func (b *EnvironmentBrowser) QueryConfigTarget(ctx *Context, req *types.QueryConfigTarget) soap.HasFault { body := &methods.QueryConfigTargetBody{ Res: &types.QueryConfigTargetResponse{ - Returnval: &types.ConfigTarget{ - SmcPresent: types.NewBool(false), - }, + Returnval: b.QueryConfigTargetResponse.Returnval, }, } - target := body.Res.Returnval + + if body.Res.Returnval != nil { + return body + } + + target := &types.ConfigTarget{ + SmcPresent: types.NewBool(false), + } + body.Res.Returnval = target var hosts []types.ManagedObjectReference if req.Host == nil { @@ -233,3 +248,22 @@ func (b *EnvironmentBrowser) QueryConfigTarget(ctx *Context, req *types.QueryCon return body } + +func (b *EnvironmentBrowser) QueryTargetCapabilities(ctx *Context, req *types.QueryTargetCapabilities) soap.HasFault { + body := &methods.QueryTargetCapabilitiesBody{ + Res: &types.QueryTargetCapabilitiesResponse{ + Returnval: b.QueryTargetCapabilitiesResponse.Returnval, + }, + } + + if body.Res.Returnval != nil { + return body + } + + body.Res.Returnval = &types.HostCapability{ + VmotionSupported: true, + MaintenanceModeSupported: true, + } + + return body +} diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/authorization_manager.go b/vendor/github.com/vmware/govmomi/simulator/esx/authorization_manager.go index d76459be9e..38cd244418 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/authorization_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/authorization_manager.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,7 @@ import "github.com/vmware/govmomi/vim25/types" // RoleList is the default template for the AuthorizationManager roleList property. // Capture method: -// govc object.collect -s -dump AuthorizationManager:ha-authmgr roleList +// govc object.collect -s -dump AuthorizationManager:ha-authmgr roleList var RoleList = []types.AuthorizationRole{ { RoleId: -6, diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/datacenter.go b/vendor/github.com/vmware/govmomi/simulator/esx/datacenter.go index c0f95eff9c..374cd9518c 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/datacenter.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/datacenter.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -23,7 +23,7 @@ import ( // Datacenter is the default template for Datacenter properties. // Capture method: -// govc datacenter.info -dump +// govc datacenter.info -dump var Datacenter = mo.Datacenter{ ManagedEntity: mo.ManagedEntity{ ExtensibleManagedObject: mo.ExtensibleManagedObject{ diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/event_manager.go b/vendor/github.com/vmware/govmomi/simulator/esx/event_manager.go index 0a572770f7..f231a3f905 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/event_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/event_manager.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2018 VMware, Inc. All Rights Reserved. +Copyright (c) 2018-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,7 @@ import "github.com/vmware/govmomi/vim25/types" // EventInfo is the default template for the EventManager description.eventInfo property. // Capture method: -// govc object.collect -s -dump EventManager:ha-eventmgr description.eventInfo +// govc object.collect -s -dump EventManager:ha-eventmgr description.eventInfo // The captured list has been manually pruned and FullFormat fields changed to use Go's template variable syntax. var EventInfo = []types.EventDescriptionEventDetail{ { diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/host_config_filesystemvolume.go b/vendor/github.com/vmware/govmomi/simulator/esx/host_config_filesystemvolume.go new file mode 100644 index 0000000000..01c62d0a48 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/simulator/esx/host_config_filesystemvolume.go @@ -0,0 +1,144 @@ +/* +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package esx + +import ( + "github.com/vmware/govmomi/units" + "github.com/vmware/govmomi/vim25/types" +) + +// HostConfigInfo is the default template for the HostSystem config property. +// Capture method: +// govc object.collect -s -dump HostSystem:ha-host config.fileSystemVolume +// - slightly modified for uuids and DiskName +var HostFileSystemVolumeInfo = types.HostFileSystemVolumeInfo{ + VolumeTypeList: []string{"VMFS", "NFS", "NFS41", "vsan", "VVOL", "VFFS", "OTHER", "PMEM"}, + MountInfo: []types.HostFileSystemMountInfo{ + { + MountInfo: types.HostMountInfo{ + Path: "/vmfs/volumes/deadbeef-01234567-89ab-cdef00000003", + AccessMode: "readWrite", + Mounted: types.NewBool(true), + Accessible: types.NewBool(true), + InaccessibleReason: "", + MountFailedReason: "", + }, + Volume: &types.HostVmfsVolume{ + HostFileSystemVolume: types.HostFileSystemVolume{ + Type: "VMFS", + Name: "datastore1", + Capacity: 3.5 * units.TB, + }, + BlockSizeMb: 1, + BlockSize: units.KB, + UnmapGranularity: units.KB, + UnmapPriority: "low", + UnmapBandwidthSpec: (*types.VmfsUnmapBandwidthSpec)(nil), + MaxBlocks: 61 * units.MB, + MajorVersion: 6, + Version: "6.82", + Uuid: "deadbeef-01234567-89ab-cdef00000003", + Extent: []types.HostScsiDiskPartition{ + { + DiskName: "____simulated_volumes_____", + Partition: 8, + }, + }, + VmfsUpgradable: false, + ForceMountedInfo: (*types.HostForceMountedInfo)(nil), + Ssd: types.NewBool(true), + Local: types.NewBool(true), + ScsiDiskType: "", + }, + VStorageSupport: "vStorageUnsupported", + }, + { + MountInfo: types.HostMountInfo{ + Path: "/vmfs/volumes/deadbeef-01234567-89ab-cdef00000002", + AccessMode: "readWrite", + Mounted: types.NewBool(true), + Accessible: types.NewBool(true), + InaccessibleReason: "", + MountFailedReason: "", + }, + Volume: &types.HostVmfsVolume{ + HostFileSystemVolume: types.HostFileSystemVolume{ + Type: "OTHER", + Name: "OSDATA-deadbeef-01234567-89ab-cdef00000002", + Capacity: 128 * units.GB, + }, + BlockSizeMb: 1, + BlockSize: units.KB, + UnmapGranularity: 0, + UnmapPriority: "", + UnmapBandwidthSpec: (*types.VmfsUnmapBandwidthSpec)(nil), + MaxBlocks: 256 * units.KB, + MajorVersion: 1, + Version: "1.00", + Uuid: "deadbeef-01234567-89ab-cdef00000002", + Extent: []types.HostScsiDiskPartition{ + { + DiskName: "____simulated_volumes_____", + Partition: 7, + }, + }, + VmfsUpgradable: false, + ForceMountedInfo: (*types.HostForceMountedInfo)(nil), + Ssd: types.NewBool(true), + Local: types.NewBool(true), + ScsiDiskType: "", + }, + VStorageSupport: "vStorageUnsupported", + }, + { + MountInfo: types.HostMountInfo{ + Path: "/vmfs/volumes/deadbeef-01234567-89ab-cdef00000001", + AccessMode: "readOnly", + Mounted: types.NewBool(true), + Accessible: types.NewBool(true), + InaccessibleReason: "", + MountFailedReason: "", + }, + Volume: &types.HostVfatVolume{ + HostFileSystemVolume: types.HostFileSystemVolume{ + Type: "OTHER", + Name: "BOOTBANK1", + Capacity: 4 * units.GB, + }, + }, + VStorageSupport: "", + }, + { + MountInfo: types.HostMountInfo{ + Path: "/vmfs/volumes/deadbeef-01234567-89ab-cdef00000000", + AccessMode: "readOnly", + Mounted: types.NewBool(true), + Accessible: types.NewBool(true), + InaccessibleReason: "", + MountFailedReason: "", + }, + Volume: &types.HostVfatVolume{ + HostFileSystemVolume: types.HostFileSystemVolume{ + Type: "OTHER", + Name: "BOOTBANK2", + Capacity: 4 * units.GB, + }, + }, + VStorageSupport: "", + }, + }, +} diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/host_config_info.go b/vendor/github.com/vmware/govmomi/simulator/esx/host_config_info.go index fd7877b28c..d56c3b607b 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/host_config_info.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/host_config_info.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,7 @@ import "github.com/vmware/govmomi/vim25/types" // HostConfigInfo is the default template for the HostSystem config property. // Capture method: -// govc object.collect -s -dump HostSystem:ha-host config +// govc object.collect -s -dump HostSystem:ha-host config var HostConfigInfo = types.HostConfigInfo{ Host: types.ManagedObjectReference{Type: "HostSystem", Value: "ha-host"}, Product: types.AboutInfo{ @@ -50,6 +50,7 @@ var HostConfigInfo = types.HostConfigInfo{ ConsoleReservation: (*types.ServiceConsoleReservationInfo)(nil), VirtualMachineReservation: (*types.VirtualMachineMemoryReservationInfo)(nil), StorageDevice: &HostStorageDeviceInfo, + FileSystemVolume: &HostFileSystemVolumeInfo, SystemFile: nil, Network: &types.HostNetworkInfo{ Vswitch: []types.HostVirtualSwitch{ diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/host_firewall_system.go b/vendor/github.com/vmware/govmomi/simulator/esx/host_firewall_system.go index 11c1285aad..46c5dea7e2 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/host_firewall_system.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/host_firewall_system.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,7 @@ import "github.com/vmware/govmomi/vim25/types" // HostFirewallInfo is the default template for the HostSystem config.firewall property. // Capture method: -// govc object.collect -s -dump HostSystem:ha-host config.firewall +// govc object.collect -s -dump HostSystem:ha-host config.firewall var HostFirewallInfo = types.HostFirewallInfo{ DynamicData: types.DynamicData{}, DefaultPolicy: types.HostFirewallDefaultPolicy{ diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/host_hardware_info.go b/vendor/github.com/vmware/govmomi/simulator/esx/host_hardware_info.go index aa633ad34b..a30303fa78 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/host_hardware_info.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/host_hardware_info.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -24,7 +24,8 @@ import ( // HostHardwareInfo is the default template for the HostSystem hardware property. // Capture method: -// govc object.collect -s -dump HostSystem:ha-host hardware +// +// govc object.collect -s -dump HostSystem:ha-host hardware var HostHardwareInfo = &types.HostHardwareInfo{ SystemInfo: types.HostSystemInfo{ Vendor: "VMware, Inc.", diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/host_storage_device_info.go b/vendor/github.com/vmware/govmomi/simulator/esx/host_storage_device_info.go index 9d1ae32dd4..79033344f4 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/host_storage_device_info.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/host_storage_device_info.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,8 @@ import "github.com/vmware/govmomi/vim25/types" // HostStorageDeviceInfo is the default template for the HostSystem config.storageDevice property. // Capture method: -// govc object.collect -s -dump HostSystem:ha-host config.storageDevice +// +// govc object.collect -s -dump HostSystem:ha-host config.storageDevice var HostStorageDeviceInfo = types.HostStorageDeviceInfo{ HostBusAdapter: []types.BaseHostHostBusAdapter{ &types.HostParallelScsiHba{ diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/host_system.go b/vendor/github.com/vmware/govmomi/simulator/esx/host_system.go index 26cd1962f6..2cd0c685d4 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/host_system.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/host_system.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -25,7 +25,8 @@ import ( // HostSystem is the default template for HostSystem properties. // Capture method: -// govc host.info -dump +// +// govc host.info -dump var HostSystem = mo.HostSystem{ ManagedEntity: mo.ManagedEntity{ ExtensibleManagedObject: mo.ExtensibleManagedObject{ @@ -52,7 +53,7 @@ var HostSystem = mo.HostSystem{ DynamicData: types.DynamicData{}, ConnectionState: "connected", PowerState: "poweredOn", - StandbyMode: "", + StandbyMode: "none", InMaintenanceMode: false, BootTime: (*time.Time)(nil), HealthSystemRuntime: &types.HealthSystemRuntime{ diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/performance_manager.go b/vendor/github.com/vmware/govmomi/simulator/esx/performance_manager.go index 532f0ad5b9..52ce6568bd 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/performance_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/performance_manager.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,8 @@ import "github.com/vmware/govmomi/vim25/types" // PerfCounter is the default template for the PerformanceManager perfCounter property. // Capture method: -// govc object.collect -s -dump PerformanceManager:ha-perfmgr perfCounter +// +// govc object.collect -s -dump PerformanceManager:ha-perfmgr perfCounter var PerfCounter = []types.PerfCounterInfo{ { Key: 0, diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/performance_manager_data.go b/vendor/github.com/vmware/govmomi/simulator/esx/performance_manager_data.go index 8d0eaca304..45c641e7f0 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/performance_manager_data.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/performance_manager_data.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2018-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/resource_pool.go b/vendor/github.com/vmware/govmomi/simulator/esx/resource_pool.go index 90382dd326..2373311aaa 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/resource_pool.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/resource_pool.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -25,7 +25,8 @@ import ( // ResourcePool is the default template for ResourcePool properties. // Capture method: -// govc pool.info "*" -dump +// +// govc pool.info "*" -dump var ResourcePool = mo.ResourcePool{ ManagedEntity: mo.ManagedEntity{ ExtensibleManagedObject: mo.ExtensibleManagedObject{ diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/root_folder.go b/vendor/github.com/vmware/govmomi/simulator/esx/root_folder.go index 3aefd1d812..1541de11a6 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/root_folder.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/root_folder.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -23,7 +23,8 @@ import ( // RootFolder is the default template for the ServiceContent rootFolder property. // Capture method: -// govc folder.info -dump / +// +// govc folder.info -dump / var RootFolder = mo.Folder{ ManagedEntity: mo.ManagedEntity{ ExtensibleManagedObject: mo.ExtensibleManagedObject{ diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/service_content.go b/vendor/github.com/vmware/govmomi/simulator/esx/service_content.go index cc8938f878..bb10eeaa55 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/service_content.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/service_content.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,8 @@ import "github.com/vmware/govmomi/vim25/types" // ServiceContent is the default template for the ServiceInstance content property. // Capture method: -// govc object.collect -s -dump - content +// +// govc object.collect -s -dump - content var ServiceContent = types.ServiceContent{ RootFolder: types.ManagedObjectReference{Type: "Folder", Value: "ha-folder-root"}, PropertyCollector: types.ManagedObjectReference{Type: "PropertyCollector", Value: "ha-property-collector"}, diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/setting.go b/vendor/github.com/vmware/govmomi/simulator/esx/setting.go index 757dfc039c..54ec6ead07 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/setting.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/setting.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -21,13 +21,20 @@ import "github.com/vmware/govmomi/vim25/types" // HardwareVersion is the default VirtualMachine.Config.Version var HardwareVersion = "vmx-13" -// Setting is captured from ESX's HostSystem.configManager.advancedOption +// AdvancedOptions is captured from ESX's HostSystem.configManager.advancedOption // Capture method: -// govc object.collect -s -dump $(govc object.collect -s HostSystem:ha-host configManager.advancedOption) setting -var Setting = []types.BaseOptionValue{ +// +// govc object.collect -s -dump $(govc object.collect -s HostSystem:ha-host configManager.advancedOption) setting +var AdvancedOptions = []types.BaseOptionValue{ // This list is currently pruned to include a single option for testing &types.OptionValue{ Key: "Config.HostAgent.log.level", Value: "info", }, } + +// Setting is captured from ESX's HostSystem.ServiceContent.setting +// Capture method: +// +// govc object.collect -s -dump OptionManager:HostAgentSettings setting +var Setting = []types.BaseOptionValue{} diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/task_manager.go b/vendor/github.com/vmware/govmomi/simulator/esx/task_manager.go index b429ad4902..1b09aff0bd 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/task_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/task_manager.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved. +Copyright (c) 2018-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,8 @@ import "github.com/vmware/govmomi/vim25/types" // Description is the default template for the TaskManager description property. // Capture method: -// govc object.collect -s -dump TaskManager:ha-taskmgr description +// +// govc object.collect -s -dump TaskManager:ha-taskmgr description var Description = types.TaskDescription{ MethodInfo: []types.BaseElementDescription{ &types.ElementDescription{ diff --git a/vendor/github.com/vmware/govmomi/simulator/esx/virtual_device.go b/vendor/github.com/vmware/govmomi/simulator/esx/virtual_device.go index 628d7e053d..a229ddceb8 100644 --- a/vendor/github.com/vmware/govmomi/simulator/esx/virtual_device.go +++ b/vendor/github.com/vmware/govmomi/simulator/esx/virtual_device.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -20,8 +20,9 @@ import "github.com/vmware/govmomi/vim25/types" // VirtualDevice is the default set of VirtualDevice types created for a VirtualMachine // Capture method: -// govc vm.create foo -// govc object.collect -s -dump vm/foo config.hardware.device +// +// govc vm.create foo +// govc object.collect -s -dump vm/foo config.hardware.device var VirtualDevice = []types.BaseVirtualDevice{ &types.VirtualIDEController{ VirtualController: types.VirtualController{ diff --git a/vendor/github.com/vmware/govmomi/simulator/guest_id.go b/vendor/github.com/vmware/govmomi/simulator/guest_id.go index 87cf4aaf83..ce107a81de 100644 --- a/vendor/github.com/vmware/govmomi/simulator/guest_id.go +++ b/vendor/github.com/vmware/govmomi/simulator/guest_id.go @@ -53,9 +53,22 @@ var GuestID = []types.VirtualMachineGuestOsIdentifier{ types.VirtualMachineGuestOsIdentifierWindows9Guest, types.VirtualMachineGuestOsIdentifierWindows9_64Guest, types.VirtualMachineGuestOsIdentifierWindows9Server64Guest, + types.VirtualMachineGuestOsIdentifierWindows11_64Guest, + types.VirtualMachineGuestOsIdentifierWindows12_64Guest, types.VirtualMachineGuestOsIdentifierWindowsHyperVGuest, + types.VirtualMachineGuestOsIdentifierWindows2019srv_64Guest, + types.VirtualMachineGuestOsIdentifierWindows2019srvNext_64Guest, + types.VirtualMachineGuestOsIdentifierWindows2022srvNext_64Guest, types.VirtualMachineGuestOsIdentifierFreebsdGuest, types.VirtualMachineGuestOsIdentifierFreebsd64Guest, + types.VirtualMachineGuestOsIdentifierFreebsd11Guest, + types.VirtualMachineGuestOsIdentifierFreebsd11_64Guest, + types.VirtualMachineGuestOsIdentifierFreebsd12Guest, + types.VirtualMachineGuestOsIdentifierFreebsd12_64Guest, + types.VirtualMachineGuestOsIdentifierFreebsd13Guest, + types.VirtualMachineGuestOsIdentifierFreebsd13_64Guest, + types.VirtualMachineGuestOsIdentifierFreebsd14Guest, + types.VirtualMachineGuestOsIdentifierFreebsd14_64Guest, types.VirtualMachineGuestOsIdentifierRedhatGuest, types.VirtualMachineGuestOsIdentifierRhel2Guest, types.VirtualMachineGuestOsIdentifierRhel3Guest, @@ -68,18 +81,24 @@ var GuestID = []types.VirtualMachineGuestOsIdentifier{ types.VirtualMachineGuestOsIdentifierRhel6_64Guest, types.VirtualMachineGuestOsIdentifierRhel7Guest, types.VirtualMachineGuestOsIdentifierRhel7_64Guest, + types.VirtualMachineGuestOsIdentifierRhel8_64Guest, + types.VirtualMachineGuestOsIdentifierRhel9_64Guest, types.VirtualMachineGuestOsIdentifierCentosGuest, types.VirtualMachineGuestOsIdentifierCentos64Guest, types.VirtualMachineGuestOsIdentifierCentos6Guest, types.VirtualMachineGuestOsIdentifierCentos6_64Guest, types.VirtualMachineGuestOsIdentifierCentos7Guest, types.VirtualMachineGuestOsIdentifierCentos7_64Guest, + types.VirtualMachineGuestOsIdentifierCentos8_64Guest, + types.VirtualMachineGuestOsIdentifierCentos9_64Guest, types.VirtualMachineGuestOsIdentifierOracleLinuxGuest, types.VirtualMachineGuestOsIdentifierOracleLinux64Guest, types.VirtualMachineGuestOsIdentifierOracleLinux6Guest, types.VirtualMachineGuestOsIdentifierOracleLinux6_64Guest, types.VirtualMachineGuestOsIdentifierOracleLinux7Guest, types.VirtualMachineGuestOsIdentifierOracleLinux7_64Guest, + types.VirtualMachineGuestOsIdentifierOracleLinux8_64Guest, + types.VirtualMachineGuestOsIdentifierOracleLinux9_64Guest, types.VirtualMachineGuestOsIdentifierSuseGuest, types.VirtualMachineGuestOsIdentifierSuse64Guest, types.VirtualMachineGuestOsIdentifierSlesGuest, @@ -90,6 +109,8 @@ var GuestID = []types.VirtualMachineGuestOsIdentifier{ types.VirtualMachineGuestOsIdentifierSles11_64Guest, types.VirtualMachineGuestOsIdentifierSles12Guest, types.VirtualMachineGuestOsIdentifierSles12_64Guest, + types.VirtualMachineGuestOsIdentifierSles15_64Guest, + types.VirtualMachineGuestOsIdentifierSles16_64Guest, types.VirtualMachineGuestOsIdentifierNld9Guest, types.VirtualMachineGuestOsIdentifierOesGuest, types.VirtualMachineGuestOsIdentifierSjdsGuest, @@ -114,12 +135,18 @@ var GuestID = []types.VirtualMachineGuestOsIdentifier{ types.VirtualMachineGuestOsIdentifierDebian9_64Guest, types.VirtualMachineGuestOsIdentifierDebian10Guest, types.VirtualMachineGuestOsIdentifierDebian10_64Guest, + types.VirtualMachineGuestOsIdentifierDebian11Guest, + types.VirtualMachineGuestOsIdentifierDebian11_64Guest, + types.VirtualMachineGuestOsIdentifierDebian12Guest, + types.VirtualMachineGuestOsIdentifierDebian12_64Guest, types.VirtualMachineGuestOsIdentifierAsianux3Guest, types.VirtualMachineGuestOsIdentifierAsianux3_64Guest, types.VirtualMachineGuestOsIdentifierAsianux4Guest, types.VirtualMachineGuestOsIdentifierAsianux4_64Guest, types.VirtualMachineGuestOsIdentifierAsianux5_64Guest, types.VirtualMachineGuestOsIdentifierAsianux7_64Guest, + types.VirtualMachineGuestOsIdentifierAsianux8_64Guest, + types.VirtualMachineGuestOsIdentifierAsianux9_64Guest, types.VirtualMachineGuestOsIdentifierOpensuseGuest, types.VirtualMachineGuestOsIdentifierOpensuse64Guest, types.VirtualMachineGuestOsIdentifierFedoraGuest, @@ -130,10 +157,16 @@ var GuestID = []types.VirtualMachineGuestOsIdentifier{ types.VirtualMachineGuestOsIdentifierOther26xLinuxGuest, types.VirtualMachineGuestOsIdentifierOtherLinuxGuest, types.VirtualMachineGuestOsIdentifierOther3xLinuxGuest, + types.VirtualMachineGuestOsIdentifierOther4xLinuxGuest, + types.VirtualMachineGuestOsIdentifierOther5xLinuxGuest, + types.VirtualMachineGuestOsIdentifierOther6xLinuxGuest, types.VirtualMachineGuestOsIdentifierGenericLinuxGuest, types.VirtualMachineGuestOsIdentifierOther24xLinux64Guest, types.VirtualMachineGuestOsIdentifierOther26xLinux64Guest, types.VirtualMachineGuestOsIdentifierOther3xLinux64Guest, + types.VirtualMachineGuestOsIdentifierOther4xLinux64Guest, + types.VirtualMachineGuestOsIdentifierOther5xLinux64Guest, + types.VirtualMachineGuestOsIdentifierOther6xLinux64Guest, types.VirtualMachineGuestOsIdentifierOtherLinux64Guest, types.VirtualMachineGuestOsIdentifierSolaris6Guest, types.VirtualMachineGuestOsIdentifierSolaris7Guest, @@ -162,10 +195,24 @@ var GuestID = []types.VirtualMachineGuestOsIdentifier{ types.VirtualMachineGuestOsIdentifierDarwin14_64Guest, types.VirtualMachineGuestOsIdentifierDarwin15_64Guest, types.VirtualMachineGuestOsIdentifierDarwin16_64Guest, + types.VirtualMachineGuestOsIdentifierDarwin17_64Guest, + types.VirtualMachineGuestOsIdentifierDarwin18_64Guest, + types.VirtualMachineGuestOsIdentifierDarwin19_64Guest, + types.VirtualMachineGuestOsIdentifierDarwin20_64Guest, + types.VirtualMachineGuestOsIdentifierDarwin21_64Guest, + types.VirtualMachineGuestOsIdentifierDarwin22_64Guest, + types.VirtualMachineGuestOsIdentifierDarwin23_64Guest, types.VirtualMachineGuestOsIdentifierVmkernelGuest, types.VirtualMachineGuestOsIdentifierVmkernel5Guest, types.VirtualMachineGuestOsIdentifierVmkernel6Guest, types.VirtualMachineGuestOsIdentifierVmkernel65Guest, + types.VirtualMachineGuestOsIdentifierVmkernel7Guest, + types.VirtualMachineGuestOsIdentifierVmkernel8Guest, + types.VirtualMachineGuestOsIdentifierAmazonlinux2_64Guest, + types.VirtualMachineGuestOsIdentifierAmazonlinux3_64Guest, + types.VirtualMachineGuestOsIdentifierCrxPod1Guest, + types.VirtualMachineGuestOsIdentifierRockylinux_64Guest, + types.VirtualMachineGuestOsIdentifierAlmalinux_64Guest, types.VirtualMachineGuestOsIdentifierOtherGuest, types.VirtualMachineGuestOsIdentifierOtherGuest64, } diff --git a/vendor/github.com/vmware/govmomi/simulator/guest_operations_manager.go b/vendor/github.com/vmware/govmomi/simulator/guest_operations_manager.go index 780f44a040..f058835808 100644 --- a/vendor/github.com/vmware/govmomi/simulator/guest_operations_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/guest_operations_manager.go @@ -69,7 +69,7 @@ func guestURL(ctx *Context, vm *VirtualMachine, path string) string { Host: "*", // See guest.FileManager.TransferURL Path: guestPrefix + strings.TrimPrefix(path, "/"), RawQuery: url.Values{ - "id": []string{vm.run.id}, + "id": []string{vm.svm.c.id}, "token": []string{ctx.Session.Key}, }.Encode(), }).String() @@ -79,7 +79,7 @@ func (m *GuestFileManager) InitiateFileTransferToGuest(ctx *Context, req *types. body := new(methods.InitiateFileTransferToGuestBody) vm := ctx.Map.Get(req.Vm).(*VirtualMachine) - err := vm.run.prepareGuestOperation(vm, req.Auth) + err := vm.svm.prepareGuestOperation(req.Auth) if err != nil { body.Fault_ = Fault("", err) return body @@ -96,7 +96,7 @@ func (m *GuestFileManager) InitiateFileTransferFromGuest(ctx *Context, req *type body := new(methods.InitiateFileTransferFromGuestBody) vm := ctx.Map.Get(req.Vm).(*VirtualMachine) - err := vm.run.prepareGuestOperation(vm, req.Auth) + err := vm.svm.prepareGuestOperation(req.Auth) if err != nil { body.Fault_ = Fault("", err) return body @@ -126,7 +126,7 @@ func (m *GuestProcessManager) StartProgramInGuest(ctx *Context, req *types.Start vm := ctx.Map.Get(req.Vm).(*VirtualMachine) - fault := vm.run.prepareGuestOperation(vm, auth) + fault := vm.svm.prepareGuestOperation(auth) if fault != nil { body.Fault_ = Fault("", fault) } @@ -141,7 +141,7 @@ func (m *GuestProcessManager) StartProgramInGuest(ctx *Context, req *types.Start args = append(args, "-e", e) } - args = append(args, vm.run.id, spec.ProgramPath, spec.Arguments) + args = append(args, vm.svm.c.id, spec.ProgramPath, spec.Arguments) spec.ProgramPath = "docker" spec.Arguments = strings.Join(args, " ") @@ -213,7 +213,7 @@ func (m *GuestFileManager) mktemp(ctx *Context, req *types.CreateTemporaryFileIn vm := ctx.Map.Get(req.Vm).(*VirtualMachine) - return vm.run.exec(ctx, vm, req.Auth, args) + return vm.svm.exec(ctx, req.Auth, args) } func (m *GuestFileManager) CreateTemporaryFileInGuest(ctx *Context, req *types.CreateTemporaryFileInGuest) soap.HasFault { @@ -298,7 +298,7 @@ func (m *GuestFileManager) ListFilesInGuest(ctx *Context, req *types.ListFilesIn return body } - res, fault := vm.run.exec(ctx, vm, req.Auth, listFiles(req)) + res, fault := vm.svm.exec(ctx, req.Auth, listFiles(req)) if fault != nil { body.Fault_ = Fault("", fault) return body @@ -317,7 +317,7 @@ func (m *GuestFileManager) DeleteFileInGuest(ctx *Context, req *types.DeleteFile vm := ctx.Map.Get(req.Vm).(*VirtualMachine) - _, fault := vm.run.exec(ctx, vm, req.Auth, args) + _, fault := vm.svm.exec(ctx, req.Auth, args) if fault != nil { body.Fault_ = Fault("", fault) return body @@ -338,7 +338,7 @@ func (m *GuestFileManager) DeleteDirectoryInGuest(ctx *Context, req *types.Delet vm := ctx.Map.Get(req.Vm).(*VirtualMachine) - _, fault := vm.run.exec(ctx, vm, req.Auth, args) + _, fault := vm.svm.exec(ctx, req.Auth, args) if fault != nil { body.Fault_ = Fault("", fault) return body @@ -359,7 +359,7 @@ func (m *GuestFileManager) MakeDirectoryInGuest(ctx *Context, req *types.MakeDir vm := ctx.Map.Get(req.Vm).(*VirtualMachine) - _, fault := vm.run.exec(ctx, vm, req.Auth, args) + _, fault := vm.svm.exec(ctx, req.Auth, args) if fault != nil { body.Fault_ = Fault("", fault) return body @@ -381,7 +381,7 @@ func (m *GuestFileManager) MoveFileInGuest(ctx *Context, req *types.MoveFileInGu vm := ctx.Map.Get(req.Vm).(*VirtualMachine) - _, fault := vm.run.exec(ctx, vm, req.Auth, args) + _, fault := vm.svm.exec(ctx, req.Auth, args) if fault != nil { body.Fault_ = Fault("", fault) return body @@ -399,7 +399,7 @@ func (m *GuestFileManager) MoveDirectoryInGuest(ctx *Context, req *types.MoveDir vm := ctx.Map.Get(req.Vm).(*VirtualMachine) - _, fault := vm.run.exec(ctx, vm, req.Auth, args) + _, fault := vm.svm.exec(ctx, req.Auth, args) if fault != nil { body.Fault_ = Fault("", fault) return body @@ -424,7 +424,7 @@ func (m *GuestFileManager) ChangeFileAttributesInGuest(ctx *Context, req *types. if attr.Permissions != 0 { args := []string{"chmod", fmt.Sprintf("%#o", attr.Permissions), req.GuestFilePath} - _, fault := vm.run.exec(ctx, vm, req.Auth, args) + _, fault := vm.svm.exec(ctx, req.Auth, args) if fault != nil { body.Fault_ = Fault("", fault) return body @@ -443,7 +443,7 @@ func (m *GuestFileManager) ChangeFileAttributesInGuest(ctx *Context, req *types. if c.id != nil { args := []string{c.cmd, fmt.Sprintf("%d", *c.id), req.GuestFilePath} - _, fault := vm.run.exec(ctx, vm, req.Auth, args) + _, fault := vm.svm.exec(ctx, req.Auth, args) if fault != nil { body.Fault_ = Fault("", fault) return body diff --git a/vendor/github.com/vmware/govmomi/simulator/host_datastore_browser.go b/vendor/github.com/vmware/govmomi/simulator/host_datastore_browser.go index 185ebbd853..4725203163 100644 --- a/vendor/github.com/vmware/govmomi/simulator/host_datastore_browser.go +++ b/vendor/github.com/vmware/govmomi/simulator/host_datastore_browser.go @@ -17,7 +17,6 @@ limitations under the License. package simulator import ( - "io/ioutil" "os" "path" "strings" @@ -149,7 +148,7 @@ func (s *searchDatastore) queryMatch(file os.FileInfo) bool { } func (s *searchDatastore) search(ds *types.ManagedObjectReference, folder string, dir string) error { - files, err := ioutil.ReadDir(dir) + files, err := os.ReadDir(dir) if err != nil { tracef("search %s: %s", dir, err) return err @@ -162,11 +161,11 @@ func (s *searchDatastore) search(ds *types.ManagedObjectReference, folder string for _, file := range files { name := file.Name() - - if s.queryMatch(file) { + info, _ := file.Info() + if s.queryMatch(info) { for _, m := range s.SearchSpec.MatchPattern { if ok, _ := path.Match(m, name); ok { - s.addFile(file, &res) + s.addFile(info, &res) break } } diff --git a/vendor/github.com/vmware/govmomi/simulator/host_system.go b/vendor/github.com/vmware/govmomi/simulator/host_system.go index f28101a8c3..fd88cb4978 100644 --- a/vendor/github.com/vmware/govmomi/simulator/host_system.go +++ b/vendor/github.com/vmware/govmomi/simulator/host_system.go @@ -17,8 +17,10 @@ limitations under the License. package simulator import ( + "fmt" "net" "os" + "sync" "time" "github.com/vmware/govmomi/simulator/esx" @@ -30,10 +32,16 @@ import ( var ( hostPortUnique = os.Getenv("VCSIM_HOST_PORT_UNIQUE") == "true" + + globalLock sync.Mutex + // globalHostCount is used to construct unique hostnames. Should be consumed under globalLock. + globalHostCount = 0 ) type HostSystem struct { mo.HostSystem + + sh *simHost } func asHostSystemMO(obj mo.Reference) (*mo.HostSystem, bool) { @@ -72,13 +80,23 @@ func NewHostSystem(host mo.HostSystem) *HostSystem { deepCopy(hs.Config, cfg) hs.Config = cfg + // copy over the reference advanced options so each host can have it's own, allowing hosts to be configured for + // container backing individually + deepCopy(esx.AdvancedOptions, &cfg.Option) + + // add a supported option to the AdvancedOption manager + simOption := types.OptionDef{ElementDescription: types.ElementDescription{Key: advOptContainerBackingImage}} + // TODO: how do we enter patterns here? Or should we stick to a list in the value? + // patterns become necessary if we want to enforce correctness on options for RUN.underlay. or allow RUN.port.xxx + hs.Config.OptionDef = append(hs.Config.OptionDef, simOption) + config := []struct { ref **types.ManagedObjectReference obj mo.Reference }{ {&hs.ConfigManager.DatastoreSystem, &HostDatastoreSystem{Host: &hs.HostSystem}}, {&hs.ConfigManager.NetworkSystem, NewHostNetworkSystem(&hs.HostSystem)}, - {&hs.ConfigManager.AdvancedOption, NewOptionManager(nil, esx.Setting)}, + {&hs.ConfigManager.AdvancedOption, NewOptionManager(nil, nil, &hs.Config.Option)}, {&hs.ConfigManager.FirewallSystem, NewHostFirewallSystem(&hs.HostSystem)}, {&hs.ConfigManager.StorageSystem, NewHostStorageSystem(&hs.HostSystem)}, } @@ -92,12 +110,23 @@ func NewHostSystem(host mo.HostSystem) *HostSystem { return hs } -func (h *HostSystem) configure(spec types.HostConnectSpec, connected bool) { +func (h *HostSystem) configure(ctx *Context, spec types.HostConnectSpec, connected bool) { h.Runtime.ConnectionState = types.HostSystemConnectionStateDisconnected if connected { h.Runtime.ConnectionState = types.HostSystemConnectionStateConnected } - if net.ParseIP(spec.HostName) != nil { + + // lets us construct non-conflicting hostname automatically if omitted + // does not use the unique port instead to avoid constraints on port, such as >1024 + + globalLock.Lock() + instanceID := globalHostCount + globalHostCount++ + globalLock.Unlock() + + if spec.HostName == "" { + spec.HostName = fmt.Sprintf("esx-%d", instanceID) + } else if net.ParseIP(spec.HostName) != nil { h.Config.Network.Vnic[0].Spec.Ip.IpAddress = spec.HostName } @@ -106,6 +135,241 @@ func (h *HostSystem) configure(spec types.HostConnectSpec, connected bool) { id := newUUID(h.Name) h.Summary.Hardware.Uuid = id h.Hardware.SystemInfo.Uuid = id + + var err error + h.sh, err = createSimulationHost(ctx, h) + if err != nil { + panic("failed to create simulation host and no path to return error: " + err.Error()) + } +} + +// configureContainerBacking sets up _this_ host for simulation using a container backing. +// Args: +// +// image - the container image with which to simulate the host +// mounts - array of mount info that should be translated into /vmfs/volumes/... mounts backed by container volumes +// networks - names of bridges to use for underlays. Will create a pNIC for each. The first will be treated as the management network. +// +// Restrictions adopted from createSimulationHost: +// * no mock of VLAN connectivity +// * only a single vmknic, used for "the management IP" +// * pNIC connectivity does not directly impact VMs/vmks using it as uplink +// +// The pnics will be named using standard pattern, ie. vmnic0, vmnic1, ... +// This will sanity check the NetConfig for "management" nicType to ensure that it maps through PortGroup->vSwitch->pNIC to vmnic0. +func (h *HostSystem) configureContainerBacking(ctx *Context, image string, mounts []types.HostFileSystemMountInfo, networks ...string) error { + option := &types.OptionValue{ + Key: advOptContainerBackingImage, + Value: image, + } + + advOpts := ctx.Map.Get(h.ConfigManager.AdvancedOption.Reference()).(*OptionManager) + fault := advOpts.UpdateOptions(&types.UpdateOptions{ChangedValue: []types.BaseOptionValue{option}}).Fault() + if fault != nil { + panic(fault) + } + + h.Config.FileSystemVolume = nil + if mounts != nil { + h.Config.FileSystemVolume = &types.HostFileSystemVolumeInfo{ + VolumeTypeList: []string{"VMFS", "OTHER"}, + MountInfo: mounts, + } + } + + // force at least a management network + if len(networks) == 0 { + networks = []string{defaultUnderlayBridgeName} + } + + // purge pNICs from the template - it makes no sense to keep them for a sim host + h.Config.Network.Pnic = make([]types.PhysicalNic, len(networks)) + + // purge any IPs and MACs associated with existing NetConfigs for the host + for cfgIdx := range h.Config.VirtualNicManagerInfo.NetConfig { + config := &h.Config.VirtualNicManagerInfo.NetConfig[cfgIdx] + for candidateIdx := range config.CandidateVnic { + candidate := &config.CandidateVnic[candidateIdx] + candidate.Spec.Ip.IpAddress = "0.0.0.0" + candidate.Spec.Ip.SubnetMask = "0.0.0.0" + candidate.Spec.Mac = "00:00:00:00:00:00" + } + } + + // The presence of a pNIC is used to indicate connectivity to a specific underlay. We construct an empty pNIC entry and specify the underly via + // host.ConfigManager.AdvancedOptions. The pNIC will be populated with the MAC (accurate) and IP (divergence - we need to stash it somewhere) for the veth. + // We create a NetConfig "management" entry for the first pNIC - this will be populated with the IP of the "host" container. + + // create a pNIC for each underlay + for i, net := range networks { + name := fmt.Sprintf("vmnic%d", i) + + // we don't have a natural field for annotating which pNIC is connected to which network, so stash it in an adv option. + option := &types.OptionValue{ + Key: advOptPrefixPnicToUnderlayPrefix + name, + Value: net, + } + fault = advOpts.UpdateOptions(&types.UpdateOptions{ChangedValue: []types.BaseOptionValue{option}}).Fault() + if fault != nil { + panic(fault) + } + + h.Config.Network.Pnic[i] = types.PhysicalNic{ + Key: "key-vim.host.PhysicalNic-" + name, + Device: name, + Pci: fmt.Sprintf("0000:%2d:00.0", i+1), + Driver: "vcsim-bridge", + DriverVersion: "1.2.10.0", + FirmwareVersion: "1.57, 0x80000185", + LinkSpeed: &types.PhysicalNicLinkInfo{ + SpeedMb: 10000, + Duplex: true, + }, + ValidLinkSpecification: []types.PhysicalNicLinkInfo{ + { + SpeedMb: 10000, + Duplex: true, + }, + }, + Spec: types.PhysicalNicSpec{ + Ip: &types.HostIpConfig{}, + LinkSpeed: (*types.PhysicalNicLinkInfo)(nil), + EnableEnhancedNetworkingStack: types.NewBool(false), + EnsInterruptEnabled: types.NewBool(false), + }, + WakeOnLanSupported: false, + Mac: "00:00:00:00:00:00", + FcoeConfiguration: &types.FcoeConfig{ + PriorityClass: 3, + SourceMac: "00:00:00:00:00:00", + VlanRange: []types.FcoeConfigVlanRange{ + {}, + }, + Capabilities: types.FcoeConfigFcoeCapabilities{}, + FcoeActive: false, + }, + VmDirectPathGen2Supported: types.NewBool(false), + VmDirectPathGen2SupportedMode: "", + ResourcePoolSchedulerAllowed: types.NewBool(false), + ResourcePoolSchedulerDisallowedReason: nil, + AutoNegotiateSupported: types.NewBool(true), + EnhancedNetworkingStackSupported: types.NewBool(false), + EnsInterruptSupported: types.NewBool(false), + RdmaDevice: "", + DpuId: "", + } + } + + // sanity check that everything's hung together sufficiently well + details, err := h.getNetConfigInterface(ctx, "management") + if err != nil { + return err + } + + if details.uplink == nil || details.uplink.Device != "vmnic0" { + return fmt.Errorf("Config provided for host %s does not result in a consistent 'management' NetConfig that's bound to 'vmnic0'", h.Name) + } + + return nil +} + +// netConfigDetails is used to packaged up all the related network entities associated with a NetConfig binding +type netConfigDetails struct { + nicType string + netconfig *types.VirtualNicManagerNetConfig + vmk *types.HostVirtualNic + netstack *types.HostNetStackInstance + portgroup *types.HostPortGroup + vswitch *types.HostVirtualSwitch + uplink *types.PhysicalNic +} + +// getNetConfigInterface returns the set of constructs active for a given nicType (eg. "management", "vmotion") +// This method is provided because the Config structure held by HostSystem is heavily interconnected but serialized and not cross-linked with pointers. +// As such there's a _lot_ of cross-referencing that needs to be done to navigate. +// The pNIC returned is the uplink associated with the vSwitch for the netconfig +func (h *HostSystem) getNetConfigInterface(ctx *Context, nicType string) (*netConfigDetails, error) { + details := &netConfigDetails{ + nicType: nicType, + } + + for i := range h.Config.VirtualNicManagerInfo.NetConfig { + if h.Config.VirtualNicManagerInfo.NetConfig[i].NicType == nicType { + details.netconfig = &h.Config.VirtualNicManagerInfo.NetConfig[i] + break + } + } + if details.netconfig == nil { + return nil, fmt.Errorf("no matching NetConfig for NicType=%s", nicType) + } + + if details.netconfig.SelectedVnic == nil { + return details, nil + } + + vnicKey := details.netconfig.SelectedVnic[0] + for i := range details.netconfig.CandidateVnic { + if details.netconfig.CandidateVnic[i].Key == vnicKey { + details.vmk = &details.netconfig.CandidateVnic[i] + break + } + } + if details.vmk == nil { + panic(fmt.Sprintf("NetConfig for host %s references non-existant vNIC key %s for %s nicType", h.Name, vnicKey, nicType)) + } + + portgroupName := details.vmk.Portgroup + netstackKey := details.vmk.Spec.NetStackInstanceKey + + for i := range h.Config.Network.NetStackInstance { + if h.Config.Network.NetStackInstance[i].Key == netstackKey { + details.netstack = &h.Config.Network.NetStackInstance[i] + break + } + } + if details.netstack == nil { + panic(fmt.Sprintf("NetConfig for host %s references non-existant NetStack key %s for %s nicType", h.Name, netstackKey, nicType)) + } + + for i := range h.Config.Network.Portgroup { + // TODO: confirm correctness of this - seems weird it references the Spec.Name instead of the key like everything else. + if h.Config.Network.Portgroup[i].Spec.Name == portgroupName { + details.portgroup = &h.Config.Network.Portgroup[i] + break + } + } + if details.portgroup == nil { + panic(fmt.Sprintf("NetConfig for host %s references non-existant PortGroup name %s for %s nicType", h.Name, portgroupName, nicType)) + } + + vswitchKey := details.portgroup.Vswitch + for i := range h.Config.Network.Vswitch { + if h.Config.Network.Vswitch[i].Key == vswitchKey { + details.vswitch = &h.Config.Network.Vswitch[i] + break + } + } + if details.vswitch == nil { + panic(fmt.Sprintf("NetConfig for host %s references non-existant vSwitch key %s for %s nicType", h.Name, vswitchKey, nicType)) + } + + if len(details.vswitch.Pnic) != 1 { + // to change this, look at the Active NIC in the NicTeamingPolicy, but for now not worth it + panic(fmt.Sprintf("vSwitch %s for host %s has multiple pNICs associated which is not supported.", vswitchKey, h.Name)) + } + + pnicKey := details.vswitch.Pnic[0] + for i := range h.Config.Network.Pnic { + if h.Config.Network.Pnic[i].Key == pnicKey { + details.uplink = &h.Config.Network.Pnic[i] + break + } + } + if details.uplink == nil { + panic(fmt.Sprintf("NetConfig for host %s references non-existant pNIC key %s for %s nicType", h.Name, pnicKey, nicType)) + } + + return details, nil } func (h *HostSystem) event() types.HostEvent { @@ -207,7 +471,7 @@ func CreateStandaloneHost(ctx *Context, f *Folder, spec types.HostConnectSpec) ( pool := NewResourcePool() host := NewHostSystem(template) - host.configure(spec, false) + host.configure(ctx, spec, false) summary := new(types.ComputeResourceSummary) addComputeResource(summary, host) @@ -222,6 +486,7 @@ func CreateStandaloneHost(ctx *Context, f *Folder, spec types.HostConnectSpec) ( ctx.Map.PutEntity(cr, ctx.Map.NewEntity(host)) host.Summary.Host = &host.Self + host.Config.Host = host.Self ctx.Map.PutEntity(cr, ctx.Map.NewEntity(pool)) @@ -247,6 +512,17 @@ func (h *HostSystem) DestroyTask(ctx *Context, req *types.Destroy_Task) soap.Has f := ctx.Map.getEntityParent(h, "Folder").(*Folder) folderRemoveChild(ctx, &f.Folder, h.Reference()) + err := h.sh.remove(ctx) + + if err != nil { + return nil, &types.RuntimeFault{ + MethodFault: types.MethodFault{ + FaultCause: &types.LocalizedMethodFault{ + Fault: &types.SystemErrorFault{Reason: err.Error()}, + LocalizedMessage: err.Error()}}} + } + + // TODO: should there be events on lifecycle operations as with VMs? return nil, nil }) diff --git a/vendor/github.com/vmware/govmomi/simulator/http_nfc_lease.go b/vendor/github.com/vmware/govmomi/simulator/http_nfc_lease.go index 26e0d299fc..54d312caf1 100644 --- a/vendor/github.com/vmware/govmomi/simulator/http_nfc_lease.go +++ b/vendor/github.com/vmware/govmomi/simulator/http_nfc_lease.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2019 VMware, Inc. All Rights Reserved. +Copyright (c) 2019-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -17,9 +17,11 @@ limitations under the License. package simulator import ( + "crypto/sha1" + "encoding/hex" "fmt" + "hash" "io" - "io/ioutil" "log" "net/http" "os" @@ -32,9 +34,15 @@ import ( "github.com/vmware/govmomi/vim25/types" ) +type metadata struct { + sha1 []byte + size int64 +} + type HttpNfcLease struct { mo.HttpNfcLease - files map[string]string + files map[string]string + metadata map[string]metadata } var ( @@ -62,12 +70,12 @@ func ServeNFC(w http.ResponseWriter, r *http.Request) { } status := http.StatusOK - var dst io.Writer + var dst hash.Hash var src io.ReadCloser switch r.Method { case http.MethodPut, http.MethodPost: - dst = ioutil.Discard + dst = sha1.New() src = r.Body case http.MethodGet: f, err := os.Open(file) @@ -82,6 +90,12 @@ func ServeNFC(w http.ResponseWriter, r *http.Request) { n, err := io.Copy(dst, src) _ = src.Close() + if dst != nil { + lease.metadata[name] = metadata{ + sha1: dst.Sum(nil), + size: n, + } + } msg := fmt.Sprintf("transferred %d bytes", n) if err != nil { @@ -92,16 +106,38 @@ func ServeNFC(w http.ResponseWriter, r *http.Request) { w.WriteHeader(status) } -func NewHttpNfcLease(ctx *Context, entity types.ManagedObjectReference) *HttpNfcLease { +func (l *HttpNfcLease) error(ctx *Context, err *types.LocalizedMethodFault) { + ctx.WithLock(l, func() { + ctx.Map.Update(l, []types.PropertyChange{ + {Name: "state", Val: types.HttpNfcLeaseStateError}, + {Name: "error", Val: err}, + }) + }) +} + +func (l *HttpNfcLease) ready(ctx *Context, entity types.ManagedObjectReference, urls []types.HttpNfcLeaseDeviceUrl) { + info := &types.HttpNfcLeaseInfo{ + Lease: l.Self, + Entity: entity, + DeviceUrl: urls, + LeaseTimeout: 300, + } + + ctx.WithLock(l, func() { + ctx.Map.Update(l, []types.PropertyChange{ + {Name: "state", Val: types.HttpNfcLeaseStateReady}, + {Name: "info", Val: info}, + }) + }) +} + +func newHttpNfcLease(ctx *Context) *HttpNfcLease { lease := &HttpNfcLease{ HttpNfcLease: mo.HttpNfcLease{ - Info: &types.HttpNfcLeaseInfo{ - Entity: entity, - LeaseTimeout: 30000, - }, - State: types.HttpNfcLeaseStateReady, + State: types.HttpNfcLeaseStateInitializing, }, - files: make(map[string]string), + files: make(map[string]string), + metadata: make(map[string]metadata), } ctx.Session.Put(lease) @@ -135,3 +171,28 @@ func (l *HttpNfcLease) HttpNfcLeaseProgress(ctx *Context, req *types.HttpNfcLeas Res: new(types.HttpNfcLeaseProgressResponse), } } + +func (l *HttpNfcLease) getDeviceKey(name string) string { + for _, devUrl := range l.Info.DeviceUrl { + if name == devUrl.TargetId { + return devUrl.Key + } + } + return "unknown" +} + +func (l *HttpNfcLease) HttpNfcLeaseGetManifest(ctx *Context, req *types.HttpNfcLeaseGetManifest) soap.HasFault { + entries := []types.HttpNfcLeaseManifestEntry{} + for name, md := range l.metadata { + entries = append(entries, types.HttpNfcLeaseManifestEntry{ + Key: l.getDeviceKey(name), + Sha1: hex.EncodeToString(md.sha1), + Size: md.size, + }) + } + return &methods.HttpNfcLeaseGetManifestBody{ + Res: &types.HttpNfcLeaseGetManifestResponse{ + Returnval: entries, + }, + } +} diff --git a/vendor/github.com/vmware/govmomi/simulator/internal/server.go b/vendor/github.com/vmware/govmomi/simulator/internal/server.go index 1f814dea29..877eca0dcc 100644 --- a/vendor/github.com/vmware/govmomi/simulator/internal/server.go +++ b/vendor/github.com/vmware/govmomi/simulator/internal/server.go @@ -286,15 +286,18 @@ func (s *Server) wrap() { s.Config.ConnState = func(c net.Conn, cs http.ConnState) { s.mu.Lock() defer s.mu.Unlock() + switch cs { case http.StateNew: - s.wg.Add(1) if _, exists := s.conns[c]; exists { panic("invalid state transition") } if s.conns == nil { s.conns = make(map[net.Conn]http.ConnState) } + // Add c to the set of tracked conns and increment it to the + // waitgroup. + s.wg.Add(1) s.conns[c] = cs if s.closed { // Probably just a socket-late-binding dial from @@ -321,7 +324,14 @@ func (s *Server) wrap() { s.closeConn(c) } case http.StateHijacked, http.StateClosed: - s.forgetConn(c) + // Remove c from the set of tracked conns and decrement it from the + // waitgroup, unless it was previously removed. + if _, ok := s.conns[c]; ok { + delete(s.conns, c) + // Keep Close from returning until the user's ConnState hook + // (if any) finishes. + defer s.wg.Done() + } } if oldHook != nil { oldHook(c, cs) @@ -341,13 +351,3 @@ func (s *Server) closeConnChan(c net.Conn, done chan<- struct{}) { done <- struct{}{} } } - -// forgetConn removes c from the set of tracked conns and decrements it from the -// waitgroup, unless it was previously removed. -// s.mu must be held. -func (s *Server) forgetConn(c net.Conn) { - if _, ok := s.conns[c]; ok { - delete(s.conns, c) - s.wg.Done() - } -} diff --git a/vendor/github.com/vmware/govmomi/simulator/model.go b/vendor/github.com/vmware/govmomi/simulator/model.go index 7d137dd2be..1d65c5944c 100644 --- a/vendor/github.com/vmware/govmomi/simulator/model.go +++ b/vendor/github.com/vmware/govmomi/simulator/model.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017-2021 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,6 @@ import ( "context" "crypto/tls" "fmt" - "io/ioutil" "log" "math/rand" "os" @@ -75,32 +74,32 @@ type Model struct { // Datacenter specifies the number of Datacenter entities to create // Name prefix: DC, vcsim flag: -dc - Datacenter int + Datacenter int `json:"datacenter"` // Portgroup specifies the number of DistributedVirtualPortgroup entities to create per Datacenter // Name prefix: DVPG, vcsim flag: -pg - Portgroup int + Portgroup int `json:"portgroup"` // PortgroupNSX specifies the number NSX backed DistributedVirtualPortgroup entities to create per Datacenter // Name prefix: NSXPG, vcsim flag: -nsx-pg - PortgroupNSX int + PortgroupNSX int `json:"portgroupNSX"` // OpaqueNetwork specifies the number of OpaqueNetwork entities to create per Datacenter, // with Summary.OpaqueNetworkType set to nsx.LogicalSwitch and Summary.OpaqueNetworkId to a random uuid. // Name prefix: NSX, vcsim flag: -nsx - OpaqueNetwork int + OpaqueNetwork int `json:"opaqueNetwork"` // Host specifies the number of standalone HostSystems entities to create per Datacenter // Name prefix: H, vcsim flag: -standalone-host - Host int `json:",omitempty"` + Host int `json:"host,omitempty"` // Cluster specifies the number of ClusterComputeResource entities to create per Datacenter // Name prefix: C, vcsim flag: -cluster - Cluster int + Cluster int `json:"cluster"` // ClusterHost specifies the number of HostSystems entities to create within a Cluster // Name prefix: H, vcsim flag: -host - ClusterHost int `json:",omitempty"` + ClusterHost int `json:"clusterHost,omitempty"` // Pool specifies the number of ResourcePool entities to create per Cluster // Note that every cluster has a root ResourcePool named "Resources", as real vCenter does. @@ -110,13 +109,13 @@ type Model struct { // Note that this flag is not effective on standalone hosts. // For example: /DC0/host/DC0_C0/Resources/DC0_C0_RP1 // Name prefix: RP, vcsim flag: -pool - Pool int + Pool int `json:"pool"` // Datastore specifies the number of Datastore entities to create // Each Datastore will have temporary local file storage and will be mounted // on every HostSystem created by the ModelConfig // Name prefix: LocalDS, vcsim flag: -ds - Datastore int + Datastore int `json:"datastore"` // Machine specifies the number of VirtualMachine entities to create per // ResourcePool. If the pool flag is specified, the specified number of virtual @@ -125,21 +124,21 @@ type Model struct { // prefixed with RP0. On standalone hosts, machines are always deployed into the // root resource pool without any prefix. // Name prefix: VM, vcsim flag: -vm - Machine int + Machine int `json:"machine"` // Folder specifies the number of Datacenter to place within a Folder. // This includes a folder for the Datacenter itself and its host, vm, network and datastore folders. // All resources for the Datacenter are placed within these folders, rather than the top-level folders. // Name prefix: F, vcsim flag: -folder - Folder int + Folder int `json:"folder"` // App specifies the number of VirtualApp to create per Cluster // Name prefix: APP, vcsim flag: -app - App int + App int `json:"app"` // Pod specifies the number of StoragePod to create per Cluster // Name prefix: POD, vcsim flag: -pod - Pod int + Pod int `json:"pod"` // Delay configurations DelayConfig DelayConfig `json:"-"` @@ -368,7 +367,7 @@ func (m *Model) decode(path string, data interface{}) error { func (m *Model) loadMethod(obj mo.Reference, dir string) error { dir = filepath.Join(dir, obj.Reference().Encode()) - info, err := ioutil.ReadDir(dir) + info, err := os.ReadDir(dir) if err != nil { if os.IsNotExist(err) { return nil @@ -477,7 +476,10 @@ func (m *Model) Create() error { ctx := SpoofContext() m.Service = New(NewServiceInstance(ctx, m.ServiceContent, m.RootFolder)) ctx.Map = Map + return m.CreateInfrastructure(ctx) +} +func (m *Model) CreateInfrastructure(ctx *Context) error { client := m.Service.client root := object.NewRootFolder(client) @@ -492,7 +494,7 @@ func (m *Model) Create() error { // 1 NIC per VM, backed by a DVPG if Model.Portgroup > 0 vmnet := esx.EthernetCard.Backing - // addHost adds a cluster host or a stanalone host. + // addHost adds a cluster host or a standalone host. addHost := func(name string, f func(types.HostConnectSpec) (*object.Task, error)) (*object.HostSystem, error) { spec := types.HostConnectSpec{ HostName: name, @@ -820,7 +822,7 @@ func (m *Model) Create() error { } func (m *Model) createTempDir(dc string, name string) (string, error) { - dir, err := ioutil.TempDir("", fmt.Sprintf("govcsim-%s-%s-", dc, name)) + dir, err := os.MkdirTemp("", fmt.Sprintf("govcsim-%s-%s-", dc, name)) if err == nil { m.dirs = append(m.dirs, dir) } @@ -855,7 +857,7 @@ func (m *Model) Remove() { Map.m.Lock() for _, obj := range Map.objects { if vm, ok := obj.(*VirtualMachine); ok { - vm.run.remove(vm) + vm.svm.remove(SpoofContext()) } } Map.m.Unlock() @@ -876,9 +878,10 @@ func (m *Model) Run(f func(context.Context, *vim25.Client) error) error { if err != nil { return err } + // Only force TLS if the provided model didn't have any Service. + m.Service.TLS = new(tls.Config) } - m.Service.TLS = new(tls.Config) m.Service.RegisterEndpoints = true s := m.Service.NewServer() diff --git a/vendor/github.com/vmware/govmomi/simulator/option_manager.go b/vendor/github.com/vmware/govmomi/simulator/option_manager.go index efcdee2153..1dd1688cd6 100644 --- a/vendor/github.com/vmware/govmomi/simulator/option_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/option_manager.go @@ -28,19 +28,45 @@ import ( "github.com/vmware/govmomi/vim25/types" ) +// OptionManager is used in at least two locations for ESX: +// 1. ServiceContent.setting - this is empty on ESX and //TODO on VC +// 2. ConfigManager.advancedOption - this is where the bulk of the ESX settings are found type OptionManager struct { mo.OptionManager + + // mirror is an array to keep in sync with OptionManager.Settings. Necessary because we use append. + // uni-directional - changes made to the mirrored array are not reflected back to Settings + mirror *[]types.BaseOptionValue +} + +func asOptionManager(ctx *Context, obj mo.Reference) (*OptionManager, bool) { + om, ok := ctx.Map.Get(obj.Reference()).(*OptionManager) + return om, ok } -func NewOptionManager(ref *types.ManagedObjectReference, setting []types.BaseOptionValue) object.Reference { +// NewOptionManager constructs the type. If mirror is non-nil it takes precedence over settings, and settings is ignored. +// Args: +// - ref - used to set OptionManager.Self if non-nil +// - setting - initial options, may be nil. +// - mirror - options array to keep updated with the OptionManager.Settings, may be nil. +func NewOptionManager(ref *types.ManagedObjectReference, setting []types.BaseOptionValue, mirror *[]types.BaseOptionValue) object.Reference { s := &OptionManager{} + + s.Setting = setting + if mirror != nil { + s.mirror = mirror + s.Setting = *mirror + } + if ref != nil { s.Self = *ref } - s.Setting = setting + return s } +// init constructs the OptionManager for ServiceContent.setting from the template directories. +// This does _not_ construct the OptionManager for ConfigManager.advancedOption. func (m *OptionManager) init(r *Registry) { if len(m.Setting) == 0 { if r.IsVPX() { @@ -103,6 +129,9 @@ func (m *OptionManager) UpdateOptions(req *types.UpdateOptions) soap.HasFault { } m.Setting = append(m.Setting, change) + if m.mirror != nil { + *m.mirror = m.Setting + } } body.Res = new(types.UpdateOptionsResponse) diff --git a/vendor/github.com/vmware/govmomi/simulator/ovf_manager.go b/vendor/github.com/vmware/govmomi/simulator/ovf_manager.go index 1540b4038e..e9cbb8d298 100644 --- a/vendor/github.com/vmware/govmomi/simulator/ovf_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/ovf_manager.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2019 VMware, Inc. All Rights Reserved. +Copyright (c) 2019-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -111,6 +111,7 @@ func (m *OvfManager) CreateImportSpec(ctx *Context, req *types.CreateImportSpec) ds := ctx.Map.Get(req.Datastore).(*Datastore) path := object.DatastorePath{Datastore: ds.Name} + vapp := &types.VAppConfigSpec{} spec := &types.VirtualMachineImportSpec{ ConfigSpec: types.VirtualMachineConfigSpec{ Name: req.Cisp.EntityName, @@ -122,10 +123,59 @@ func (m *OvfManager) CreateImportSpec(ctx *Context, req *types.CreateImportSpec) NumCPUs: 1, NumCoresPerSocket: 1, MemoryMB: 32, + VAppConfig: vapp, }, ResPoolEntity: &req.ResourcePool, } + index := 0 + for i, product := range env.VirtualSystem.Product { + vapp.Product = append(vapp.Product, types.VAppProductSpec{ + ArrayUpdateSpec: types.ArrayUpdateSpec{ + Operation: types.ArrayUpdateOperationAdd, + }, + Info: &types.VAppProductInfo{ + Key: int32(i), + ClassId: toString(product.Class), + InstanceId: toString(product.Instance), + Name: product.Product, + Vendor: product.Vendor, + Version: product.Version, + }, + }) + + for _, p := range product.Property { + key := product.Key(p) + val := "" + + for _, m := range req.Cisp.PropertyMapping { + if m.Key == key { + val = m.Value + } + } + + vapp.Property = append(vapp.Property, types.VAppPropertySpec{ + ArrayUpdateSpec: types.ArrayUpdateSpec{ + Operation: types.ArrayUpdateOperationAdd, + }, + Info: &types.VAppPropertyInfo{ + Key: int32(index), + ClassId: toString(product.Class), + InstanceId: toString(product.Instance), + Id: p.Key, + Category: product.Category, + Label: toString(p.Label), + Type: p.Type, + UserConfigurable: p.UserConfigurable, + DefaultValue: toString(p.Default), + Value: val, + Description: toString(p.Description), + }, + }) + index++ + } + } + if req.Cisp.DeploymentOption == "" && env.DeploymentOption != nil { for _, c := range env.DeploymentOption.Configuration { if isTrue(c.Default) { diff --git a/vendor/github.com/vmware/govmomi/simulator/performance_manager.go b/vendor/github.com/vmware/govmomi/simulator/performance_manager.go index 2bd8bf5f6f..1319b3c496 100644 --- a/vendor/github.com/vmware/govmomi/simulator/performance_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/performance_manager.go @@ -19,6 +19,7 @@ package simulator import ( "math/rand" "strconv" + "strings" "time" "github.com/vmware/govmomi/simulator/esx" @@ -174,9 +175,6 @@ func (p *PerformanceManager) QueryPerf(ctx *Context, req *types.QueryPerf) soap. body.Res.Returnval = make([]types.BasePerfEntityMetricBase, len(req.QuerySpec)) for i, qs := range req.QuerySpec { - metrics := new(types.PerfEntityMetric) - metrics.Entity = qs.Entity - // Get metric data for this entity type metricData, ok := p.metricData[qs.Entity.Type] if !ok { @@ -202,10 +200,13 @@ func (p *PerformanceManager) QueryPerf(ctx *Context, req *types.QueryPerf) soap. interval = 20 // TODO: Determine from entity type } n := 1 + int32(end.Sub(start).Seconds())/interval - if n > qs.MaxSample { + if qs.MaxSample > 0 && n > qs.MaxSample { n = qs.MaxSample } + metrics := new(types.PerfEntityMetric) + metrics.Entity = qs.Entity + // Loop through each interval "tick" metrics.SampleInfo = make([]types.PerfSampleInfo, n) metrics.Value = make([]types.BasePerfMetricSeries, len(qs.MetricId)) @@ -213,10 +214,11 @@ func (p *PerformanceManager) QueryPerf(ctx *Context, req *types.QueryPerf) soap. metrics.SampleInfo[tick] = types.PerfSampleInfo{Timestamp: end.Add(time.Duration(-interval*tick) * time.Second), Interval: interval} } + series := make([]*types.PerfMetricIntSeries, len(qs.MetricId)) for j, mid := range qs.MetricId { // Create list of metrics for this tick - series := &types.PerfMetricIntSeries{Value: make([]int64, n)} - series.Id = mid + series[j] = &types.PerfMetricIntSeries{Value: make([]int64, n)} + series[j].Id = mid points := metricData[mid.CounterId] offset := int64(start.Unix()) / int64(interval) @@ -237,11 +239,56 @@ func (p *PerformanceManager) QueryPerf(ctx *Context, req *types.QueryPerf) soap. } else { p = 0 } - series.Value[tick] = p + series[j].Value[tick] = p } - metrics.Value[j] = series + metrics.Value[j] = series[j] + } + + if qs.Format == string(types.PerfFormatCsv) { + metricsCsv := new(types.PerfEntityMetricCSV) + metricsCsv.Entity = qs.Entity + + //PerfSampleInfo encoded in the following CSV format: [interval1], [date1], [interval2], [date2], and so on. + metricsCsv.SampleInfoCSV = sampleInfoCSV(metrics) + metricsCsv.Value = make([]types.PerfMetricSeriesCSV, len(qs.MetricId)) + + for j, mid := range qs.MetricId { + seriesCsv := &types.PerfMetricSeriesCSV{Value: ""} + seriesCsv.Id = mid + seriesCsv.Value = valueCSV(series[j]) + metricsCsv.Value[j] = *seriesCsv + } + + body.Res.Returnval[i] = metricsCsv + } else { + body.Res.Returnval[i] = metrics } - body.Res.Returnval[i] = metrics } return body } + +// sampleInfoCSV converts the SampleInfo field to a CSV string +func sampleInfoCSV(m *types.PerfEntityMetric) string { + values := make([]string, len(m.SampleInfo)*2) + + i := 0 + for _, s := range m.SampleInfo { + values[i] = strconv.Itoa(int(s.Interval)) + i++ + values[i] = s.Timestamp.Format(time.RFC3339) + i++ + } + + return strings.Join(values, ",") +} + +// valueCSV converts the Value field to a CSV string +func valueCSV(s *types.PerfMetricIntSeries) string { + values := make([]string, len(s.Value)) + + for i := range s.Value { + values[i] = strconv.FormatInt(s.Value[i], 10) + } + + return strings.Join(values, ",") +} diff --git a/vendor/github.com/vmware/govmomi/simulator/property_collector.go b/vendor/github.com/vmware/govmomi/simulator/property_collector.go index 44112b5a22..851a32f7b8 100644 --- a/vendor/github.com/vmware/govmomi/simulator/property_collector.go +++ b/vendor/github.com/vmware/govmomi/simulator/property_collector.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -240,6 +240,13 @@ func isFalse(v *bool) bool { return v == nil || !*v } +func toString(v *string) string { + if v == nil { + return "" + } + return *v +} + func lcFirst(s string) string { return strings.ToLower(s[:1]) + s[1:] } diff --git a/vendor/github.com/vmware/govmomi/simulator/registry.go b/vendor/github.com/vmware/govmomi/simulator/registry.go index c91af59e2a..4b3e330607 100644 --- a/vendor/github.com/vmware/govmomi/simulator/registry.go +++ b/vendor/github.com/vmware/govmomi/simulator/registry.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017-2021 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -577,8 +577,8 @@ func (r *Registry) MarshalJSON() ([]byte, error) { defer r.m.Unlock() vars := struct { - Objects int - Locks int + Objects int `json:"objects"` + Locks int `json:"locks"` }{ len(r.objects), len(r.locks), diff --git a/vendor/github.com/vmware/govmomi/simulator/resource_pool.go b/vendor/github.com/vmware/govmomi/simulator/resource_pool.go index a5f5a9aa25..eeab93af74 100644 --- a/vendor/github.com/vmware/govmomi/simulator/resource_pool.go +++ b/vendor/github.com/vmware/govmomi/simulator/resource_pool.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -217,59 +217,98 @@ func (p *ResourcePool) ImportVApp(ctx *Context, req *types.ImportVApp) soap.HasF folder = ctx.Map.Get(*req.Folder).(*Folder) } - res := folder.CreateVMTask(ctx, &types.CreateVM_Task{ - This: folder.Self, - Config: spec.ConfigSpec, - Pool: p.Self, - Host: req.Host, - }) + lease := newHttpNfcLease(ctx) + ref := lease.Reference() - ctask := ctx.Map.Get(res.(*methods.CreateVM_TaskBody).Res.Returnval).(*Task) - ctask.Wait() + CreateTask(p, "ImportVAppLRO", func(*Task) (types.AnyType, types.BaseMethodFault) { + if vapp, ok := spec.ConfigSpec.VAppConfig.(*types.VAppConfigSpec); ok { + for _, p := range vapp.Property { + if p.Info == nil || isTrue(p.Info.UserConfigurable) { + continue + } + + if p.Info.Value == "" || p.Info.Value == p.Info.DefaultValue { + continue + } + + fault := &types.NotUserConfigurableProperty{ + VAppPropertyFault: types.VAppPropertyFault{ + Id: p.Info.Id, + Category: p.Info.Category, + Label: p.Info.Label, + Type: p.Info.Type, + Value: p.Info.Value, + }, + } - if ctask.Info.Error != nil { - body.Fault_ = Fault("", ctask.Info.Error.Fault) - return body - } + lease.error(ctx, &types.LocalizedMethodFault{ + LocalizedMessage: fmt.Sprintf("Property %s.%s is not user configurable", p.Info.ClassId, p.Info.Id), + Fault: fault, + }) - lease := NewHttpNfcLease(ctx, ctask.Info.Result.(types.ManagedObjectReference)) - ref := lease.Reference() - lease.Info.Lease = ref - - vm := ctx.Map.Get(lease.Info.Entity).(*VirtualMachine) - device := object.VirtualDeviceList(vm.Config.Hardware.Device) - ndevice := make(map[string]int) - for _, d := range device { - info, ok := d.GetVirtualDevice().Backing.(types.BaseVirtualDeviceFileBackingInfo) - if !ok { - continue + return nil, fault + } } - var file object.DatastorePath - file.FromString(info.GetVirtualDeviceFileBackingInfo().FileName) - name := path.Base(file.Path) - ds := vm.findDatastore(file.Datastore) - lease.files[name] = path.Join(ds.Info.GetDatastoreInfo().Url, file.Path) - - _, disk := d.(*types.VirtualDisk) - kind := device.Type(d) - n := ndevice[kind] - ndevice[kind]++ - - lease.Info.DeviceUrl = append(lease.Info.DeviceUrl, types.HttpNfcLeaseDeviceUrl{ - Key: fmt.Sprintf("/%s/%s:%d", vm.Self.Value, kind, n), - ImportKey: fmt.Sprintf("/%s/%s:%d", vm.Name, kind, n), - Url: (&url.URL{ - Scheme: "https", - Host: "*", - Path: nfcPrefix + path.Join(ref.Value, name), - }).String(), - SslThumbprint: "", - Disk: types.NewBool(disk), - TargetId: name, - DatastoreKey: "", - FileSize: 0, + + res := folder.CreateVMTask(ctx, &types.CreateVM_Task{ + This: folder.Self, + Config: spec.ConfigSpec, + Pool: p.Self, + Host: req.Host, }) - } + + ctask := ctx.Map.Get(res.(*methods.CreateVM_TaskBody).Res.Returnval).(*Task) + ctask.Wait() + + if ctask.Info.Error != nil { + lease.error(ctx, ctask.Info.Error) + return nil, ctask.Info.Error.Fault + } + + mref := ctask.Info.Result.(types.ManagedObjectReference) + vm := ctx.Map.Get(mref).(*VirtualMachine) + device := object.VirtualDeviceList(vm.Config.Hardware.Device) + ndevice := make(map[string]int) + var urls []types.HttpNfcLeaseDeviceUrl + + for _, d := range device { + info, ok := d.GetVirtualDevice().Backing.(types.BaseVirtualDeviceFileBackingInfo) + if !ok { + continue + } + var file object.DatastorePath + file.FromString(info.GetVirtualDeviceFileBackingInfo().FileName) + name := path.Base(file.Path) + ds := vm.findDatastore(file.Datastore) + lease.files[name] = path.Join(ds.Info.GetDatastoreInfo().Url, file.Path) + + _, disk := d.(*types.VirtualDisk) + kind := device.Type(d) + n := ndevice[kind] + ndevice[kind]++ + + urls = append(urls, types.HttpNfcLeaseDeviceUrl{ + Key: fmt.Sprintf("/%s/%s:%d", vm.Self.Value, kind, n), + ImportKey: fmt.Sprintf("/%s/%s:%d", vm.Name, kind, n), + Url: (&url.URL{ + Scheme: "https", + Host: "*", + Path: nfcPrefix + path.Join(ref.Value, name), + }).String(), + SslThumbprint: "", + Disk: types.NewBool(disk), + TargetId: name, + DatastoreKey: "", + FileSize: 0, + }) + } + + lease.ready(ctx, mref, urls) + + // TODO: keep this task running until lease timeout or marked completed by the client + + return nil, nil + }).Run(ctx) body.Res = &types.ImportVAppResponse{ Returnval: ref, diff --git a/vendor/github.com/vmware/govmomi/simulator/search_index.go b/vendor/github.com/vmware/govmomi/simulator/search_index.go index 96e296274f..7919386210 100644 --- a/vendor/github.com/vmware/govmomi/simulator/search_index.go +++ b/vendor/github.com/vmware/govmomi/simulator/search_index.go @@ -53,6 +53,14 @@ func (s *SearchIndex) FindByDatastorePath(r *types.FindByDatastorePath) soap.Has func (s *SearchIndex) FindByInventoryPath(req *types.FindByInventoryPath) soap.HasFault { body := &methods.FindByInventoryPathBody{Res: new(types.FindByInventoryPathResponse)} + root := Map.content().RootFolder + o := &root + + if req.InventoryPath == "/" { + body.Res.Returnval = o + return body + } + split := func(c rune) bool { return c == '/' } @@ -61,9 +69,6 @@ func (s *SearchIndex) FindByInventoryPath(req *types.FindByInventoryPath) soap.H return body } - root := Map.content().RootFolder - o := &root - for _, name := range path { f := s.FindChild(&types.FindChild{Entity: *o, Name: name}) diff --git a/vendor/github.com/vmware/govmomi/simulator/session_manager.go b/vendor/github.com/vmware/govmomi/simulator/session_manager.go index 169ea3c41c..e9fbfcb637 100644 --- a/vendor/github.com/vmware/govmomi/simulator/session_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/session_manager.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -20,6 +20,7 @@ import ( "context" "fmt" "net/http" + "net/url" "os" "reflect" "strings" @@ -41,6 +42,7 @@ type SessionManager struct { ServiceHostName string TLSCert func() string + ValidLogin func(*types.Login) bool sessions map[string]Session } @@ -106,22 +108,23 @@ func (m *SessionManager) putSession(s Session) { m.sessions[s.Key] = s } -func (s *SessionManager) validLogin(ctx *Context, req *types.Login) bool { - if ctx.Session != nil { - return false - } - user := ctx.svc.Listen.User - if user == nil || user == DefaultLogin { +func (s *SessionManager) Authenticate(u url.URL, req *types.Login) bool { + if u.User == nil || u.User == DefaultLogin { return req.UserName != "" && req.Password != "" } - pass, _ := user.Password() - return req.UserName == user.Username() && req.Password == pass + + if s.ValidLogin != nil { + return s.ValidLogin(req) + } + + pass, _ := u.User.Password() + return req.UserName == u.User.Username() && req.Password == pass } func (s *SessionManager) Login(ctx *Context, req *types.Login) soap.HasFault { body := new(methods.LoginBody) - if s.validLogin(ctx, req) { + if ctx.Session == nil && s.Authenticate(*ctx.svc.Listen, req) { body.Res = &types.LoginResponse{ Returnval: createSession(ctx, req.UserName, req.Locale), } diff --git a/vendor/github.com/vmware/govmomi/simulator/simulator.go b/vendor/github.com/vmware/govmomi/simulator/simulator.go index 673031fc95..c0532151e1 100644 --- a/vendor/github.com/vmware/govmomi/simulator/simulator.go +++ b/vendor/github.com/vmware/govmomi/simulator/simulator.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -26,7 +26,6 @@ import ( "encoding/pem" "fmt" "io" - "io/ioutil" "log" "net" "net/http" @@ -98,7 +97,7 @@ type Server struct { // New returns an initialized simulator Service instance func New(instance *ServiceInstance) *Service { s := &Service{ - readAll: ioutil.ReadAll, + readAll: io.ReadAll, sm: Map.SessionManager(), sdk: make(map[string]*Registry), } @@ -338,8 +337,8 @@ func (r *response) MarshalXML(e *xml.Encoder, start xml.StartElement) error { // About generates some info about the simulator. func (s *Service) About(w http.ResponseWriter, r *http.Request) { var about struct { - Methods []string - Types []string + Methods []string `json:"methods"` + Types []string `json:"types"` } seen := make(map[string]bool) @@ -421,7 +420,9 @@ func (s *Service) HandleFunc(pattern string, handler func(http.ResponseWriter, * // RegisterSDK adds an HTTP handler for the Registry's Path and Namespace. // If r.Path is already registered, r's objects are added to the existing Registry. -func (s *Service) RegisterSDK(r *Registry) { +// An optional set of aliases can be provided to register the same handler for +// multiple paths. +func (s *Service) RegisterSDK(r *Registry, alias ...string) { if existing, ok := s.sdk[r.Path]; ok { for id, obj := range r.objects { existing.objects[id] = obj @@ -435,6 +436,11 @@ func (s *Service) RegisterSDK(r *Registry) { s.sdk[r.Path] = r s.ServeMux.HandleFunc(r.Path, s.ServeSDK) + + for _, p := range alias { + s.sdk[p] = r + s.ServeMux.HandleFunc(p, s.ServeSDK) + } } // StatusSDK can be used to simulate an /sdk HTTP response code other than 200. @@ -654,12 +660,9 @@ func defaultIP(addr *net.TCPAddr) string { // NewServer returns an http Server instance for the given service func (s *Service) NewServer() *Server { - s.RegisterSDK(Map) + s.RegisterSDK(Map, Map.Path+"/vimService") mux := s.ServeMux - vim := Map.Path + "/vimService" - s.sdk[vim] = s.sdk[vim25.Path] - mux.HandleFunc(vim, s.ServeSDK) mux.HandleFunc(Map.Path+"/vimServiceVersions.xml", s.ServiceVersions) mux.HandleFunc(folderPrefix, s.ServeDatastore) mux.HandleFunc(guestPrefix, ServeGuest) @@ -768,7 +771,7 @@ func (s *Server) CertificateFile() (string, error) { return s.caFile, nil } - f, err := ioutil.TempFile("", "vcsim-") + f, err := os.CreateTemp("", "vcsim-") if err != nil { return "", err } diff --git a/vendor/github.com/vmware/govmomi/simulator/snapshot.go b/vendor/github.com/vmware/govmomi/simulator/snapshot.go index bb1b66f6ff..55d43658d5 100644 --- a/vendor/github.com/vmware/govmomi/simulator/snapshot.go +++ b/vendor/github.com/vmware/govmomi/simulator/snapshot.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import ( type VirtualMachineSnapshot struct { mo.VirtualMachineSnapshot + DataSets map[string]*DataSet } func (v *VirtualMachineSnapshot) createSnapshotFiles() types.BaseMethodFault { @@ -158,6 +159,7 @@ func (v *VirtualMachineSnapshot) RevertToSnapshotTask(ctx *Context, req *types.R vm := ctx.Map.Get(v.Vm).(*VirtualMachine) ctx.WithLock(vm, func() { + vm.DataSets = copyDataSetsForVmClone(v.DataSets) ctx.Map.Update(vm, []types.PropertyChange{ {Name: "snapshot.currentSnapshot", Val: v.Self}, }) diff --git a/vendor/github.com/vmware/govmomi/simulator/task.go b/vendor/github.com/vmware/govmomi/simulator/task.go index bd43f7420b..73c52b919c 100644 --- a/vendor/github.com/vmware/govmomi/simulator/task.go +++ b/vendor/github.com/vmware/govmomi/simulator/task.go @@ -110,10 +110,21 @@ func (t *Task) Run(ctx *Context) types.ManagedObjectReference { // in most cases, the caller already holds this lock, and we would like // the lock to be held across the "hand off" to the async goroutine. - unlock := vimMap.AcquireLock(ctx, tr) - + // however, with a TaskDelay, PropertyCollector (for example) cannot read + // any object properties while the lock is held. + handoff := true + if v, ok := TaskDelay.MethodDelay["LockHandoff"]; ok { + handoff = v != 0 + } + var unlock func() + if handoff { + unlock = vimMap.AcquireLock(ctx, tr) + } go func() { TaskDelay.delay(t.Info.Name) + if !handoff { + unlock = vimMap.AcquireLock(ctx, tr) + } res, err := t.Execute(t) unlock() diff --git a/vendor/github.com/vmware/govmomi/simulator/view_manager.go b/vendor/github.com/vmware/govmomi/simulator/view_manager.go index 62d91bcc47..94e1d5265c 100644 --- a/vendor/github.com/vmware/govmomi/simulator/view_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/view_manager.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -154,6 +154,8 @@ func walk(root mo.Reference, f func(child types.ManagedObjectReference)) { children = []types.ManagedObjectReference{e.VmFolder, e.HostFolder, e.DatastoreFolder, e.NetworkFolder} case *mo.Folder: children = e.ChildEntity + case *mo.StoragePod: + children = e.ChildEntity case *mo.ComputeResource: children = e.Host children = append(children, *e.ResourcePool) @@ -225,8 +227,8 @@ func (m *ViewManager) CreateListView(ctx *Context, req *types.CreateListView) so body := new(methods.CreateListViewBody) list := new(ListView) - if err := list.add(req.Obj); err != nil { - body.Fault_ = Fault("", err) + if refs := list.add(ctx, req.Obj); len(refs) != 0 { + body.Fault_ = Fault("", &types.ManagedObjectNotFound{Obj: refs[0]}) return body } @@ -243,19 +245,20 @@ type ListView struct { mo.ListView } -func (v *ListView) update() { - Map.Update(v, []types.PropertyChange{{Name: "view", Val: v.View}}) +func (v *ListView) update(ctx *Context) { + ctx.Map.Update(v, []types.PropertyChange{{Name: "view", Val: v.View}}) } -func (v *ListView) add(refs []types.ManagedObjectReference) *types.ManagedObjectNotFound { +func (v *ListView) add(ctx *Context, refs []types.ManagedObjectReference) []types.ManagedObjectReference { + var unresolved []types.ManagedObjectReference for _, ref := range refs { - obj := Map.Get(ref) + obj := ctx.Session.Get(ref) if obj == nil { - return &types.ManagedObjectNotFound{Obj: ref} + unresolved = append(unresolved, ref) } v.View = append(v.View, ref) } - return nil + return unresolved } func (v *ListView) DestroyView(ctx *Context, c *types.DestroyView) soap.HasFault { @@ -263,40 +266,37 @@ func (v *ListView) DestroyView(ctx *Context, c *types.DestroyView) soap.HasFault return destroyView(c.This) } -func (v *ListView) ModifyListView(req *types.ModifyListView) soap.HasFault { - body := new(methods.ModifyListViewBody) +func (v *ListView) ModifyListView(ctx *Context, req *types.ModifyListView) soap.HasFault { + body := &methods.ModifyListViewBody{ + Res: new(types.ModifyListViewResponse), + } + + body.Res.Returnval = v.add(ctx, req.Add) for _, ref := range req.Remove { RemoveReference(&v.View, ref) + if ctx.Map.Get(ref) == nil { + body.Res.Returnval = append(body.Res.Returnval, ref) + } } - if err := v.add(req.Add); err != nil { - body.Fault_ = Fault("", err) - return body - } - - body.Res = new(types.ModifyListViewResponse) - if len(req.Remove) != 0 || len(req.Add) != 0 { - v.update() + v.update(ctx) } return body } -func (v *ListView) ResetListView(req *types.ResetListView) soap.HasFault { - body := new(methods.ResetListViewBody) +func (v *ListView) ResetListView(ctx *Context, req *types.ResetListView) soap.HasFault { + body := &methods.ResetListViewBody{ + Res: new(types.ResetListViewResponse), + } v.View = nil - if err := v.add(req.Obj); err != nil { - body.Fault_ = Fault("", err) - return body - } - - body.Res = new(types.ResetListViewResponse) + body.Res.Returnval = v.add(ctx, req.Obj) - v.update() + v.update(ctx) return body } diff --git a/vendor/github.com/vmware/govmomi/simulator/virtual_machine.go b/vendor/github.com/vmware/govmomi/simulator/virtual_machine.go index 8deeceda7a..98af0865ca 100644 --- a/vendor/github.com/vmware/govmomi/simulator/virtual_machine.go +++ b/vendor/github.com/vmware/govmomi/simulator/virtual_machine.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -19,7 +19,6 @@ package simulator import ( "bytes" "fmt" - "io/ioutil" "log" "net" "os" @@ -43,10 +42,11 @@ import ( type VirtualMachine struct { mo.VirtualMachine + DataSets map[string]*DataSet log string sid int32 - run container + svm *simVM uid uuid.UUID imc *types.CustomizationSpec } @@ -141,6 +141,7 @@ func NewVirtualMachine(ctx *Context, parent types.ManagedObjectReference, spec * InstanceUuid: newUUID(strings.ToUpper(spec.Files.VmPathName)), Version: esx.HardwareVersion, Firmware: string(types.GuestOsDescriptorFirmwareTypeBios), + VAppConfig: spec.VAppConfig, Files: &types.VirtualMachineFileInfo{ SnapshotDirectory: dsPath, SuspendDirectory: dsPath, @@ -165,6 +166,7 @@ func NewVirtualMachine(ctx *Context, parent types.ManagedObjectReference, spec * vm.Summary.QuickStats.GuestHeartbeatStatus = types.ManagedEntityStatusGray vm.Summary.OverallStatus = types.ManagedEntityStatusGreen vm.ConfigStatus = types.ManagedEntityStatusGreen + vm.DataSets = make(map[string]*DataSet) // put vm in the folder only if no errors occurred f, _ := asFolderMO(folder) @@ -336,18 +338,20 @@ func (vm *VirtualMachine) apply(spec *types.VirtualMachineConfigSpec) { // updateVAppProperty updates the simulator VM with the specified VApp properties. func (vm *VirtualMachine) updateVAppProperty(spec *types.VmConfigSpec) types.BaseMethodFault { - ps := make([]types.VAppPropertyInfo, 0) - - if vm.Config.VAppConfig != nil && vm.Config.VAppConfig.GetVmConfigInfo() != nil { - ps = vm.Config.VAppConfig.GetVmConfigInfo().Property + if vm.Config.VAppConfig == nil { + vm.Config.VAppConfig = &types.VmConfigInfo{} } + info := vm.Config.VAppConfig.GetVmConfigInfo() + propertyInfo := info.Property + productInfo := info.Product + for _, prop := range spec.Property { var foundIndex int exists := false // Check if the specified property exists or not. This helps rejecting invalid // operations (e.g., Adding a VApp property that already exists) - for i, p := range ps { + for i, p := range propertyInfo { if p.Key == prop.Info.Key { exists = true foundIndex = i @@ -360,25 +364,54 @@ func (vm *VirtualMachine) updateVAppProperty(spec *types.VmConfigSpec) types.Bas if exists { return new(types.InvalidArgument) } - ps = append(ps, *prop.Info) + propertyInfo = append(propertyInfo, *prop.Info) case types.ArrayUpdateOperationEdit: if !exists { return new(types.InvalidArgument) } - ps[foundIndex] = *prop.Info + propertyInfo[foundIndex] = *prop.Info case types.ArrayUpdateOperationRemove: if !exists { return new(types.InvalidArgument) } - ps = append(ps[:foundIndex], ps[foundIndex+1:]...) + propertyInfo = append(propertyInfo[:foundIndex], propertyInfo[foundIndex+1:]...) } } - if vm.Config.VAppConfig == nil { - vm.Config.VAppConfig = &types.VmConfigInfo{} + for _, prod := range spec.Product { + var foundIndex int + exists := false + // Check if the specified product exists or not. This helps rejecting invalid + // operations (e.g., Adding a VApp product that already exists) + for i, p := range productInfo { + if p.Key == prod.Info.Key { + exists = true + foundIndex = i + break + } + } + + switch prod.Operation { + case types.ArrayUpdateOperationAdd: + if exists { + return new(types.InvalidArgument) + } + productInfo = append(productInfo, *prod.Info) + case types.ArrayUpdateOperationEdit: + if !exists { + return new(types.InvalidArgument) + } + productInfo[foundIndex] = *prod.Info + case types.ArrayUpdateOperationRemove: + if !exists { + return new(types.InvalidArgument) + } + productInfo = append(productInfo[:foundIndex], productInfo[foundIndex+1:]...) + } } - vm.Config.VAppConfig.GetVmConfigInfo().Property = ps + info.Product = productInfo + info.Property = propertyInfo return nil } @@ -394,13 +427,46 @@ func extraConfigKey(key string) string { return key } -func (vm *VirtualMachine) applyExtraConfig(spec *types.VirtualMachineConfigSpec) { +func (vm *VirtualMachine) applyExtraConfig(ctx *Context, spec *types.VirtualMachineConfigSpec) types.BaseMethodFault { + var removedContainerBacking bool var changes []types.PropertyChange for _, c := range spec.ExtraConfig { val := c.GetOptionValue() key := strings.TrimPrefix(extraConfigKey(val.Key), "SET.") if key == val.Key { - vm.Config.ExtraConfig = append(vm.Config.ExtraConfig, c) + keyIndex := -1 + for i := range vm.Config.ExtraConfig { + bov := vm.Config.ExtraConfig[i] + if bov == nil { + continue + } + ov := bov.GetOptionValue() + if ov == nil { + continue + } + if ov.Key == key { + keyIndex = i + break + } + } + if keyIndex < 0 { + vm.Config.ExtraConfig = append(vm.Config.ExtraConfig, c) + } else { + if s, ok := val.Value.(string); ok && s == "" { + if key == ContainerBackingOptionKey { + removedContainerBacking = true + } + // Remove existing element + l := len(vm.Config.ExtraConfig) + vm.Config.ExtraConfig[keyIndex] = vm.Config.ExtraConfig[l-1] + vm.Config.ExtraConfig[l-1] = nil + vm.Config.ExtraConfig = vm.Config.ExtraConfig[:l-1] + } else { + // Update existing element + vm.Config.ExtraConfig[keyIndex].GetOptionValue().Value = val.Value + } + } + continue } changes = append(changes, types.PropertyChange{Name: key, Val: val.Value}) @@ -421,9 +487,52 @@ func (vm *VirtualMachine) applyExtraConfig(spec *types.VirtualMachineConfigSpec) ) } } + + // create the container backing before we publish the updates so the simVM is available before handlers + // get triggered + var fault types.BaseMethodFault + if vm.svm == nil { + vm.svm = createSimulationVM(vm) + + // check to see if the VM is already powered on - if so we need to retroactively hit that path here + if vm.Runtime.PowerState == types.VirtualMachinePowerStatePoweredOn { + err := vm.svm.start(ctx) + if err != nil { + // don't attempt to undo the changes already made - just return an error + // we'll retry the svm.start operation on pause/restart calls + fault = &types.VAppConfigFault{ + VimFault: types.VimFault{ + MethodFault: types.MethodFault{ + FaultCause: &types.LocalizedMethodFault{ + Fault: &types.SystemErrorFault{Reason: err.Error()}, + LocalizedMessage: err.Error()}}}} + } + } + } else if removedContainerBacking { + err := vm.svm.remove(ctx) + if err == nil { + // remove link from container to VM so callbacks no longer reflect state + vm.svm.vm = nil + // nil container backing reference to return this to a pure in-mem simulated VM + vm.svm = nil + + } else { + // don't attempt to undo the changes already made - just return an error + // we'll retry the svm.start operation on pause/restart calls + fault = &types.VAppConfigFault{ + VimFault: types.VimFault{ + MethodFault: types.MethodFault{ + FaultCause: &types.LocalizedMethodFault{ + Fault: &types.SystemErrorFault{Reason: err.Error()}, + LocalizedMessage: err.Error()}}}} + } + } + if len(changes) != 0 { Map.Update(vm, changes) } + + return fault } func validateGuestID(id string) types.BaseMethodFault { @@ -838,7 +947,7 @@ func (vm *VirtualMachine) RefreshStorageInfo(ctx *Context, req *types.RefreshSto continue } - files, err := ioutil.ReadDir(directory) + files, err := os.ReadDir(directory) if err != nil { body.Fault_ = Fault("", ctx.Map.FileManager().fault(directory, err, new(types.CannotAccessFile))) return body @@ -849,8 +958,8 @@ func (vm *VirtualMachine) RefreshStorageInfo(ctx *Context, req *types.RefreshSto Datastore: p.Datastore, Path: strings.TrimPrefix(file.Name(), datastore.Info.GetDatastoreInfo().Url), } - - vm.addFileLayoutEx(datastorePath, file.Size()) + info, _ := file.Info() + vm.addFileLayoutEx(datastorePath, info.Size()) } } @@ -1022,8 +1131,9 @@ var vmwOUI = net.HardwareAddr([]byte{0x0, 0xc, 0x29}) // From http://pubs.vmware.com/vsphere-60/index.jsp?topic=%2Fcom.vmware.vsphere.networking.doc%2FGUID-DC7478FF-DC44-4625-9AD7-38208C56A552.html // "The host generates generateMAC addresses that consists of the VMware OUI 00:0C:29 and the last three octets in hexadecimal -// format of the virtual machine UUID. The virtual machine UUID is based on a hash calculated by using the UUID of the -// ESXi physical machine and the path to the configuration file (.vmx) of the virtual machine." +// +// format of the virtual machine UUID. The virtual machine UUID is based on a hash calculated by using the UUID of the +// ESXi physical machine and the path to the configuration file (.vmx) of the virtual machine." func (vm *VirtualMachine) generateMAC(unit int32) string { id := []byte(vm.Config.Uuid) @@ -1465,6 +1575,7 @@ func (vm *VirtualMachine) genVmdkPath(p object.DatastorePath) (string, types.Bas func (vm *VirtualMachine) configureDevices(ctx *Context, spec *types.VirtualMachineConfigSpec) types.BaseMethodFault { devices := object.VirtualDeviceList(vm.Config.Hardware.Device) + var err types.BaseMethodFault for i, change := range spec.DeviceChange { dspec := change.GetVirtualDeviceConfigSpec() device := dspec.Device.GetVirtualDevice() @@ -1501,7 +1612,7 @@ func (vm *VirtualMachine) configureDevices(ctx *Context, spec *types.VirtualMach } key := device.Key - err := vm.configureDevice(ctx, devices, dspec, nil) + err = vm.configureDevice(ctx, devices, dspec, nil) if err != nil { return err } @@ -1528,7 +1639,7 @@ func (vm *VirtualMachine) configureDevices(ctx *Context, spec *types.VirtualMach device.DeviceInfo.GetDescription().Summary = "" // regenerate summary } - err := vm.configureDevice(ctx, devices, dspec, oldDevice) + err = vm.configureDevice(ctx, devices, dspec, oldDevice) if err != nil { return err } @@ -1543,9 +1654,16 @@ func (vm *VirtualMachine) configureDevices(ctx *Context, spec *types.VirtualMach {Name: "config.hardware.device", Val: []types.BaseVirtualDevice(devices)}, }) - vm.updateDiskLayouts() + err = vm.updateDiskLayouts() + if err != nil { + return err + } - vm.applyExtraConfig(spec) // Do this after device config, as some may apply to the devices themselves (e.g. ethernet -> guest.net) + // Do this after device config, as some may apply to the devices themselves (e.g. ethernet -> guest.net) + err = vm.applyExtraConfig(ctx, spec) + if err != nil { + return err + } return nil } @@ -1580,14 +1698,23 @@ func (c *powerVMTask) Run(task *Task) (types.AnyType, types.BaseMethodFault) { return nil, new(types.InvalidState) } - c.run.start(c.ctx, c.VirtualMachine) + err := c.svm.start(c.ctx) + if err != nil { + return nil, &types.MissingPowerOnConfiguration{ + VAppConfigFault: types.VAppConfigFault{ + VimFault: types.VimFault{ + MethodFault: types.MethodFault{ + FaultCause: &types.LocalizedMethodFault{ + Fault: &types.SystemErrorFault{Reason: err.Error()}, + LocalizedMessage: err.Error()}}}}} + } c.ctx.postEvent( &types.VmStartingEvent{VmEvent: event}, &types.VmPoweredOnEvent{VmEvent: event}, ) c.customize(c.ctx) case types.VirtualMachinePowerStatePoweredOff: - c.run.stop(c.ctx, c.VirtualMachine) + c.svm.stop(c.ctx) c.ctx.postEvent( &types.VmStoppingEvent{VmEvent: event}, &types.VmPoweredOffEvent{VmEvent: event}, @@ -1600,7 +1727,7 @@ func (c *powerVMTask) Run(task *Task) (types.AnyType, types.BaseMethodFault) { } } - c.run.pause(c.ctx, c.VirtualMachine) + c.svm.pause(c.ctx) c.ctx.postEvent( &types.VmSuspendingEvent{VmEvent: event}, &types.VmSuspendedEvent{VmEvent: event}, @@ -1707,7 +1834,7 @@ func (vm *VirtualMachine) RebootGuest(ctx *Context, req *types.RebootGuest) soap } if vm.Guest.ToolsRunningStatus == string(types.VirtualMachineToolsRunningStatusGuestToolsRunning) { - vm.run.restart(ctx, vm) + vm.svm.restart(ctx) body.Res = new(types.RebootGuestResponse) } else { body.Fault_ = Fault("", new(types.ToolsUnavailable)) @@ -1771,6 +1898,7 @@ func (vm *VirtualMachine) DestroyTask(ctx *Context, req *types.Destroy_Task) soa task := CreateTask(vm, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) { if dc == nil { return nil, &types.ManagedObjectNotFound{Obj: vm.Self} // If our Parent was destroyed, so were we. + // TODO: should this also trigger container removal? } r := vm.UnregisterVM(ctx, &types.UnregisterVM{ @@ -1795,7 +1923,14 @@ func (vm *VirtualMachine) DestroyTask(ctx *Context, req *types.Destroy_Task) soa Datacenter: &dc.Self, }) - vm.run.remove(vm) + err := vm.svm.remove(ctx) + if err != nil { + return nil, &types.RuntimeFault{ + MethodFault: types.MethodFault{ + FaultCause: &types.LocalizedMethodFault{ + Fault: &types.SystemErrorFault{Reason: err.Error()}, + LocalizedMessage: err.Error()}}} + } return nil, nil }) @@ -1909,6 +2044,7 @@ func (vm *VirtualMachine) CloneVMTask(ctx *Context, req *types.CloneVM_Task) soa } config := types.VirtualMachineConfigSpec{ Name: req.Name, + Version: vm.Config.Version, GuestId: vm.Config.GuestId, Files: &types.VirtualMachineFileInfo{ VmPathName: vmx.String(), @@ -1973,6 +2109,7 @@ func (vm *VirtualMachine) CloneVMTask(ctx *Context, req *types.CloneVM_Task) soa if req.Spec.Config != nil && req.Spec.Config.DeviceChange != nil { clone.configureDevices(ctx, &types.VirtualMachineConfigSpec{DeviceChange: req.Spec.Config.DeviceChange}) } + clone.DataSets = copyDataSetsForVmClone(vm.DataSets) if req.Spec.Template { _ = clone.MarkAsTemplate(&types.MarkAsTemplate{This: clone.Self}) @@ -2178,6 +2315,7 @@ func (vm *VirtualMachine) CreateSnapshotTask(ctx *Context, req *types.CreateSnap snapshot := &VirtualMachineSnapshot{} snapshot.Vm = vm.Reference() snapshot.Config = *vm.Config + snapshot.DataSets = copyDataSetsForVmClone(vm.DataSets) ctx.Map.Put(snapshot) @@ -2235,8 +2373,10 @@ func (vm *VirtualMachine) RevertToCurrentSnapshotTask(ctx *Context, req *types.R return body } + snapshot := ctx.Map.Get(*vm.Snapshot.CurrentSnapshot).(*VirtualMachineSnapshot) task := CreateTask(vm, "revertSnapshot", func(t *Task) (types.AnyType, types.BaseMethodFault) { + vm.DataSets = copyDataSetsForVmClone(snapshot.DataSets) return nil, nil }) @@ -2277,8 +2417,8 @@ func (vm *VirtualMachine) RemoveAllSnapshotsTask(ctx *Context, req *types.Remove func (vm *VirtualMachine) ShutdownGuest(ctx *Context, c *types.ShutdownGuest) soap.HasFault { r := &methods.ShutdownGuestBody{} - // should be poweron - if vm.Runtime.PowerState == types.VirtualMachinePowerStatePoweredOff { + + if vm.Runtime.PowerState != types.VirtualMachinePowerStatePoweredOn { r.Fault_ = Fault("", &types.InvalidPowerState{ RequestedState: types.VirtualMachinePowerStatePoweredOn, ExistingState: vm.Runtime.PowerState, @@ -2286,27 +2426,61 @@ func (vm *VirtualMachine) ShutdownGuest(ctx *Context, c *types.ShutdownGuest) so return r } - // change state - vm.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOff - vm.Summary.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOff event := vm.event() - ctx.postEvent( - &types.VmGuestShutdownEvent{VmEvent: event}, - &types.VmPoweredOffEvent{VmEvent: event}, - ) - vm.run.stop(ctx, vm) + ctx.postEvent(&types.VmGuestShutdownEvent{VmEvent: event}) - ctx.Map.Update(vm, []types.PropertyChange{ - {Name: "runtime.powerState", Val: types.VirtualMachinePowerStatePoweredOff}, - {Name: "summary.runtime.powerState", Val: types.VirtualMachinePowerStatePoweredOff}, - }) + _ = CreateTask(vm, "shutdownGuest", func(*Task) (types.AnyType, types.BaseMethodFault) { + vm.svm.stop(ctx) + + ctx.Map.Update(vm, []types.PropertyChange{ + {Name: "runtime.powerState", Val: types.VirtualMachinePowerStatePoweredOff}, + {Name: "summary.runtime.powerState", Val: types.VirtualMachinePowerStatePoweredOff}, + }) + + ctx.postEvent(&types.VmPoweredOffEvent{VmEvent: event}) + + return nil, nil + }).Run(ctx) r.Res = new(types.ShutdownGuestResponse) return r } +func (vm *VirtualMachine) StandbyGuest(ctx *Context, c *types.StandbyGuest) soap.HasFault { + r := &methods.StandbyGuestBody{} + + if vm.Runtime.PowerState != types.VirtualMachinePowerStatePoweredOn { + r.Fault_ = Fault("", &types.InvalidPowerState{ + RequestedState: types.VirtualMachinePowerStatePoweredOn, + ExistingState: vm.Runtime.PowerState, + }) + + return r + } + + event := vm.event() + ctx.postEvent(&types.VmGuestStandbyEvent{VmEvent: event}) + + _ = CreateTask(vm, "standbyGuest", func(*Task) (types.AnyType, types.BaseMethodFault) { + vm.svm.pause(ctx) + + ctx.Map.Update(vm, []types.PropertyChange{ + {Name: "runtime.powerState", Val: types.VirtualMachinePowerStateSuspended}, + {Name: "summary.runtime.powerState", Val: types.VirtualMachinePowerStateSuspended}, + }) + + ctx.postEvent(&types.VmSuspendedEvent{VmEvent: event}) + + return nil, nil + }).Run(ctx) + + r.Res = new(types.StandbyGuestResponse) + + return r +} + func (vm *VirtualMachine) MarkAsTemplate(req *types.MarkAsTemplate) soap.HasFault { r := &methods.MarkAsTemplateBody{} diff --git a/vendor/github.com/vmware/govmomi/simulator/vpx/performance_manager_data.go b/vendor/github.com/vmware/govmomi/simulator/vpx/performance_manager_data.go index 3c42c5350e..8fc34960ff 100644 --- a/vendor/github.com/vmware/govmomi/simulator/vpx/performance_manager_data.go +++ b/vendor/github.com/vmware/govmomi/simulator/vpx/performance_manager_data.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2018-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -49,10 +49,10 @@ var VmMetricData = map[int32][]int64{ 185, 189, 134, 130, 160, 122, 84, 113, 153, 95, 110, 141, 91, 108, 130, 3372, 1942, 151, 102, 158, 162, 100, 143, 122, 109, 211, 229, 173, 187, 237, 200, 205, 241, 184, 204, 217, 182, 195, 219, 213, 211, 214, 189, 182, 245, 2671, 612, 1055, 595, 644, 747, 611, 336, 244, 118, 113, 128, 93, 94, 130, 359, 131, 151, 94, 137, 149, 106, 109, 127, 124}, - 70: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + 70: []int64{91, 585, 246, 114, 553, 348, 824, 848, 827, 882, 632, 500, 647, 805, 425, 971, 789, 1001, 910, 1013, 338, 713, 496, 168, 201, 886, 124, 968, 768, 736, + 612, 859, 973, 64, 312, 449, 38, 839, 807, 571, 83, 862, 1015, 333, 818, 173, 396, 520, 171, 678, 160, 203, 991, 549, 776, 524, 390, 228, 576, 307, + 1005, 93, 893, 475, 451, 141, 98, 439, 95, 104, 739, 630, 275, 701, 722, 16, 207, 468, 310, 387, 217, 377, 684, 969, 396, 1010, 866, 914, 181, 621, 995, + 831, 278, 530, 465, 745, 704, 762, 545, 544}, 473: []int64{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 27, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, @@ -113,10 +113,13 @@ var VmMetricData = map[int32][]int64{ 20, 20, 20, 25, 20, 20, 20, 20, 20, 20, 21, 20, 20, 20, 20, 20, 21, 21, 20, 20, 20, 20, 21, 20, 20, 20, 20, 20, 21, 20, 20, 20, 20, 24, 20, 21, 20, 20, 20, 20, 20, 21, 20, 21, 20, 20, 20, 21, 20, 20, 20, 20, 20, 23, 20, 20, 20, 20, 20, 20, 21, 20, 20, 20, 20, 20, 21, 20, 20, 20}, - 410: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + 410: []int64{976, 899, 657, 904, 171, 606, 607, 707, 823, 331, 255, 421, 230, 1001, + 937, 467, 738, 287, 904, 962, 518, 391, 593, 593, 59, 874, 364, 873, 728, 727, 533, + 328, 957, 637, 973, 1014, 259, 160, 698, 589, 933, 283, 385, 393, 129, 414, 16, 800, + 105, 150, 905, 278, 131, 115, 678, 738, 444, 411, 388, 402, 541, 428, 970, 260, 56, + 794, 975, 480, 644, 110, 702, 93, 240, 322, 651, 370, 261, 589, 72, 259, 405, 965, + 927, 519, 210, 291, 688, 758, 942, 301, 253, 605, 677, 995, 509, 478, 646, 3, 472, 1007, + }, 505: []int64{1100, 1100, 1100, 1100, 1100, 1000, 1000, 1000, 1000, 1000, 1100, 1100, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1300, 1300, 1300, 1100, 1200, 1100, 1100, 1100, 1100, 1100, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1300, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1300, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1200, 1400, 1600, 1800, 2000, 2300, 2500, 2600, 2600, 2600, 2600, 2600, 2600, 2600, 2600, @@ -181,10 +184,7 @@ var VmMetricData = map[int32][]int64{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - 94: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + 94: []int64{341, 881, 851, 214, 263, 802, 777, 58, 661, 231, 255, 494, 192, 302, 90, 371, 709, 164, 58, 1, 511, 711, 1005, 556, 457, 869, 708, 994, 668, 826, 112, 633, 901, 345, 317, 199, 199, 168, 981, 665, 29, 436, 225, 426, 309, 333, 757, 696, 840, 210, 500, 343, 651, 717, 803, 869, 445, 907, 928, 268, 437, 583, 160, 478, 891, 471, 72, 448, 457, 499, 348, 527, 409, 731, 849, 572, 378, 33, 254, 414, 781, 322, 153, 755, 301, 583, 823, 55, 637, 233, 259, 6, 448, 217, 842, 921, 971, 419, 246, 289}, 400: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -305,10 +305,7 @@ var VmMetricData = map[int32][]int64{ 800, 900, 1000, 1000, 1300, 1400, 1300, 900, 800, 900, 1000, 1000, 1000, 800, 800, 2400, 3900, 4100, 2600, 1400, 1200, 1200, 900, 800, 800, 1000, 1100, 1000, 900, 800, 900, 900, 1000, 900, 1200, 1200, 1200, 900, 800, 900, 1100, 1100, 1100, 800, 900, 2000, 2900, 4100, 3800, 4200, 4500, 4700, 3900, 2400, 1400, 1000, 1100, 1100, 900, 800, 1000, 1100, 1200, 900, 1200, 1300, 1400, 1100, 1000, 1000}, - 74: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + 74: []int64{961, 1016, 502, 571, 475, 122, 219, 937, 428, 657, 356, 987, 332, 469, 465, 216, 708, 984, 519, 696, 420, 994, 454, 7, 223, 559, 320, 521, 632, 18, 280, 144, 48, 994, 584, 555, 665, 944, 831, 135, 40, 851, 210, 440, 679, 569, 908, 745, 552, 125, 783, 877, 317, 895, 458, 999, 50, 288, 600, 729, 716, 441, 713, 800, 378, 440, 225, 226, 384, 588, 982, 393, 736, 817, 453, 644, 255, 92, 671, 81, 586, 1019, 286, 247, 781, 524, 765, 762, 217, 941, 595, 478, 597, 294, 648, 327, 1019, 706, 826, 813}, 85: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -357,10 +354,7 @@ var VmMetricData = map[int32][]int64{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - 406: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + 406: []int64{942, 615, 308, 1003, 67, 638, 951, 442, 100, 350, 477, 964, 469, 905, 622, 523, 679, 130, 457, 208, 710, 905, 781, 740, 608, 254, 286, 483, 205, 929, 88, 936, 730, 832, 144, 658, 558, 306, 19, 920, 254, 804, 458, 370, 328, 655, 43, 165, 653, 310, 369, 705, 188, 238, 170, 948, 535, 209, 293, 971, 787, 245, 377, 767, 807, 324, 896, 109, 178, 928, 954, 312, 26, 831, 816, 646, 159, 232, 997, 820, 387, 128, 28, 582, 1010, 705, 662, 815, 830, 946, 750, 637, 600, 847, 732, 566, 562, 406, 311, 609}, 513: []int64{1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1800, 1800, 1900, 1900, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 1900, 1900, 1900, 1900, 1900, 1800, 1700, 1800, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 2200, 2500, 3600, 3700, 3800, 3900, 3900, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, @@ -373,10 +367,12 @@ var VmMetricData = map[int32][]int64{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - 10: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + 10: []int64{740, 967, 600, 858, 667, 588, 488, 323, 834, 600, 49, 486, 867, 163, 219, 532, + 224, 115, 377, 80, 671, 327, 77, 8, 995, 831, 594, 326, 595, 182, 152, 195, 897, 924, 995, + 393, 126, 296, 678, 494, 752, 198, 199, 184, 412, 600, 19, 454, 605, 481, 456, 54, 487, + 395, 24, 859, 670, 710, 339, 232, 300, 941, 187, 190, 779, 127, 252, 304, 580, 823, 30, + 43, 3, 30, 523, 670, 499, 474, 962, 588, 300, 978, 338, 772, 212, 435, 920, 958, 533, 650, + 39, 668, 185, 124, 851, 226, 356, 594, 247, 194}, 12: []int64{137, 101, 116, 123, 114, 107, 96, 96, 103, 124, 111, 109, 108, 106, 106, 124, 122, 117, 149, 137, 141, 109, 110, 154, 128, 88, 107, 119, 102, 108, 125, 91, 95, 116, 97, 108, 100, 103, 119, 122, 97, 99, 108, 94, 97, 106, 105, 106, 107, 98, 111, 105, 97, 98, 106, 111, 94, 90, 95, 100, 131, 100, 103, 125, 108, 112, 97, 91, 107, 106, 98, 102, 116, 96, 112, 257, 186, 182, 259, 271, 232, 196, 123, 107, 122, 112, 114, 118, 104, 116, @@ -684,11 +680,12 @@ var HostMetricData = map[int32][]int64{ 135, 102, 74, 158, 108, 74, 121, 144, 74, 132, 124, 82, 211, 154, 127, 142, 84, 76, 115, 96, 76, 128, 84, 72, 116, 157, 96, 126, 94, 107, 136, 132, 106, 158, 164, 96, 112, 137, 90, 142, }, - 410: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 410: []int64{976, 899, 657, 904, 171, 606, 607, 707, 823, 331, 255, 421, 230, 1001, + 937, 467, 738, 287, 904, 962, 518, 391, 593, 593, 59, 874, 364, 873, 728, 727, 533, + 328, 957, 637, 973, 1014, 259, 160, 698, 589, 933, 283, 385, 393, 129, 414, 16, 800, + 105, 150, 905, 278, 131, 115, 678, 738, 444, 411, 388, 402, 541, 428, 970, 260, 56, + 794, 975, 480, 644, 110, 702, 93, 240, 322, 651, 370, 261, 589, 72, 259, 405, 965, + 927, 519, 210, 291, 688, 758, 942, 301, 253, 605, 677, 995, 509, 478, 646, 3, 472, 1007, }, 470: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -708,11 +705,12 @@ var HostMetricData = map[int32][]int64{ 58386204, 58386216, 58386220, 58386220, 58388612, 58386220, 58386220, 58386220, 58386220, 58386208, 58386248, 58386248, 58386248, 58386236, 58386248, 58386248, 58386248, 58386248, 58386248, 58386248, 58386248, 58386248, 58386236, 58386248, 58388640, 58386248, 58386240, 58386248, 58386248, 58386248, 58386248, 58388640, 58386248, 58386248, 58386248, 58386236, 58386248, 58386248, 58386248, 58386236, }, - 90: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 90: []int64{6, 644, 90, 376, 809, 98, 902, 998, 526, 633, 973, 1019, 423, 410, 219, + 879, 566, 390, 109, 450, 489, 341, 61, 465, 29, 893, 134, 1022, 703, 73, 477, 976, + 172, 175, 65, 696, 410, 566, 430, 187, 300, 542, 305, 751, 606, 567, 905, 70, 369, + 524, 913, 829, 351, 456, 295, 29, 539, 694, 620, 1010, 441, 904, 706, 954, 777, 221, + 497, 586, 456, 694, 183, 631, 302, 391, 857, 864, 610, 880, 906, 299, 839, 399, 49, + 713, 220, 903, 788, 228, 256, 119, 562, 395, 991, 543, 205, 584, 130, 804, 70, 99, }, 406: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1012,16 +1010,14 @@ var ResourcePoolMetricData = map[int32][]int64{ 1211531, 1206346, 1206131, 1206061, 1205836, 1205722, 1205495, 1205681, 1205711, 1204664, 1204509, 1205405, 1205132, 1204909, 1204796, 1204754, 1204743, 1204720, 1204484, 1204448, 1204636, 1204476, 1204354, 1204331, 1204079, 1203968, 1203899, 1203865, 1203811, 1203734, 1203865, 1203628, 1203251, 1203212, 1203098, 1203057, 1203938, 1203697, 1203608, 1203573, 1203545, 1203465, 1202291, 1201669, 1201782, 1201631, 1201743, 1201529, 1201474, 1201407, 1199122, 1198521, 1198570}, - 70: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - 90: []int64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + 70: []int64{91, 585, 246, 114, 553, 348, 824, 848, 827, 882, 632, 500, 647, 805, 425, 971, 789, 1001, 910, 1013, 338, 713, 496, 168, 201, 886, 124, 968, 768, 736, 612, 859, 973, 64, 312, 449, 38, 839, 807, 571, 83, 862, 1015, 333, 818, 173, 396, 520, 171, 678, 160, 203, 991, 549, 776, 524, 390, 228, 576, 307, 1005, 93, 893, 475, 451, 141, 98, 439, 95, 104, 739, 630, 275, 701, 722, 16, 207, 468, 310, 387, 217, 377, 684, 969, 396, 1010, 866, 914, 181, 621, 995, 831, 278, 530, 465, 745, 704, 762, 545, 544}, + 90: []int64{6, 644, 90, 376, 809, 98, 902, 998, 526, 633, 973, 1019, 423, 410, 219, + 879, 566, 390, 109, 450, 489, 341, 61, 465, 29, 893, 134, 1022, 703, 73, 477, 976, + 172, 175, 65, 696, 410, 566, 430, 187, 300, 542, 305, 751, 606, 567, 905, 70, 369, + 524, 913, 829, 351, 456, 295, 29, 539, 694, 620, 1010, 441, 904, 706, 954, 777, 221, + 497, 586, 456, 694, 183, 631, 302, 391, 857, 864, 610, 880, 906, 299, 839, 399, 49, + 713, 220, 903, 788, 228, 256, 119, 562, 395, 991, 543, 205, 584, 130, 804, 70, 99, + }, 7: []int64{1406, 1419, 1426, 1412, 1413, 1408, 1472, 1426, 1462, 1424, 1447, 1403, 1433, 1429, 1420, 1395, 1447, 1396, 1406, 1413, 1432, 1420, 1425, 1411, 1432, 1437, 1444, 1407, 1448, 1450, 1477, 1431, 1451, 1437, 1403, 1459, 1478, 1452, 1447, 1446, 1410, 1441, 1445, 1415, 1433, 1435, 1458, 1419, 1441, 1476, 1310, 1482, 1451, 1458, 1455, 1428, 1446, 1443, 1436, 1449, diff --git a/vendor/github.com/vmware/govmomi/simulator/vpx/service_content.go b/vendor/github.com/vmware/govmomi/simulator/vpx/service_content.go index 3018d01ed2..c1874c5df6 100644 --- a/vendor/github.com/vmware/govmomi/simulator/vpx/service_content.go +++ b/vendor/github.com/vmware/govmomi/simulator/vpx/service_content.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -24,7 +24,7 @@ import ( // ServiceContent is the default template for the ServiceInstance content property. // Capture method: -// govc object.collect -s -dump - content +// govc object.collect -s -dump - content var ServiceContent = types.ServiceContent{ RootFolder: types.ManagedObjectReference{Type: "Folder", Value: "group-d1"}, PropertyCollector: types.ManagedObjectReference{Type: "PropertyCollector", Value: "propertyCollector"}, diff --git a/vendor/github.com/vmware/govmomi/simulator/vpx/setting.go b/vendor/github.com/vmware/govmomi/simulator/vpx/setting.go index 7bbf0c02d6..7625824da6 100644 --- a/vendor/github.com/vmware/govmomi/simulator/vpx/setting.go +++ b/vendor/github.com/vmware/govmomi/simulator/vpx/setting.go @@ -18,6 +18,8 @@ package vpx import "github.com/vmware/govmomi/vim25/types" +// TODO: figure out whether this is Setting or AdvancedOptions - see esx/setting.go for the difference + // Setting is captured from VC's ServiceContent.OptionManager.setting var Setting = []types.BaseOptionValue{ // This list is currently pruned to include sso options only with sso.enabled set to false diff --git a/vendor/github.com/vmware/govmomi/simulator/vpx/task_manager.go b/vendor/github.com/vmware/govmomi/simulator/vpx/task_manager.go index dee36ff71a..a3fcc302d8 100644 --- a/vendor/github.com/vmware/govmomi/simulator/vpx/task_manager.go +++ b/vendor/github.com/vmware/govmomi/simulator/vpx/task_manager.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved. +Copyright (c) 2018-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -20,7 +20,7 @@ import "github.com/vmware/govmomi/vim25/types" // Description is the default template for the TaskManager description property. // Capture method: -// govc object.collect -s -dump TaskManager:TaskManager description +// govc object.collect -s -dump TaskManager:TaskManager description var Description = types.TaskDescription{ MethodInfo: []types.BaseElementDescription{ &types.ElementDescription{ diff --git a/vendor/github.com/vmware/govmomi/task/wait.go b/vendor/github.com/vmware/govmomi/task/wait.go index b78f5110d9..d52458e667 100644 --- a/vendor/github.com/vmware/govmomi/task/wait.go +++ b/vendor/github.com/vmware/govmomi/task/wait.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2015 VMware, Inc. All Rights Reserved. +Copyright (c) 2015-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -113,7 +113,6 @@ func (t *taskCallback) fn(pc []types.PropertyChange) bool { // The detail for the progress update is set to an empty string. If the task // finishes in the error state, the error instance is passed through as well. // Note that this error is the same error that is returned by this function. -// func Wait(ctx context.Context, ref types.ManagedObjectReference, pc *property.Collector, s progress.Sinker) (*types.TaskInfo, error) { cb := &taskCallback{} diff --git a/vendor/github.com/vmware/govmomi/toolbox/hgfs/archive.go b/vendor/github.com/vmware/govmomi/toolbox/hgfs/archive.go index 65f5743aba..6360743beb 100644 --- a/vendor/github.com/vmware/govmomi/toolbox/hgfs/archive.go +++ b/vendor/github.com/vmware/govmomi/toolbox/hgfs/archive.go @@ -22,7 +22,6 @@ import ( "bytes" "compress/gzip" "io" - "io/ioutil" "log" "math" "net/url" @@ -139,7 +138,7 @@ func (h *ArchiveHandler) newArchiveFromGuest(u *url.URL) (File, error) { } var z io.Writer = w - var c io.Closer = ioutil.NopCloser(nil) + var c io.Closer = io.NopCloser(nil) switch u.Query().Get("format") { case "tgz": @@ -194,7 +193,7 @@ func (h *ArchiveHandler) newArchiveToGuest(u *url.URL) (File, error) { c := func() error { // Drain the pipe of tar trailer data (two null blocks) if cerr == nil { - _, _ = io.Copy(ioutil.Discard, a.Reader) + _, _ = io.Copy(io.Discard, a.Reader) } return nil } diff --git a/vendor/github.com/vmware/govmomi/toolbox/hgfs/server.go b/vendor/github.com/vmware/govmomi/toolbox/hgfs/server.go index efc3faf212..1c887e9748 100644 --- a/vendor/github.com/vmware/govmomi/toolbox/hgfs/server.go +++ b/vendor/github.com/vmware/govmomi/toolbox/hgfs/server.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2017 VMware, Inc. All Rights Reserved. +Copyright (c) 2017-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -198,9 +198,9 @@ func (s *Server) OpenFile(name string, mode int32) (File, error) { // Note that callers on the VMX side that reach this path are only concerned with: // - does the file exist? // - size: -// + used for UI progress with desktop Drag-N-Drop operations, which toolbox does not support. -// + sent to as Content-Length header in response to GET of FileTransferInformation.Url, -// if the first ReadV3 size is > HGFS_LARGE_PACKET_MAX +// + used for UI progress with desktop Drag-N-Drop operations, which toolbox does not support. +// + sent to as Content-Length header in response to GET of FileTransferInformation.Url, +// if the first ReadV3 size is > HGFS_LARGE_PACKET_MAX func (s *Server) Stat(name string) (os.FileInfo, error) { u := urlParse(name) diff --git a/vendor/github.com/vmware/govmomi/toolbox/process/process.go b/vendor/github.com/vmware/govmomi/toolbox/process/process.go index 312a0cf345..8b9cc15d2d 100644 --- a/vendor/github.com/vmware/govmomi/toolbox/process/process.go +++ b/vendor/github.com/vmware/govmomi/toolbox/process/process.go @@ -21,7 +21,6 @@ import ( "context" "fmt" "io" - "io/ioutil" "net" "net/url" "os" @@ -392,7 +391,7 @@ func (m *Manager) Stat(u *url.URL) (os.FileInfo, error) { pf := &File{ name: name, - Closer: ioutil.NopCloser(nil), // via hgfs, nop for stdout and stderr + Closer: io.NopCloser(nil), // via hgfs, nop for stdout and stderr } var r *bytes.Buffer diff --git a/vendor/github.com/vmware/govmomi/vapi/internal/internal.go b/vendor/github.com/vmware/govmomi/vapi/internal/internal.go index f6584c569b..2872f38030 100644 --- a/vendor/github.com/vmware/govmomi/vapi/internal/internal.go +++ b/vendor/github.com/vmware/govmomi/vapi/internal/internal.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2018-2022 VMware, Inc. All Rights Reserved. +Copyright (c) 2018-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -43,7 +43,6 @@ const ( TrustedCertificatesPath = "/api/content/trusted-certificates" VCenterOVFLibraryItem = "/com/vmware/vcenter/ovf/library-item" VCenterVMTXLibraryItem = "/vcenter/vm-template/library-items" - VCenterVM = "/vcenter/vm" SessionCookieName = "vmware-api-session-id" UseHeaderAuthn = "vmware-use-header-authn" DebugEcho = "/vc-sim/debug/echo" @@ -59,7 +58,10 @@ type AssociatedObject struct { // Reference implements mo.Reference func (o AssociatedObject) Reference() types.ManagedObjectReference { - return types.ManagedObjectReference(o) + return types.ManagedObjectReference{ + Type: o.Type, + Value: o.Value, + } } // Association for tag-association requests. @@ -69,9 +71,11 @@ type Association struct { // NewAssociation returns an Association, converting ref to an AssociatedObject. func NewAssociation(ref mo.Reference) Association { - obj := AssociatedObject(ref.Reference()) return Association{ - ObjectID: &obj, + ObjectID: &AssociatedObject{ + Type: ref.Reference().Type, + Value: ref.Reference().Value, + }, } } diff --git a/vendor/github.com/vmware/govmomi/vapi/library/finder/README.md b/vendor/github.com/vmware/govmomi/vapi/library/finder/README.md new file mode 100644 index 0000000000..62331f2673 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/library/finder/README.md @@ -0,0 +1,187 @@ +# The content library finder +The govmomi package now includes a finder for the content library, [`github.com/vmware/govmomi/vapi/library.Finder`](https://github.com/akutz/govmomi/blob/feature/content-library/vapi/library/finder/finder.go). This finder supports searching for objects in the content library using an inventory path design similar to the [standard govmomi finder](https://github.com/vmware/govmomi/blob/main/find/finder.go) and includes support for wildcard matching courtesy of golang's [`path.Match`](https://golang.org/pkg/path/#Match). For example: + +| Pattern | Result | +|---------|--------| +| `*` | Gets all of the content libraries | +| `*/` | Gets all of the content library items for all of the content libraries. | +| `/Public/` | Gets all of the content library items for the content library named `Public` | +| `/*/*/` | Gets all of the content library files for all of the content library items for all of the content libraries. | +| `Public/*/photon2*` | Gets all of the files that begin with `photon2` in all of the content library items for the content library named `Public` | + +The use of a wildcard character in the search string results in a full listing of content library objects for that part of the path's server-side analogue. If `Public/Photon2*` is searched, then all of the content library items for the `Public` library are listed in order to perform the wildcard matching. However, if `Public/PhotonOS-2-GA` then the server-side API call [`library:item:find`](https://vdc-repo.vmware.com/vmwb-repository/dcr-public/1cd28284-3b72-4885-9e31-d1c6d9e26686/71ef7304-a6c9-43b3-a3cd-868b2c236c81/doc/operations/com/vmware/content/library/item.find-operation.html) is used to find an item with the name `PhotonOS-2-GA`. + +## Performance +Search strings that do not use wildcard characters **should** be **more** efficient as these searches rely on server-side find calls and do not require dumping all of the objects. However, this is only true for systems with a large number of objects in the content libraries. This is due to the number of round-trips required to lookup an object with a direct path. For example: + +| Search path | Roundtrips | +|------|------------| +| `Public/Photon2` | 4 | +| `Public*/Photon2*` | 2 | + +The *absolute* search path takes twice as many roundtrips compared to the search path with wildcards: + +### Absolute path search logic +1. Find library ID for library with name using server-side find API +2. Get library with library ID +3. Find item ID for item with name using server-side find API +4. Get item with item ID + +### Wildcard search logic +1. Get all of the libraries and filter the pattern on the client-side +2. Get all of the items for the library and filter the pattern on the client-=side + +### Searches at scale +While a system that has few content library objects benefits from wildcard search logic, the fact is that the above approach regarding absolute paths proves out to be **much** more efficient for systems with large numbers of content library objects. + + +## `govc library.ls` + +### Listing all the objects in the content library + +```console +$ govc library.ls '*/*/' +/ISOs/CentOS-7-x86_64-Minimal-1804/CentOS-7-x86_64-Minimal-1804.iso +/ISOs/CoreOS Production/coreos_production_iso_image.iso +/ISOs/VMware-VCSA-all-6.7.0-8217866.iso/VMware-VCSA-all-6.7.0-8217866.iso +/ISOs/VMware-VIM-all-6.7.0-8217866.iso/VMware-VIM-all-6.7.0-8217866.iso +/ISOs/ubuntu-16.04.5-server-amd64/ubuntu-16.04.5-server-amd64.iso +/ISOs/photon-2.0-304b817/photon-2.0-304b817.iso +/OVAs/VMware-vCenter-Server-Appliance-6.7.0.10000-8217866_OVF10.ova/VMware-vCenter-Server-Appliance-6.7.0.10000-8217866_OVF10.ova +/OVAs/coreos_production_vmware_ova/coreos_production_vmware_ova.ovf +/OVAs/coreos_production_vmware_ova/coreos_production_vmware_ova-1.vmdk +/OVAs/centos_cloud_template/centos_cloud_template-2.iso +/OVAs/centos_cloud_template/centos_cloud_template.ovf +/OVAs/centos_cloud_template/centos_cloud_template-1.vmdk +/OVAs/centos_cloud_template/centos_cloud_template-3.nvram +/OVAs/photon-custom-hw13-2.0-304b817/photon-ova-disk1.vmdk +/OVAs/photon-custom-hw13-2.0-304b817/photon-ova.ovf +/OVAs/yakity-centos/yakity-centos-2.nvram +/OVAs/yakity-centos/yakity-centos-1.vmdk +/OVAs/yakity-centos/yakity-centos.ovf +/OVAs/yakity-photon/yakity-photon-1.vmdk +/OVAs/yakity-photon/yakity-photon.ovf +/OVAs/yakity-photon/yakity-photon-2.nvram +/OVAs/ubuntu-16.04-server-cloudimg-amd64/ubuntu-16.04-server-cloudimg-amd64.ovf +/OVAs/ubuntu-16.04-server-cloudimg-amd64/ubuntu-16.04-server-cloudimg-amd64-1.vmdk +/sk8-TestUploadOVA/photon2-cloud-init/photon2-cloud-init.ovf +/sk8-TestUploadOVA/photon2-cloud-init/photon2-cloud-init-1.vmdk +/Public/photon2-cloud-init/photon2-cloud-init.ovf +/Public/photon2-cloud-init/photon2-cloud-init-1.vmdk +``` + +## `govc library.info` + +### Getting the info for all the objects in the content library + +```console +$ govc library.info '*/*/' +Name: CentOS-7-x86_64-Minimal-1804.iso + Path: /ISOs/CentOS-7-x86_64-Minimal-1804/CentOS-7-x86_64-Minimal-1804.iso + Size: 824637106200 + Version: 1 +Name: coreos_production_iso_image.iso + Path: /ISOs/CoreOS Production/coreos_production_iso_image.iso + Size: 824637441624 + Version: 1 +Name: VMware-VCSA-all-6.7.0-8217866.iso + Path: /ISOs/VMware-VCSA-all-6.7.0-8217866.iso/VMware-VCSA-all-6.7.0-8217866.iso + Size: 824637106368 + Version: 1 +Name: VMware-VIM-all-6.7.0-8217866.iso + Path: /ISOs/VMware-VIM-all-6.7.0-8217866.iso/VMware-VIM-all-6.7.0-8217866.iso + Size: 824637106504 + Version: 1 +Name: ubuntu-16.04.5-server-amd64.iso + Path: /ISOs/ubuntu-16.04.5-server-amd64/ubuntu-16.04.5-server-amd64.iso + Size: 824637441944 + Version: 1 +Name: photon-2.0-304b817.iso + Path: /ISOs/photon-2.0-304b817/photon-2.0-304b817.iso + Size: 824637106672 + Version: 1 +Name: VMware-vCenter-Server-Appliance-6.7.0.10000-8217866_OVF10.ova + Path: /OVAs/VMware-vCenter-Server-Appliance-6.7.0.10000-8217866_OVF10.ova/VMware-vCenter-Server-Appliance-6.7.0.10000-8217866_OVF10.ova + Size: 824637106880 + Version: 1 +Name: coreos_production_vmware_ova.ovf + Path: /OVAs/coreos_production_vmware_ova/coreos_production_vmware_ova.ovf + Size: 824637107032 + Version: 1 +Name: coreos_production_vmware_ova-1.vmdk + Path: /OVAs/coreos_production_vmware_ova/coreos_production_vmware_ova-1.vmdk + Size: 824637107072 + Version: 1 +Name: centos_cloud_template-2.iso + Path: /OVAs/centos_cloud_template/centos_cloud_template-2.iso + Size: 824636997760 + Version: 1 +Name: centos_cloud_template.ovf + Path: /OVAs/centos_cloud_template/centos_cloud_template.ovf + Size: 824636997792 + Version: 1 +Name: centos_cloud_template-1.vmdk + Path: /OVAs/centos_cloud_template/centos_cloud_template-1.vmdk + Size: 824636997832 + Version: 1 +Name: centos_cloud_template-3.nvram + Path: /OVAs/centos_cloud_template/centos_cloud_template-3.nvram + Size: 824636997856 + Version: 1 +Name: photon-ova-disk1.vmdk + Path: /OVAs/photon-custom-hw13-2.0-304b817/photon-ova-disk1.vmdk + Size: 824637107280 + Version: 1 +Name: photon-ova.ovf + Path: /OVAs/photon-custom-hw13-2.0-304b817/photon-ova.ovf + Size: 824637107328 + Version: 1 +Name: yakity-centos-2.nvram + Path: /OVAs/yakity-centos/yakity-centos-2.nvram + Size: 824637253000 + Version: 2 +Name: yakity-centos-1.vmdk + Path: /OVAs/yakity-centos/yakity-centos-1.vmdk + Size: 824637253024 + Version: 2 +Name: yakity-centos.ovf + Path: /OVAs/yakity-centos/yakity-centos.ovf + Size: 824637253056 + Version: 2 +Name: yakity-photon-1.vmdk + Path: /OVAs/yakity-photon/yakity-photon-1.vmdk + Size: 824637107504 + Version: 5 +Name: yakity-photon.ovf + Path: /OVAs/yakity-photon/yakity-photon.ovf + Size: 824637107536 + Version: 5 +Name: yakity-photon-2.nvram + Path: /OVAs/yakity-photon/yakity-photon-2.nvram + Size: 824637107560 + Version: 5 +Name: ubuntu-16.04-server-cloudimg-amd64.ovf + Path: /OVAs/ubuntu-16.04-server-cloudimg-amd64/ubuntu-16.04-server-cloudimg-amd64.ovf + Size: 824637442112 + Version: 1 +Name: ubuntu-16.04-server-cloudimg-amd64-1.vmdk + Path: /OVAs/ubuntu-16.04-server-cloudimg-amd64/ubuntu-16.04-server-cloudimg-amd64-1.vmdk + Size: 824637442136 + Version: 1 +Name: photon2-cloud-init.ovf + Path: /sk8-TestUploadOVA/photon2-cloud-init/photon2-cloud-init.ovf + Size: 824636903184 + Version: 1 +Name: photon2-cloud-init-1.vmdk + Path: /sk8-TestUploadOVA/photon2-cloud-init/photon2-cloud-init-1.vmdk + Size: 824636903208 + Version: 1 +Name: photon2-cloud-init.ovf + Path: /Public/photon2-cloud-init/photon2-cloud-init.ovf + Size: 824637442304 + Version: 3 +Name: photon2-cloud-init-1.vmdk + Path: /Public/photon2-cloud-init/photon2-cloud-init-1.vmdk + Size: 824637442328 + Version: 3 +``` diff --git a/vendor/github.com/vmware/govmomi/vapi/library/finder/finder.go b/vendor/github.com/vmware/govmomi/vapi/library/finder/finder.go new file mode 100644 index 0000000000..5f03078316 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/library/finder/finder.go @@ -0,0 +1,328 @@ +/* +Copyright (c) 2018 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package finder + +import ( + "context" + "encoding/json" + "fmt" + "path" + "strings" + + "github.com/vmware/govmomi/vapi/library" +) + +// Finder is a helper object for finding content library objects by their +// inventory paths: /LIBRARY/ITEM/FILE. +// +// Wildcard characters `*` and `?` are both supported. However, the use +// of a wildcard character in the search string results in a full listing of +// that part of the path's server-side items. +// +// Path parts that do not use wildcard characters rely on server-side Find +// functions to find the path token by its name. Ironically finding one +// item with a direct path takes longer than if a wildcard is used because +// of the multiple round-trips. Direct paths will be more performant on +// systems that have numerous items. +type Finder struct { + M *library.Manager +} + +// NewFinder returns a new Finder. +func NewFinder(m *library.Manager) *Finder { + return &Finder{m} +} + +// Find finds one or more items that match the provided inventory path(s). +func (f *Finder) Find( + ctx context.Context, ipath ...string) ([]FindResult, error) { + + if len(ipath) == 0 { + ipath = []string{""} + } + var result []FindResult + for _, p := range ipath { + results, err := f.find(ctx, p) + if err != nil { + return nil, err + } + result = append(result, results...) + } + return result, nil +} + +func (f *Finder) find(ctx context.Context, ipath string) ([]FindResult, error) { + + if ipath == "" { + ipath = "*" + } + + // Get the argument and remove any leading separator characters. + ipath = strings.TrimPrefix(ipath, "/") + + // Tokenize the path into its distinct parts. + parts := strings.Split(ipath, "/") + + // If there are more than three parts then the file name contains + // the "/" character. In that case collapse any additional parts + // back into the filename. + if len(parts) > 3 { + parts = []string{ + parts[0], + parts[1], + strings.Join(parts[2:], "/"), + } + } + + libs, err := f.findLibraries(ctx, parts[0]) + if err != nil { + return nil, err + } + + // If the path is a single token then the libraries are requested. + if len(parts) < 2 { + return libs, nil + } + + items, err := f.findLibraryItems(ctx, libs, parts[1]) + if err != nil { + return nil, err + } + + // If the path is two tokens then the library items are requested. + if len(parts) < 3 { + return items, nil + } + + // Get the library item files. + return f.findLibraryItemFiles(ctx, items, parts[2]) +} + +// FindResult is the type of object returned from a Find operation. +type FindResult interface { + + // GetParent returns the parent of the find result. If the find result + // is a Library then this function will return nil. + GetParent() FindResult + + // GetPath returns the inventory path of the find result. + GetPath() string + + // GetID returns the ID of the find result. + GetID() string + + // GetName returns the name of the find result. + GetName() string + + // GetResult gets the underlying library object. + GetResult() interface{} +} + +type findResult struct { + result interface{} + parent FindResult +} + +func (f findResult) GetResult() interface{} { + return f.result +} +func (f findResult) GetParent() FindResult { + return f.parent +} +func (f findResult) GetPath() string { + switch f.result.(type) { + case library.Library: + return fmt.Sprintf("/%s", f.GetName()) + case library.Item, library.File: + return fmt.Sprintf("%s/%s", f.parent.GetPath(), f.GetName()) + default: + return "" + } +} + +func (f findResult) GetID() string { + switch t := f.result.(type) { + case library.Library: + return t.ID + case library.Item: + return t.ID + default: + return "" + } +} + +func (f findResult) GetName() string { + switch t := f.result.(type) { + case library.Library: + return t.Name + case library.Item: + return t.Name + case library.File: + return t.Name + default: + return "" + } +} + +func (f findResult) MarshalJSON() ([]byte, error) { + return json.Marshal(f.GetResult()) +} + +func (f *Finder) findLibraries( + ctx context.Context, + token string) ([]FindResult, error) { + + if token == "" { + token = "*" + } + + var result []FindResult + + // If the token does not contain any wildcard characters then perform + // a lookup by name using a server side call. + if !strings.ContainsAny(token, "*?") { + libIDs, err := f.M.FindLibrary(ctx, library.Find{Name: token}) + if err != nil { + return nil, err + } + for _, id := range libIDs { + lib, err := f.M.GetLibraryByID(ctx, id) + if err != nil { + return nil, err + } + result = append(result, findResult{result: *lib}) + } + if len(result) == 0 { + lib, err := f.M.GetLibraryByID(ctx, token) + if err == nil { + result = append(result, findResult{result: *lib}) + } + } + return result, nil + } + + libs, err := f.M.GetLibraries(ctx) + if err != nil { + return nil, err + } + for _, lib := range libs { + match, err := path.Match(token, lib.Name) + if err != nil { + return nil, err + } + if match { + result = append(result, findResult{result: lib}) + } + } + return result, nil +} + +func (f *Finder) findLibraryItems( + ctx context.Context, + parents []FindResult, token string) ([]FindResult, error) { + + if token == "" { + token = "*" + } + + var result []FindResult + + for _, parent := range parents { + // If the token does not contain any wildcard characters then perform + // a lookup by name using a server side call. + if !strings.ContainsAny(token, "*?") { + childIDs, err := f.M.FindLibraryItems( + ctx, library.FindItem{ + Name: token, + LibraryID: parent.GetID(), + }) + if err != nil { + return nil, err + } + for _, id := range childIDs { + child, err := f.M.GetLibraryItem(ctx, id) + if err != nil { + return nil, err + } + result = append(result, findResult{ + result: *child, + parent: parent, + }) + } + continue + } + + children, err := f.M.GetLibraryItems(ctx, parent.GetID()) + if err != nil { + return nil, err + } + for _, child := range children { + match, err := path.Match(token, child.Name) + if err != nil { + return nil, err + } + if match { + result = append( + result, findResult{parent: parent, result: child}) + } + } + } + return result, nil +} + +func (f *Finder) findLibraryItemFiles( + ctx context.Context, + parents []FindResult, token string) ([]FindResult, error) { + + if token == "" { + token = "*" + } + + var result []FindResult + + for _, parent := range parents { + // If the token does not contain any wildcard characters then perform + // a lookup by name using a server side call. + if !strings.ContainsAny(token, "*?") { + child, err := f.M.GetLibraryItemFile(ctx, parent.GetID(), token) + if err != nil { + return nil, err + } + result = append(result, findResult{ + result: *child, + parent: parent, + }) + continue + } + + children, err := f.M.ListLibraryItemFiles(ctx, parent.GetID()) + if err != nil { + return nil, err + } + for _, child := range children { + match, err := path.Match(token, child.Name) + if err != nil { + return nil, err + } + if match { + result = append( + result, findResult{parent: parent, result: child}) + } + } + } + return result, nil +} diff --git a/vendor/github.com/vmware/govmomi/vapi/library/library.go b/vendor/github.com/vmware/govmomi/vapi/library/library.go index e5e5d0896f..62ad873bc5 100644 --- a/vendor/github.com/vmware/govmomi/vapi/library/library.go +++ b/vendor/github.com/vmware/govmomi/vapi/library/library.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2018 VMware, Inc. All Rights Reserved. +Copyright (c) 2018-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -37,7 +37,7 @@ type StorageBackings struct { // Library provides methods to create, read, update, delete, and enumerate libraries. type Library struct { CreationTime *time.Time `json:"creation_time,omitempty"` - Description string `json:"description,omitempty"` + Description *string `json:"description,omitempty"` ID string `json:"id,omitempty"` LastModifiedTime *time.Time `json:"last_modified_time,omitempty"` LastSyncTime *time.Time `json:"last_sync_time,omitempty"` @@ -120,7 +120,7 @@ func (l *Library) Patch(src *Library) { if src.Name != "" { l.Name = src.Name } - if src.Description != "" { + if src.Description != nil { l.Description = src.Description } if src.Version != "" { diff --git a/vendor/github.com/vmware/govmomi/vapi/library/library_item.go b/vendor/github.com/vmware/govmomi/vapi/library/library_item.go index adc2101ab1..e143da5d96 100644 --- a/vendor/github.com/vmware/govmomi/vapi/library/library_item.go +++ b/vendor/github.com/vmware/govmomi/vapi/library/library_item.go @@ -36,7 +36,7 @@ type Item struct { Cached bool `json:"cached,omitempty"` ContentVersion string `json:"content_version,omitempty"` CreationTime *time.Time `json:"creation_time,omitempty"` - Description string `json:"description,omitempty"` + Description *string `json:"description,omitempty"` ID string `json:"id,omitempty"` LastModifiedTime *time.Time `json:"last_modified_time,omitempty"` LastSyncTime *time.Time `json:"last_sync_time,omitempty"` @@ -63,7 +63,7 @@ func (i *Item) Patch(src *Item) { if src.Name != "" { i.Name = src.Name } - if src.Description != "" { + if src.Description != nil { i.Description = src.Description } if src.Type != "" { @@ -82,12 +82,17 @@ func (c *Manager) CreateLibraryItem(ctx context.Context, item Item) (string, err LibraryID string `json:"library_id,omitempty"` Type string `json:"type"` } + + description := "" + if item.Description != nil { + description = *item.Description + } spec := struct { Item createItemSpec `json:"create_spec"` }{ Item: createItemSpec{ Name: item.Name, - Description: item.Description, + Description: description, LibraryID: item.LibraryID, Type: item.Type, }, diff --git a/vendor/github.com/vmware/govmomi/vapi/rest/client.go b/vendor/github.com/vmware/govmomi/vapi/rest/client.go index b1cefd0e28..46fb4e3a60 100644 --- a/vendor/github.com/vmware/govmomi/vapi/rest/client.go +++ b/vendor/github.com/vmware/govmomi/vapi/rest/client.go @@ -22,7 +22,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "net/url" "strings" @@ -32,6 +31,7 @@ import ( "github.com/vmware/govmomi/vapi/internal" "github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" ) // Client extends soap.Client to support JSON encoding, while inheriting security features, debug tracing and session persistence. @@ -180,6 +180,11 @@ func (c *Client) Do(ctx context.Context, req *http.Request, resBody interface{}) } } + // OperationID (see soap.Client.soapRoundTrip) + if id, ok := ctx.Value(types.ID{}).(string); ok { + req.Header.Add("X-Request-ID", id) + } + if headers, ok := ctx.Value(headersContext{}).(http.Header); ok { for k, v := range headers { for _, v := range v { @@ -195,7 +200,7 @@ func (c *Client) Do(ctx context.Context, req *http.Request, resBody interface{}) case http.StatusNoContent: case http.StatusBadRequest: // TODO: structured error types - detail, err := ioutil.ReadAll(res.Body) + detail, err := io.ReadAll(res.Body) if err != nil { return err } diff --git a/vendor/github.com/vmware/govmomi/vapi/simulator/simulator.go b/vendor/github.com/vmware/govmomi/vapi/simulator/simulator.go index c43494f2b0..43a6e46173 100644 --- a/vendor/github.com/vmware/govmomi/vapi/simulator/simulator.go +++ b/vendor/github.com/vmware/govmomi/vapi/simulator/simulator.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2018-2022 VMware, Inc. All Rights Reserved. +Copyright (c) 2018-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -28,7 +28,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "log" "net/http" "net/url" @@ -88,6 +87,7 @@ type download struct { type handler struct { sync.Mutex + sm *simulator.SessionManager ServeMux *http.ServeMux URL url.URL Category map[string]*tags.Category @@ -104,7 +104,7 @@ type handler struct { func init() { simulator.RegisterEndpoint(func(s *simulator.Service, r *simulator.Registry) { if r.IsVPX() { - patterns, h := New(s.Listen, r.OptionManager().Setting) + patterns, h := New(s.Listen, r) for _, p := range patterns { s.Handle(p, h) } @@ -113,8 +113,9 @@ func init() { } // New creates a vAPI simulator. -func New(u *url.URL, settings []vim.BaseOptionValue) ([]string, http.Handler) { +func New(u *url.URL, r *simulator.Registry) ([]string, http.Handler) { s := &handler{ + sm: r.SessionManager(), ServeMux: http.NewServeMux(), URL: *u, Category: make(map[string]*tags.Category), @@ -166,7 +167,6 @@ func New(u *url.URL, settings []vim.BaseOptionValue) ([]string, http.Handler) { {internal.VCenterOVFLibraryItem + "/", s.libraryItemOVFID}, {internal.VCenterVMTXLibraryItem, s.libraryItemCreateTemplate}, {internal.VCenterVMTXLibraryItem + "/", s.libraryItemTemplateID}, - {internal.VCenterVM + "/", s.vmID}, {internal.DebugEcho, s.debugEcho}, // /api/ patterns. {internal.SecurityPoliciesPath, s.librarySecurityPolicies}, @@ -237,10 +237,7 @@ func (s *handler) isAuthorized(r *http.Request) bool { func (s *handler) hasAuthorization(r *http.Request) (string, bool) { u, p, ok := r.BasicAuth() if ok { // user+pass auth - if u == "" || p == "" { - return u, false - } - return u, true + return u, s.sm.Authenticate(s.URL, &vim.Login{UserName: u, Password: p}) } auth := r.Header.Get("Authorization") return "TODO", strings.HasPrefix(auth, "SIGN ") // token auth @@ -267,14 +264,22 @@ func (s *handler) AttachedObjects(tag vim.VslmTagEntry) ([]vim.ManagedObjectRefe } var ids []vim.ManagedObjectReference for id := range s.Association[t.ID] { - ids = append(ids, vim.ManagedObjectReference(id)) + ids = append( + ids, + vim.ManagedObjectReference{ + Type: id.Type, + Value: id.Value, + }) } return ids, nil } // AttachedTags is meant for internal use via simulator.Registry.tagManager func (s *handler) AttachedTags(ref vim.ManagedObjectReference) ([]vim.VslmTagEntry, vim.BaseMethodFault) { - oid := internal.AssociatedObject(ref) + oid := internal.AssociatedObject{ + Type: ref.Type, + Value: ref.Value, + } var tags []vim.VslmTagEntry for id, objs := range s.Association { if objs[oid] { @@ -295,7 +300,10 @@ func (s *handler) AttachTag(ref vim.ManagedObjectReference, tag vim.VslmTagEntry if t == nil { return new(vim.NotFound) } - s.Association[t.ID][internal.AssociatedObject(ref)] = true + s.Association[t.ID][internal.AssociatedObject{ + Type: ref.Type, + Value: ref.Value, + }] = true return nil } @@ -305,13 +313,17 @@ func (s *handler) DetachTag(id vim.ManagedObjectReference, tag vim.VslmTagEntry) if t == nil { return new(vim.NotFound) } - delete(s.Association[t.ID], internal.AssociatedObject(id)) + delete(s.Association[t.ID], internal.AssociatedObject{ + Type: id.Type, + Value: id.Value, + }) return nil } // StatusOK responds with http.StatusOK and encodes val, if specified, to JSON // For use with "/api" endpoints. func StatusOK(w http.ResponseWriter, val ...interface{}) { + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) if len(val) == 0 { return @@ -360,6 +372,60 @@ func BadRequest(w http.ResponseWriter, kind string) { } } +// ApiErrorAlreadyExists responds with a REST error of type "ALREADY_EXISTS". +// For use with "/api" endpoints. +func ApiErrorAlreadyExists(w http.ResponseWriter) { + apiError(w, http.StatusBadRequest, "ALREADY_EXISTS") +} + +// ApiErrorGeneral responds with a REST error of type "ERROR". +// For use with "/api" endpoints. +func ApiErrorGeneral(w http.ResponseWriter) { + apiError(w, http.StatusInternalServerError, "ERROR") +} + +// ApiErrorInvalidArgument responds with a REST error of type "INVALID_ARGUMENT". +// For use with "/api" endpoints. +func ApiErrorInvalidArgument(w http.ResponseWriter) { + apiError(w, http.StatusBadRequest, "INVALID_ARGUMENT") +} + +// ApiErrorNotAllowedInCurrentState responds with a REST error of type "NOT_ALLOWED_IN_CURRENT_STATE". +// For use with "/api" endpoints. +func ApiErrorNotAllowedInCurrentState(w http.ResponseWriter) { + apiError(w, http.StatusBadRequest, "NOT_ALLOWED_IN_CURRENT_STATE") +} + +// ApiErrorNotFound responds with a REST error of type "NOT_FOUND". +// For use with "/api" endpoints. +func ApiErrorNotFound(w http.ResponseWriter) { + apiError(w, http.StatusNotFound, "NOT_FOUND") +} + +// ApiErrorResourceInUse responds with a REST error of type "RESOURCE_IN_USE". +// For use with "/api" endpoints. +func ApiErrorResourceInUse(w http.ResponseWriter) { + apiError(w, http.StatusBadRequest, "RESOURCE_IN_USE") +} + +// ApiErrorUnauthorized responds with a REST error of type "UNAUTHORIZED". +// For use with "/api" endpoints. +func ApiErrorUnauthorized(w http.ResponseWriter) { + apiError(w, http.StatusBadRequest, "UNAUTHORIZED") +} + +// ApiErrorUnsupported responds with a REST error of type "UNSUPPORTED". +// For use with "/api" endpoints. +func ApiErrorUnsupported(w http.ResponseWriter) { + apiError(w, http.StatusBadRequest, "UNSUPPORTED") +} + +func apiError(w http.ResponseWriter, statusCode int, errorType string) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(statusCode) + w.Write([]byte(fmt.Sprintf(`{"error_type":"%s", "messages":[]}`, errorType))) +} + func (*handler) error(w http.ResponseWriter, err error) { http.Error(w, err.Error(), http.StatusInternalServerError) log.Print(err) @@ -1735,7 +1801,7 @@ func (s *handler) libraryDeploy(ctx context.Context, c *vim25.Client, lib *libra } name := item.ovf() - desc, err := ioutil.ReadFile(filepath.Join(libraryPath(lib, item.ID), name)) + desc, err := os.ReadFile(filepath.Join(libraryPath(lib, item.ID), name)) if err != nil { return nil, err } @@ -1810,6 +1876,23 @@ func (s *handler) libraryDeploy(ctx context.Context, c *vim25.Client, lib *libra return nil, errors.New(spec.Error[0].LocalizedMessage) } + if config != nil { + if vmImportSpec, ok := spec.ImportSpec.(*types.VirtualMachineImportSpec); ok { + var configSpecs []types.BaseVirtualDeviceConfigSpec + + // Remove devices that we don't want to carry over from the import spec. Otherwise, since we + // just reconfigure the VM with the provided ConfigSpec later these devices won't be removed. + for _, d := range vmImportSpec.ConfigSpec.DeviceChange { + switch d.GetVirtualDeviceConfigSpec().Device.(type) { + case types.BaseVirtualEthernetCard: + default: + configSpecs = append(configSpecs, d) + } + } + vmImportSpec.ConfigSpec.DeviceChange = configSpecs + } + } + req := types.ImportVApp{ This: pool, Spec: spec.ImportSpec, @@ -1865,7 +1948,7 @@ func (s *handler) libraryItemOVF(w http.ResponseWriter, r *http.Request) { ID: id, LibraryID: l.Library.ID, Name: req.Spec.Name, - Description: req.Spec.Description, + Description: &req.Spec.Description, Type: library.ItemTypeOVF, CreationTime: types.NewTime(time.Now()), LastModifiedTime: types.NewTime(time.Now()), @@ -1925,7 +2008,10 @@ func (s *handler) libraryItemOVFID(w http.ResponseWriter, r *http.Request) { if err != nil { return err } - id := vcenter.ResourceID(info.Entity) + id := vcenter.ResourceID{ + Type: info.Entity.Type, + Value: info.Entity.Value, + } d.Succeeded = true d.ResourceID = &id return nil @@ -2265,17 +2351,6 @@ func (s *handler) libraryTrustedCertificatesID(w http.ResponseWriter, r *http.Re } } -func (s *handler) vmID(w http.ResponseWriter, r *http.Request) { - id := path.Base(r.URL.Path) - - switch r.Method { - case http.MethodDelete: - s.deleteVM(&types.ManagedObjectReference{Type: "VirtualMachine", Value: id}) - default: - http.NotFound(w, r) - } -} - func (s *handler) debugEcho(w http.ResponseWriter, r *http.Request) { r.Write(w) } diff --git a/vendor/github.com/vmware/govmomi/vapi/tags/tag_association.go b/vendor/github.com/vmware/govmomi/vapi/tags/tag_association.go index 33b2209366..ca8818191b 100644 --- a/vendor/github.com/vmware/govmomi/vapi/tags/tag_association.go +++ b/vendor/github.com/vmware/govmomi/vapi/tags/tag_association.go @@ -81,7 +81,11 @@ func (c *Manager) AttachTagToMultipleObjects(ctx context.Context, tagID string, var ids []internal.AssociatedObject for i := range refs { - ids = append(ids, internal.AssociatedObject(refs[i].Reference())) + ref := refs[i].Reference() + ids = append(ids, internal.AssociatedObject{ + Type: ref.Type, + Value: ref.Value, + }) } spec := struct { @@ -116,7 +120,10 @@ func (c *Manager) AttachMultipleTagsToObject(ctx context.Context, tagIDs []strin } } - obj := internal.AssociatedObject(ref.Reference()) + obj := internal.AssociatedObject{ + Type: ref.Reference().Type, + Value: ref.Reference().Value, + } spec := struct { ObjectID internal.AssociatedObject `json:"object_id"` TagIDs []string `json:"tag_ids"` @@ -166,7 +173,10 @@ func (c *Manager) DetachMultipleTagsFromObject(ctx context.Context, tagIDs []str } } - obj := internal.AssociatedObject(ref.Reference()) + obj := internal.AssociatedObject{ + Type: ref.Reference().Type, + Value: ref.Reference().Value, + } spec := struct { ObjectID internal.AssociatedObject `json:"object_id"` TagIDs []string `json:"tag_ids"` @@ -337,7 +347,11 @@ func (t *AttachedTags) UnmarshalJSON(b []byte) error { func (c *Manager) ListAttachedTagsOnObjects(ctx context.Context, objectID []mo.Reference) ([]AttachedTags, error) { var ids []internal.AssociatedObject for i := range objectID { - ids = append(ids, internal.AssociatedObject(objectID[i].Reference())) + ref := objectID[i].Reference() + ids = append(ids, internal.AssociatedObject{ + Type: ref.Type, + Value: ref.Value, + }) } spec := struct { diff --git a/vendor/github.com/vmware/govmomi/vapi/vcenter/vcenter_ovf.go b/vendor/github.com/vmware/govmomi/vapi/vcenter/vcenter_ovf.go index 80f0d38c31..71efc23abe 100644 --- a/vendor/github.com/vmware/govmomi/vapi/vcenter/vcenter_ovf.go +++ b/vendor/github.com/vmware/govmomi/vapi/vcenter/vcenter_ovf.go @@ -297,8 +297,10 @@ func (c *Manager) DeployLibraryItem(ctx context.Context, libraryItemID string, d return nil, err } if res.Succeeded { - ref := types.ManagedObjectReference(*res.ResourceID) - return &ref, nil + return &types.ManagedObjectReference{ + Type: res.ResourceID.Type, + Value: res.ResourceID.Value, + }, nil } return nil, res.Error } diff --git a/vendor/github.com/vmware/govmomi/vapi/vm/dataset/dataset.go b/vendor/github.com/vmware/govmomi/vapi/vm/dataset/dataset.go new file mode 100644 index 0000000000..cb178d6fbf --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/vm/dataset/dataset.go @@ -0,0 +1,200 @@ +/* +Copyright (c) 2023-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package dataset + +import ( + "context" + "net/http" + "net/url" + "path" + "strconv" + + "github.com/vmware/govmomi/vapi/rest" + "github.com/vmware/govmomi/vapi/vm/internal" +) + +// Manager extends rest.Client, adding data set related methods. +// +// Data sets functionality was introduced in vSphere 8.0, +// and requires the VM to have virtual hardware version 20 or newer. +// +// See the VMware Guest SDK Programming Guide for details on using data sets +// from within the guest OS of a VM. +// +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/vm/data_sets/ +type Manager struct { + *rest.Client +} + +// NewManager creates a new Manager instance with the given client. +func NewManager(client *rest.Client) *Manager { + return &Manager{ + Client: client, + } +} + +// Access permission to the entries of a data set. +type Access string + +const ( + AccessNone = Access("NONE") + AccessReadOnly = Access("READ_ONLY") + AccessReadWrite = Access("READ_WRITE") +) + +// Describes a data set to be created. +type CreateSpec struct { + // Name should take the form "com.company.project" to avoid conflict with other uses. + // Must not be empty. + Name string `json:"name"` + + // Description of the data set. + Description string `json:"description"` + + // Host controls access to the data set entries by the ESXi host and the vCenter. + // For example, if the host access is set to NONE, the entries of this data set + // will not be accessible through the vCenter API. + // Must not be empty. + Host Access `json:"host"` + + // Guest controls access to the data set entries by the guest OS of the VM (i.e. in-guest APIs). + // For example, if the guest access is set to READ_ONLY, it will be forbidden + // to create, delete, and update entries in this data set via the VMware Guest SDK. + // Must not be empty. + Guest Access `json:"guest"` + + // OmitFromSnapshotAndClone controls whether the data set is included in snapshots and clones of the VM. + // When a VM is reverted to a snapshot, any data set with OmitFromSnapshotAndClone=true will be destroyed. + // Default is false. + OmitFromSnapshotAndClone *bool `json:"omit_from_snapshot_and_clone,omitempty"` +} + +// Describes modifications to a data set. +type UpdateSpec struct { + Description *string `json:"description,omitempty"` + Host *Access `json:"host,omitempty"` + Guest *Access `json:"guest,omitempty"` + OmitFromSnapshotAndClone *bool `json:"omit_from_snapshot_and_clone,omitempty"` +} + +// Data set information. +type Info struct { + Name string `json:"name"` + Description string `json:"description"` + Host Access `json:"host"` + Guest Access `json:"guest"` + Used int `json:"used"` + OmitFromSnapshotAndClone bool `json:"omit_from_snapshot_and_clone"` +} + +// Brief data set information. +type Summary struct { + DataSet string `json:"data_set"` + Name string `json:"name"` + Description string `json:"description"` +} + +const dataSetsPathField = "data-sets" + +func dataSetPath(vm string, dataSet string) string { + return path.Join(internal.VCenterVMPath, url.PathEscape(vm), dataSetsPathField, url.PathEscape(dataSet)) +} + +func dataSetsPath(vm string) string { + return path.Join(internal.VCenterVMPath, url.PathEscape(vm), dataSetsPathField) +} + +const entriesPathField = "entries" + +func entryPath(vm string, dataSet string, key string) string { + return path.Join(internal.VCenterVMPath, url.PathEscape(vm), dataSetsPathField, url.PathEscape(dataSet), entriesPathField, url.PathEscape(key)) +} + +func entriesPath(vm string, dataSet string) string { + return path.Join(internal.VCenterVMPath, url.PathEscape(vm), dataSetsPathField, url.PathEscape(dataSet), entriesPathField) +} + +// CreateDataSet creates a data set associated with the given virtual machine. +func (c *Manager) CreateDataSet(ctx context.Context, vm string, spec *CreateSpec) (string, error) { + url := c.Resource(dataSetsPath(vm)) + var res string + err := c.Do(ctx, url.Request(http.MethodPost, spec), &res) + return res, err +} + +// DeleteDataSet deletes an existing data set from the given virtual machine. +// The operation will fail if the data set is not empty. +// Set the force flag to delete a non-empty data set. +func (c *Manager) DeleteDataSet(ctx context.Context, vm string, dataSet string, force bool) error { + url := c.Resource(dataSetPath(vm, dataSet)) + if force { + url.WithParam("force", strconv.FormatBool(force)) + } + return c.Do(ctx, url.Request(http.MethodDelete), nil) +} + +// GetDataSet retrieves information about the given data set. +func (c *Manager) GetDataSet(ctx context.Context, vm string, dataSet string) (*Info, error) { + url := c.Resource(dataSetPath(vm, dataSet)) + var res Info + err := c.Do(ctx, url.Request(http.MethodGet), &res) + return &res, err +} + +// UpdateDataSet modifies the given data set. +func (c *Manager) UpdateDataSet(ctx context.Context, vm string, dataSet string, spec *UpdateSpec) error { + url := c.Resource(dataSetPath(vm, dataSet)) + return c.Do(ctx, url.Request(http.MethodPatch, spec), nil) +} + +// ListDataSets returns a list of brief descriptions of the data sets on with the given virtual machine. +func (c *Manager) ListDataSets(ctx context.Context, vm string) ([]Summary, error) { + url := c.Resource(dataSetsPath(vm)) + var res []Summary + err := c.Do(ctx, url.Request(http.MethodGet), &res) + return res, err +} + +// SetEntry creates or updates an entry in the given data set. +// If an entry with the given key already exists, it will be overwritten. +// The key can be at most 4096 bytes. The value can be at most 1MB. +func (c *Manager) SetEntry(ctx context.Context, vm string, dataSet string, key string, value string) error { + url := c.Resource(entryPath(vm, dataSet, key)) + return c.Do(ctx, url.Request(http.MethodPut, value), nil) +} + +// GetEntry returns the value of the data set entry with the given key. +func (c *Manager) GetEntry(ctx context.Context, vm string, dataSet string, key string) (string, error) { + url := c.Resource(entryPath(vm, dataSet, key)) + var res string + err := c.Do(ctx, url.Request(http.MethodGet), &res) + return res, err +} + +// DeleteEntry removes an existing entry from the given data set. +func (c *Manager) DeleteEntry(ctx context.Context, vm string, dataSet string, key string) error { + url := c.Resource(entryPath(vm, dataSet, key)) + return c.Do(ctx, url.Request(http.MethodDelete), nil) +} + +// ListEntries returns a list of all entry keys in the given data set. +func (c *Manager) ListEntries(ctx context.Context, vm string, dataSet string) ([]string, error) { + url := c.Resource(entriesPath(vm, dataSet)) + var res []string + err := c.Do(ctx, url.Request(http.MethodGet), &res) + return res, err +} diff --git a/vendor/github.com/vmware/govmomi/vapi/vm/internal/internal.go b/vendor/github.com/vmware/govmomi/vapi/vm/internal/internal.go new file mode 100644 index 0000000000..b016caa1a7 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vapi/vm/internal/internal.go @@ -0,0 +1,24 @@ +/* +Copyright (c) 2023-2023 VMware, Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +const ( + // VCenterVMPath is the REST endpoint for the virtual machine API + VCenterVMPath = "/api/vcenter/vm" + // LegacyVCenterVMPath is the legacy REST endpoint for the virtual machine API, relative to the "/rest" base path + LegacyVCenterVMPath = "/vcenter/vm" +) diff --git a/vendor/github.com/vmware/govmomi/view/list_view.go b/vendor/github.com/vmware/govmomi/view/list_view.go index e8cfb50434..4958941cc6 100644 --- a/vendor/github.com/vmware/govmomi/view/list_view.go +++ b/vendor/github.com/vmware/govmomi/view/list_view.go @@ -34,29 +34,41 @@ func NewListView(c *vim25.Client, ref types.ManagedObjectReference) *ListView { } } -func (v ListView) Add(ctx context.Context, refs []types.ManagedObjectReference) error { +func (v ListView) Add(ctx context.Context, refs []types.ManagedObjectReference) ([]types.ManagedObjectReference, error) { req := types.ModifyListView{ This: v.Reference(), Add: refs, } - _, err := methods.ModifyListView(ctx, v.Client(), &req) - return err + res, err := methods.ModifyListView(ctx, v.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil } -func (v ListView) Remove(ctx context.Context, refs []types.ManagedObjectReference) error { +func (v ListView) Remove(ctx context.Context, refs []types.ManagedObjectReference) ([]types.ManagedObjectReference, error) { req := types.ModifyListView{ This: v.Reference(), Remove: refs, } - _, err := methods.ModifyListView(ctx, v.Client(), &req) - return err + res, err := methods.ModifyListView(ctx, v.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil } -func (v ListView) Reset(ctx context.Context, refs []types.ManagedObjectReference) error { +func (v ListView) Reset(ctx context.Context, refs []types.ManagedObjectReference) ([]types.ManagedObjectReference, error) { req := types.ResetListView{ This: v.Reference(), Obj: refs, } - _, err := methods.ResetListView(ctx, v.Client(), &req) - return err + res, err := methods.ResetListView(ctx, v.Client(), &req) + if err != nil { + return nil, err + } + + return res.Returnval, nil } diff --git a/vendor/github.com/vmware/govmomi/view/task_view.go b/vendor/github.com/vmware/govmomi/view/task_view.go index 68f62f8d10..4e1beef38c 100644 --- a/vendor/github.com/vmware/govmomi/view/task_view.go +++ b/vendor/github.com/vmware/govmomi/view/task_view.go @@ -73,7 +73,7 @@ func (v TaskView) Collect(ctx context.Context, f func([]types.TaskInfo)) error { tasks = change.Val.(types.ArrayOfManagedObjectReference).ManagedObjectReference if len(tasks) != 0 { reset = func() { - _ = v.Reset(ctx, tasks) + _, _ = v.Reset(ctx, tasks) // Remember any tasks we've reported as complete already, // to avoid reporting multiple times when Reset is triggered. @@ -113,7 +113,7 @@ func (v TaskView) Collect(ctx context.Context, f func([]types.TaskInfo)) error { if reset != nil { reset() } else if len(prune) != 0 { - _ = v.Remove(ctx, prune) + _, _ = v.Remove(ctx, prune) } if len(tasks) != 0 && len(infos) == 0 { diff --git a/vendor/github.com/vmware/govmomi/vim25/client.go b/vendor/github.com/vmware/govmomi/vim25/client.go index b14cea8520..6101330953 100644 --- a/vendor/github.com/vmware/govmomi/vim25/client.go +++ b/vendor/github.com/vmware/govmomi/vim25/client.go @@ -1,11 +1,11 @@ /* -Copyright (c) 2015-2016 VMware, Inc. All Rights Reserved. +Copyright (c) 2015-2023 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 +http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -32,7 +32,7 @@ import ( const ( Namespace = "vim25" - Version = "7.0" + Version = "8.0.2.0" Path = "/sdk" ) diff --git a/vendor/github.com/vmware/govmomi/vim25/json/LICENSE b/vendor/github.com/vmware/govmomi/vim25/json/LICENSE new file mode 100644 index 0000000000..6a66aea5ea --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/json/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/vmware/govmomi/vim25/json/README.md b/vendor/github.com/vmware/govmomi/vim25/json/README.md new file mode 100644 index 0000000000..6cbe80349a --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/json/README.md @@ -0,0 +1,9 @@ +# JSON with Discriminators + +The source code in this directory was copied from Go 1.17.13's `encoding/json` package in order to add support for JSON discriminators. Please use the following command to review the diff: + +```shell +C1="$(git log --pretty=format:'%h' --no-patch --grep='Vendor Go 1.17.13 encoding/json')" && \ +C2="$(git log --pretty=format:'%h' --no-patch --grep='JSON Encoding w Discriminator Support')" && \ +git diff "${C1}".."${C2}" +``` diff --git a/vendor/github.com/vmware/govmomi/vim25/json/decode.go b/vendor/github.com/vmware/govmomi/vim25/json/decode.go new file mode 100644 index 0000000000..6a92a2410b --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/json/decode.go @@ -0,0 +1,1319 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Represents JSON data structure using native Go types: booleans, floats, +// strings, arrays, and maps. + +package json + +import ( + "encoding" + "encoding/base64" + "fmt" + "reflect" + "strconv" + "strings" + "unicode" + "unicode/utf16" + "unicode/utf8" +) + +// Unmarshal parses the JSON-encoded data and stores the result +// in the value pointed to by v. If v is nil or not a pointer, +// Unmarshal returns an InvalidUnmarshalError. +// +// Unmarshal uses the inverse of the encodings that +// Marshal uses, allocating maps, slices, and pointers as necessary, +// with the following additional rules: +// +// To unmarshal JSON into a pointer, Unmarshal first handles the case of +// the JSON being the JSON literal null. In that case, Unmarshal sets +// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into +// the value pointed at by the pointer. If the pointer is nil, Unmarshal +// allocates a new value for it to point to. +// +// To unmarshal JSON into a value implementing the Unmarshaler interface, +// Unmarshal calls that value's UnmarshalJSON method, including +// when the input is a JSON null. +// Otherwise, if the value implements encoding.TextUnmarshaler +// and the input is a JSON quoted string, Unmarshal calls that value's +// UnmarshalText method with the unquoted form of the string. +// +// To unmarshal JSON into a struct, Unmarshal matches incoming object +// keys to the keys used by Marshal (either the struct field name or its tag), +// preferring an exact match but also accepting a case-insensitive match. By +// default, object keys which don't have a corresponding struct field are +// ignored (see Decoder.DisallowUnknownFields for an alternative). +// +// To unmarshal JSON into an interface value, +// Unmarshal stores one of these in the interface value: +// +// bool, for JSON booleans +// float64, for JSON numbers +// string, for JSON strings +// []interface{}, for JSON arrays +// map[string]interface{}, for JSON objects +// nil for JSON null +// +// To unmarshal a JSON array into a slice, Unmarshal resets the slice length +// to zero and then appends each element to the slice. +// As a special case, to unmarshal an empty JSON array into a slice, +// Unmarshal replaces the slice with a new empty slice. +// +// To unmarshal a JSON array into a Go array, Unmarshal decodes +// JSON array elements into corresponding Go array elements. +// If the Go array is smaller than the JSON array, +// the additional JSON array elements are discarded. +// If the JSON array is smaller than the Go array, +// the additional Go array elements are set to zero values. +// +// To unmarshal a JSON object into a map, Unmarshal first establishes a map to +// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal +// reuses the existing map, keeping existing entries. Unmarshal then stores +// key-value pairs from the JSON object into the map. The map's key type must +// either be any string type, an integer, implement json.Unmarshaler, or +// implement encoding.TextUnmarshaler. +// +// If a JSON value is not appropriate for a given target type, +// or if a JSON number overflows the target type, Unmarshal +// skips that field and completes the unmarshaling as best it can. +// If no more serious errors are encountered, Unmarshal returns +// an UnmarshalTypeError describing the earliest such error. In any +// case, it's not guaranteed that all the remaining fields following +// the problematic one will be unmarshaled into the target object. +// +// The JSON null value unmarshals into an interface, map, pointer, or slice +// by setting that Go value to nil. Because null is often used in JSON to mean +// ``not present,'' unmarshaling a JSON null into any other Go type has no effect +// on the value and produces no error. +// +// When unmarshaling quoted strings, invalid UTF-8 or +// invalid UTF-16 surrogate pairs are not treated as an error. +// Instead, they are replaced by the Unicode replacement +// character U+FFFD. +// +func Unmarshal(data []byte, v interface{}) error { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + var d decodeState + err := checkValid(data, &d.scan) + if err != nil { + return err + } + + d.init(data) + return d.unmarshal(v) +} + +// Unmarshaler is the interface implemented by types +// that can unmarshal a JSON description of themselves. +// The input can be assumed to be a valid encoding of +// a JSON value. UnmarshalJSON must copy the JSON data +// if it wishes to retain the data after returning. +// +// By convention, to approximate the behavior of Unmarshal itself, +// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. +type Unmarshaler interface { + UnmarshalJSON([]byte) error +} + +// An UnmarshalTypeError describes a JSON value that was +// not appropriate for a value of a specific Go type. +type UnmarshalTypeError struct { + Value string // description of JSON value - "bool", "array", "number -5" + Type reflect.Type // type of Go value it could not be assigned to + Offset int64 // error occurred after reading Offset bytes + Struct string // name of the struct type containing the field + Field string // the full path from root node to the field +} + +func (e *UnmarshalTypeError) Error() string { + if e.Struct != "" || e.Field != "" { + return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String() + } + return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() +} + +// An UnmarshalFieldError describes a JSON object key that +// led to an unexported (and therefore unwritable) struct field. +// +// Deprecated: No longer used; kept for compatibility. +type UnmarshalFieldError struct { + Key string + Type reflect.Type + Field reflect.StructField +} + +func (e *UnmarshalFieldError) Error() string { + return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() +} + +// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. +// (The argument to Unmarshal must be a non-nil pointer.) +type InvalidUnmarshalError struct { + Type reflect.Type +} + +func (e *InvalidUnmarshalError) Error() string { + if e.Type == nil { + return "json: Unmarshal(nil)" + } + + if e.Type.Kind() != reflect.Ptr { + return "json: Unmarshal(non-pointer " + e.Type.String() + ")" + } + return "json: Unmarshal(nil " + e.Type.String() + ")" +} + +func (d *decodeState) unmarshal(v interface{}) error { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Ptr || rv.IsNil() { + return &InvalidUnmarshalError{reflect.TypeOf(v)} + } + + d.scan.reset() + d.scanWhile(scanSkipSpace) + // We decode rv not rv.Elem because the Unmarshaler interface + // test must be applied at the top level of the value. + err := d.value(rv) + if err != nil { + return d.addErrorContext(err) + } + return d.savedError +} + +// A Number represents a JSON number literal. +type Number string + +// String returns the literal text of the number. +func (n Number) String() string { return string(n) } + +// Float64 returns the number as a float64. +func (n Number) Float64() (float64, error) { + return strconv.ParseFloat(string(n), 64) +} + +// Int64 returns the number as an int64. +func (n Number) Int64() (int64, error) { + return strconv.ParseInt(string(n), 10, 64) +} + +// An errorContext provides context for type errors during decoding. +type errorContext struct { + Struct reflect.Type + FieldStack []string +} + +// decodeState represents the state while decoding a JSON value. +type decodeState struct { + data []byte + off int // next read offset in data + opcode int // last read result + scan scanner + errorContext *errorContext + savedError error + useNumber bool + disallowUnknownFields bool + + discriminatorTypeFieldName string + discriminatorValueFieldName string + discriminatorToTypeFn DiscriminatorToTypeFunc +} + +// readIndex returns the position of the last byte read. +func (d *decodeState) readIndex() int { + return d.off - 1 +} + +// phasePanicMsg is used as a panic message when we end up with something that +// shouldn't happen. It can indicate a bug in the JSON decoder, or that +// something is editing the data slice while the decoder executes. +const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" + +func (d *decodeState) init(data []byte) *decodeState { + d.data = data + d.off = 0 + d.savedError = nil + if d.errorContext != nil { + d.errorContext.Struct = nil + // Reuse the allocated space for the FieldStack slice. + d.errorContext.FieldStack = d.errorContext.FieldStack[:0] + } + return d +} + +// saveError saves the first err it is called with, +// for reporting at the end of the unmarshal. +func (d *decodeState) saveError(err error) { + if d.savedError == nil { + d.savedError = d.addErrorContext(err) + } +} + +// addErrorContext returns a new error enhanced with information from d.errorContext +func (d *decodeState) addErrorContext(err error) error { + if d.errorContext != nil && (d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0) { + switch err := err.(type) { + case *UnmarshalTypeError: + err.Struct = d.errorContext.Struct.Name() + err.Field = strings.Join(d.errorContext.FieldStack, ".") + } + } + return err +} + +// skip scans to the end of what was started. +func (d *decodeState) skip() { + s, data, i := &d.scan, d.data, d.off + depth := len(s.parseState) + for { + op := s.step(s, data[i]) + i++ + if len(s.parseState) < depth { + d.off = i + d.opcode = op + return + } + } +} + +// scanNext processes the byte at d.data[d.off]. +func (d *decodeState) scanNext() { + if d.off < len(d.data) { + d.opcode = d.scan.step(&d.scan, d.data[d.off]) + d.off++ + } else { + d.opcode = d.scan.eof() + d.off = len(d.data) + 1 // mark processed EOF with len+1 + } +} + +// scanWhile processes bytes in d.data[d.off:] until it +// receives a scan code not equal to op. +func (d *decodeState) scanWhile(op int) { + s, data, i := &d.scan, d.data, d.off + for i < len(data) { + newOp := s.step(s, data[i]) + i++ + if newOp != op { + d.opcode = newOp + d.off = i + return + } + } + + d.off = len(data) + 1 // mark processed EOF with len+1 + d.opcode = d.scan.eof() +} + +// rescanLiteral is similar to scanWhile(scanContinue), but it specialises the +// common case where we're decoding a literal. The decoder scans the input +// twice, once for syntax errors and to check the length of the value, and the +// second to perform the decoding. +// +// Only in the second step do we use decodeState to tokenize literals, so we +// know there aren't any syntax errors. We can take advantage of that knowledge, +// and scan a literal's bytes much more quickly. +func (d *decodeState) rescanLiteral() { + data, i := d.data, d.off +Switch: + switch data[i-1] { + case '"': // string + for ; i < len(data); i++ { + switch data[i] { + case '\\': + i++ // escaped char + case '"': + i++ // tokenize the closing quote too + break Switch + } + } + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number + for ; i < len(data); i++ { + switch data[i] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '.', 'e', 'E', '+', '-': + default: + break Switch + } + } + case 't': // true + i += len("rue") + case 'f': // false + i += len("alse") + case 'n': // null + i += len("ull") + } + if i < len(data) { + d.opcode = stateEndValue(&d.scan, data[i]) + } else { + d.opcode = scanEnd + } + d.off = i + 1 +} + +// value consumes a JSON value from d.data[d.off-1:], decoding into v, and +// reads the following byte ahead. If v is invalid, the value is discarded. +// The first byte of the value has been read already. +func (d *decodeState) value(v reflect.Value) error { + switch d.opcode { + default: + panic(phasePanicMsg) + + case scanBeginArray: + if v.IsValid() { + if err := d.array(v); err != nil { + return err + } + } else { + d.skip() + } + d.scanNext() + + case scanBeginObject: + if v.IsValid() { + if err := d.object(v); err != nil { + return err + } + } else { + d.skip() + } + d.scanNext() + + case scanBeginLiteral: + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.rescanLiteral() + + if v.IsValid() { + if err := d.literalStore(d.data[start:d.readIndex()], v, false); err != nil { + return err + } + } + } + return nil +} + +type unquotedValue struct{} + +// valueQuoted is like value but decodes a +// quoted string literal or literal null into an interface value. +// If it finds anything other than a quoted string literal or null, +// valueQuoted returns unquotedValue{}. +func (d *decodeState) valueQuoted() interface{} { + switch d.opcode { + default: + panic(phasePanicMsg) + + case scanBeginArray, scanBeginObject: + d.skip() + d.scanNext() + + case scanBeginLiteral: + v := d.literalInterface() + switch v.(type) { + case nil, string: + return v + } + } + return unquotedValue{} +} + +// indirect walks down v allocating pointers as needed, +// until it gets to a non-pointer. +// If it encounters an Unmarshaler, indirect stops and returns that. +// If decodingNull is true, indirect stops at the first settable pointer so it +// can be set to nil. +func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { + // Issue #24153 indicates that it is generally not a guaranteed property + // that you may round-trip a reflect.Value by calling Value.Addr().Elem() + // and expect the value to still be settable for values derived from + // unexported embedded struct fields. + // + // The logic below effectively does this when it first addresses the value + // (to satisfy possible pointer methods) and continues to dereference + // subsequent pointers as necessary. + // + // After the first round-trip, we set v back to the original value to + // preserve the original RW flags contained in reflect.Value. + v0 := v + haveAddr := false + + // If v is a named type and is addressable, + // start with its address, so that if the type has pointer methods, + // we find them. + if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() { + haveAddr = true + v = v.Addr() + } + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) { + haveAddr = false + v = e + continue + } + } + + if v.Kind() != reflect.Ptr { + break + } + + if decodingNull && v.CanSet() { + break + } + + // Prevent infinite loop if v is an interface pointing to its own address: + // var v interface{} + // v = &v + if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { + v = v.Elem() + break + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Unmarshaler); ok { + return u, nil, reflect.Value{} + } + if !decodingNull { + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, reflect.Value{} + } + } + } + + if haveAddr { + v = v0 // restore original value after round-trip Value.Addr().Elem() + haveAddr = false + } else { + v = v.Elem() + } + } + return nil, nil, v +} + +// array consumes an array from d.data[d.off-1:], decoding into v. +// The first byte of the array ('[') has been read already. +func (d *decodeState) array(v reflect.Value) error { + // Check for unmarshaler. + u, ut, pv := indirect(v, false) + if u != nil { + start := d.readIndex() + d.skip() + return u.UnmarshalJSON(d.data[start:d.off]) + } + if ut != nil { + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + } + v = pv + + // Check type of target. + switch v.Kind() { + case reflect.Interface: + if v.NumMethod() == 0 { + // Decoding into nil interface? Switch to non-reflect code. + ai := d.arrayInterface() + v.Set(reflect.ValueOf(ai)) + return nil + } + // Otherwise it's invalid. + fallthrough + default: + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + case reflect.Array, reflect.Slice: + break + } + + i := 0 + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + + // Get element of array, growing if necessary. + if v.Kind() == reflect.Slice { + // Grow slice if necessary + if i >= v.Cap() { + newcap := v.Cap() + v.Cap()/2 + if newcap < 4 { + newcap = 4 + } + newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) + reflect.Copy(newv, v) + v.Set(newv) + } + if i >= v.Len() { + v.SetLen(i + 1) + } + } + + if i < v.Len() { + // Decode into element. + if err := d.value(v.Index(i)); err != nil { + return err + } + } else { + // Ran out of fixed array: skip. + if err := d.value(reflect.Value{}); err != nil { + return err + } + } + i++ + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + + if i < v.Len() { + if v.Kind() == reflect.Array { + // Array. Zero the rest. + z := reflect.Zero(v.Type().Elem()) + for ; i < v.Len(); i++ { + v.Index(i).Set(z) + } + } else { + v.SetLen(i) + } + } + if i == 0 && v.Kind() == reflect.Slice { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) + } + return nil +} + +var nullLiteral = []byte("null") +var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() + +// object consumes an object from d.data[d.off-1:], decoding into v. +// The first byte ('{') of the object has been read already. +func (d *decodeState) object(v reflect.Value) error { + // Check for unmarshaler. + u, ut, pv := indirect(v, false) + if u != nil { + start := d.readIndex() + d.skip() + return u.UnmarshalJSON(d.data[start:d.off]) + } + if ut != nil { + d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + } + v = pv + t := v.Type() + + // Decoding into nil interface? Switch to non-reflect code. + if v.Kind() == reflect.Interface && v.NumMethod() == 0 && !d.isDiscriminatorSet() { + oi := d.objectInterface() + v.Set(reflect.ValueOf(oi)) + return nil + } + + var fields structFields + + // Check type of target: + // struct or + // map[T1]T2 where T1 is string, an integer type, + // or an encoding.TextUnmarshaler + switch v.Kind() { + case reflect.Map: + // Map key must either have string kind, have an integer kind, + // or be an encoding.TextUnmarshaler. + switch t.Key().Kind() { + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + default: + if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) + d.skip() + return nil + } + } + if v.IsNil() { + v.Set(reflect.MakeMap(t)) + } + case reflect.Struct: + fields = cachedTypeFields(t) + // ok + default: + if d.isDiscriminatorSet() { + return d.discriminatorInterfaceDecode(t, v) + } + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) + d.skip() + return nil + } + + var mapElem reflect.Value + var origErrorContext errorContext + if d.errorContext != nil { + origErrorContext = *d.errorContext + } + + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read key. + start := d.readIndex() + d.rescanLiteral() + item := d.data[start:d.readIndex()] + key, ok := unquoteBytes(item) + if !ok { + panic(phasePanicMsg) + } + + // Figure out field corresponding to key. + var subv reflect.Value + destring := false // whether the value is wrapped in a string to be decoded first + + if v.Kind() == reflect.Map { + elemType := t.Elem() + if !mapElem.IsValid() { + mapElem = reflect.New(elemType).Elem() + } else { + mapElem.Set(reflect.Zero(elemType)) + } + subv = mapElem + } else { + var f *field + if i, ok := fields.nameIndex[string(key)]; ok { + // Found an exact name match. + f = &fields.list[i] + } else { + // Fall back to the expensive case-insensitive + // linear search. + for i := range fields.list { + ff := &fields.list[i] + if ff.equalFold(ff.nameBytes, key) { + f = ff + break + } + } + } + if f != nil { + subv = v + destring = f.quoted + for _, i := range f.index { + if subv.Kind() == reflect.Ptr { + if subv.IsNil() { + // If a struct embeds a pointer to an unexported type, + // it is not possible to set a newly allocated value + // since the field is unexported. + // + // See https://golang.org/issue/21357 + if !subv.CanSet() { + d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) + // Invalidate subv to ensure d.value(subv) skips over + // the JSON value without assigning it to subv. + subv = reflect.Value{} + destring = false + break + } + subv.Set(reflect.New(subv.Type().Elem())) + } + subv = subv.Elem() + } + subv = subv.Field(i) + } + if d.errorContext == nil { + d.errorContext = new(errorContext) + } + d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) + d.errorContext.Struct = t + } else if d.disallowUnknownFields { + d.saveError(fmt.Errorf("json: unknown field %q", key)) + } + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + if destring { + switch qv := d.valueQuoted().(type) { + case nil: + if err := d.literalStore(nullLiteral, subv, false); err != nil { + return err + } + case string: + if err := d.literalStore([]byte(qv), subv, true); err != nil { + return err + } + default: + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) + } + } else { + if err := d.value(subv); err != nil { + return err + } + } + + // Write value back to map; + // if using struct, subv points into struct already. + if v.Kind() == reflect.Map { + kt := t.Key() + var kv reflect.Value + switch { + case reflect.PtrTo(kt).Implements(textUnmarshalerType): + kv = reflect.New(kt) + if err := d.literalStore(item, kv, true); err != nil { + return err + } + kv = kv.Elem() + case kt.Kind() == reflect.String: + kv = reflect.ValueOf(key).Convert(kt) + default: + switch kt.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := string(key) + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowInt(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) + break + } + kv = reflect.ValueOf(n).Convert(kt) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + s := string(key) + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowUint(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) + break + } + kv = reflect.ValueOf(n).Convert(kt) + default: + panic("json: Unexpected key type") // should never occur + } + } + if kv.IsValid() { + if !d.isDiscriminatorSet() || kv.String() != d.discriminatorTypeFieldName { + v.SetMapIndex(kv, subv) + } + } + } + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.errorContext != nil { + // Reset errorContext to its original state. + // Keep the same underlying array for FieldStack, to reuse the + // space and avoid unnecessary allocs. + d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] + d.errorContext.Struct = origErrorContext.Struct + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + return nil +} + +// convertNumber converts the number literal s to a float64 or a Number +// depending on the setting of d.useNumber. +func (d *decodeState) convertNumber(s string) (interface{}, error) { + if d.useNumber { + return Number(s), nil + } + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)} + } + return f, nil +} + +var numberType = reflect.TypeOf(Number("")) + +// literalStore decodes a literal stored in item into v. +// +// fromQuoted indicates whether this literal came from unwrapping a +// string from the ",string" struct tag option. this is used only to +// produce more helpful error messages. +func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) error { + // Check for unmarshaler. + if len(item) == 0 { + //Empty string given + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return nil + } + isNull := item[0] == 'n' // null + u, ut, pv := indirect(v, isNull) + if u != nil { + return u.UnmarshalJSON(item) + } + if ut != nil { + if item[0] != '"' { + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return nil + } + val := "number" + switch item[0] { + case 'n': + val = "null" + case 't', 'f': + val = "bool" + } + d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())}) + return nil + } + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + return ut.UnmarshalText(s) + } + + v = pv + + switch c := item[0]; c { + case 'n': // null + // The main parser checks that only true and false can reach here, + // but if this was a quoted string input, it could be anything. + if fromQuoted && string(item) != "null" { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + break + } + switch v.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + v.Set(reflect.Zero(v.Type())) + // otherwise, ignore null for primitives/string + } + case 't', 'f': // true, false + value := item[0] == 't' + // The main parser checks that only true and false can reach here, + // but if this was a quoted string input, it could be anything. + if fromQuoted && string(item) != "true" && string(item) != "false" { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + break + } + switch v.Kind() { + default: + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) + } + case reflect.Bool: + v.SetBool(value) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(value)) + } else { + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) + } + } + + case '"': // string + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + switch v.Kind() { + default: + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + case reflect.Slice: + if v.Type().Elem().Kind() != reflect.Uint8 { + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) + n, err := base64.StdEncoding.Decode(b, s) + if err != nil { + d.saveError(err) + break + } + v.SetBytes(b[:n]) + case reflect.String: + if v.Type() == numberType && !isValidNumber(string(s)) { + return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item) + } + v.SetString(string(s)) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(string(s))) + } else { + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + } + } + + default: // number + if c != '-' && (c < '0' || c > '9') { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + s := string(item) + switch v.Kind() { + default: + if v.Kind() == reflect.String && v.Type() == numberType { + // s must be a valid number, because it's + // already been tokenized. + v.SetString(s) + break + } + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) + case reflect.Interface: + n, err := d.convertNumber(s) + if err != nil { + d.saveError(err) + break + } + if v.NumMethod() != 0 { + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.Set(reflect.ValueOf(n)) + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || v.OverflowInt(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetInt(n) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || v.OverflowUint(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetUint(n) + + case reflect.Float32, reflect.Float64: + n, err := strconv.ParseFloat(s, v.Type().Bits()) + if err != nil || v.OverflowFloat(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetFloat(n) + } + } + return nil +} + +// The xxxInterface routines build up a value to be stored +// in an empty interface. They are not strictly necessary, +// but they avoid the weight of reflection in this common case. + +// valueInterface is like value but returns interface{} +func (d *decodeState) valueInterface() (val interface{}) { + switch d.opcode { + default: + panic(phasePanicMsg) + case scanBeginArray: + val = d.arrayInterface() + d.scanNext() + case scanBeginObject: + val = d.objectInterface() + d.scanNext() + case scanBeginLiteral: + val = d.literalInterface() + } + return +} + +// arrayInterface is like array but returns []interface{}. +func (d *decodeState) arrayInterface() []interface{} { + var v = make([]interface{}, 0) + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + + v = append(v, d.valueInterface()) + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + return v +} + +// objectInterface is like object but returns map[string]interface{}. +func (d *decodeState) objectInterface() map[string]interface{} { + m := make(map[string]interface{}) + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read string key. + start := d.readIndex() + d.rescanLiteral() + item := d.data[start:d.readIndex()] + key, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + // Read value. + m[key] = d.valueInterface() + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + return m +} + +// literalInterface consumes and returns a literal from d.data[d.off-1:] and +// it reads the following byte ahead. The first byte of the literal has been +// read already (that's how the caller knows it's a literal). +func (d *decodeState) literalInterface() interface{} { + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.rescanLiteral() + + item := d.data[start:d.readIndex()] + + switch c := item[0]; c { + case 'n': // null + return nil + + case 't', 'f': // true, false + return c == 't' + + case '"': // string + s, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + return s + + default: // number + if c != '-' && (c < '0' || c > '9') { + panic(phasePanicMsg) + } + n, err := d.convertNumber(string(item)) + if err != nil { + d.saveError(err) + } + return n + } +} + +// getu4 decodes \uXXXX from the beginning of s, returning the hex value, +// or it returns -1. +func getu4(s []byte) rune { + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + return -1 + } + var r rune + for _, c := range s[2:6] { + switch { + case '0' <= c && c <= '9': + c = c - '0' + case 'a' <= c && c <= 'f': + c = c - 'a' + 10 + case 'A' <= c && c <= 'F': + c = c - 'A' + 10 + default: + return -1 + } + r = r*16 + rune(c) + } + return r +} + +// unquote converts a quoted JSON string literal s into an actual string t. +// The rules are different than for Go, so cannot use strconv.Unquote. +func unquote(s []byte) (t string, ok bool) { + s, ok = unquoteBytes(s) + t = string(s) + return +} + +func unquoteBytes(s []byte) (t []byte, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return + } + s = s[1 : len(s)-1] + + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { + return s, true + } + + b := make([]byte, len(s)+2*utf8.UTFMax) + w := copy(b, s[0:r]) + for r < len(s) { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-2*utf8.UTFMax { + nb := make([]byte, (len(b)+utf8.UTFMax)*2) + copy(nb, b[0:w]) + b = nb + } + switch c := s[r]; { + case c == '\\': + r++ + if r >= len(s) { + return + } + switch s[r] { + default: + return + case '"', '\\', '/', '\'': + b[w] = s[r] + r++ + w++ + case 'b': + b[w] = '\b' + r++ + w++ + case 'f': + b[w] = '\f' + r++ + w++ + case 'n': + b[w] = '\n' + r++ + w++ + case 'r': + b[w] = '\r' + r++ + w++ + case 't': + b[w] = '\t' + r++ + w++ + case 'u': + r-- + rr := getu4(s[r:]) + if rr < 0 { + return + } + r += 6 + if utf16.IsSurrogate(rr) { + rr1 := getu4(s[r:]) + if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8.EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode.ReplacementChar + } + w += utf8.EncodeRune(b[w:], rr) + } + + // Quote, control characters are invalid. + case c == '"', c < ' ': + return + + // ASCII + case c < utf8.RuneSelf: + b[w] = c + r++ + w++ + + // Coerce to well-formed UTF-8. + default: + rr, size := utf8.DecodeRune(s[r:]) + r += size + w += utf8.EncodeRune(b[w:], rr) + } + } + return b[0:w], true +} diff --git a/vendor/github.com/vmware/govmomi/vim25/json/discriminator.go b/vendor/github.com/vmware/govmomi/vim25/json/discriminator.go new file mode 100644 index 0000000000..ce315dd527 --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/json/discriminator.go @@ -0,0 +1,568 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import ( + "fmt" + "reflect" + "regexp" + "strconv" + "sync" +) + +// DiscriminatorToTypeFunc is used to get a reflect.Type from its +// discriminator. +type DiscriminatorToTypeFunc func(discriminator string) (reflect.Type, bool) + +// TypeToDiscriminatorFunc is used to get a discriminator string from a +// reflect.Type. Empty return value suppresses discriminator rendering. +type TypeToDiscriminatorFunc func(reflect.Type) (discriminator string) + +// DefaultDiscriminatorFunc is shorthand for the ShortName func and is used when +// no other discriminator func is set explicitly +var DefaultDiscriminatorFunc = ShortName + +// ShortName returns the type name in golang without the package name +func ShortName(t reflect.Type) (discriminator string) { + tn := t.Name() + if tn == "" { + return t.String() + } + return tn +} + +// FullName return the name of the type prefixed with the package name as +// appropriate +func FullName(t reflect.Type) (discriminator string) { + tn := t.Name() + if tn == "" { + return t.String() + } + if pp := t.PkgPath(); pp != "" { + return fmt.Sprintf("%s.%s", pp, tn) + } + return tn +} + +// DiscriminatorEncodeMode is a mask that describes the different encode +// options. +type DiscriminatorEncodeMode uint8 + +const ( + // DiscriminatorEncodeTypeNameRootValue causes the type name to be encoded + // for the root value. + DiscriminatorEncodeTypeNameRootValue DiscriminatorEncodeMode = 1 << iota + + // DiscriminatorEncodeTypeNameAllObjects causes the type name to be encoded + // for all struct and map values. Please note this specifically does not + // apply to the root value. + DiscriminatorEncodeTypeNameAllObjects + + // DiscriminatorEncodeTypeNameIfRequired is the default behavior when + // the discriminator is set, and the type name is only encoded if required. + DiscriminatorEncodeTypeNameIfRequired DiscriminatorEncodeMode = 0 +) + +func (m DiscriminatorEncodeMode) root() bool { + return m&DiscriminatorEncodeTypeNameRootValue > 0 +} + +func (m DiscriminatorEncodeMode) all() bool { + return m&DiscriminatorEncodeTypeNameAllObjects > 0 +} + +func (d *decodeState) isDiscriminatorSet() bool { + return d.discriminatorTypeFieldName != "" && + d.discriminatorValueFieldName != "" +} + +// discriminatorOpType describes the current operation related to +// discriminators when reading a JSON object's fields. +type discriminatorOpType uint8 + +const ( + // discriminatorOpTypeNameField indicates the discriminator type name + // field was discovered. + discriminatorOpTypeNameField = iota + 1 + + // discriminatorOpValueField indicates the discriminator value field + // was discovered. + discriminatorOpValueField +) + +func (d *decodeState) discriminatorGetValue() (reflect.Value, error) { + // Record the current offset so we know where the data starts. + offset := d.readIndex() + + // Create a temporary decodeState used to inspect the current object + // and determine its discriminator type and decode its value. + dd := &decodeState{ + disallowUnknownFields: d.disallowUnknownFields, + useNumber: d.useNumber, + discriminatorToTypeFn: d.discriminatorToTypeFn, + discriminatorTypeFieldName: d.discriminatorTypeFieldName, + discriminatorValueFieldName: d.discriminatorValueFieldName, + } + dd.init(append([]byte{}, d.data[offset:]...)) + defer freeScanner(&dd.scan) + dd.scan.reset() + + var ( + t reflect.Type // the instance of the type + valueOff = -1 // the offset of a possible discriminator value + ) + + dd.scanWhile(scanSkipSpace) + if dd.opcode != scanBeginObject { + panic(phasePanicMsg) + } + + for { + dd.scanWhile(scanSkipSpace) + if dd.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if dd.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read key. + start := dd.readIndex() + dd.rescanLiteral() + item := dd.data[start:dd.readIndex()] + key, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + + // Check to see if the key is related to the discriminator. + var discriminatorOp discriminatorOpType + switch key { + case d.discriminatorTypeFieldName: + discriminatorOp = discriminatorOpTypeNameField + case d.discriminatorValueFieldName: + discriminatorOp = discriminatorOpValueField + } + + // Read : before value. + if dd.opcode == scanSkipSpace { + dd.scanWhile(scanSkipSpace) + } + + if dd.opcode != scanObjectKey { + panic(phasePanicMsg) + } + dd.scanWhile(scanSkipSpace) + + // Read value. + valOff := dd.readIndex() + val := dd.valueInterface() + + switch discriminatorOp { + case discriminatorOpTypeNameField: + tn, ok := val.(string) + if !ok { + return reflect.Value{}, fmt.Errorf( + "json: discriminator type at offset %d is not string", + offset+valOff) + } + if tn == "" { + return reflect.Value{}, fmt.Errorf( + "json: discriminator type at offset %d is empty", + offset+valOff) + } + + // Parse the type name into a type instance. + ti, err := discriminatorParseTypeName(tn, d.discriminatorToTypeFn) + if err != nil { + return reflect.Value{}, err + } + + // Assign the type instance to the outer variable, t. + t = ti + + // Primitive types and types with Unmarshaler are wrapped in a + // structure with type and value fields. Structures and Maps not + // implementing Unmarshaler use discriminator embedded within their + // content. + if useNestedDiscriminator(t) { + // If the type is a map or a struct not implementing Unmarshaler + // then it is not necessary to continue walking over the current + // JSON object since it will be completely re-scanned to decode + // its value into the discovered type. + dd.opcode = scanEndObject + } else { + // Otherwise if the value offset has been discovered then it is + // safe to stop walking over the current JSON object as well. + if valueOff > -1 { + dd.opcode = scanEndObject + } + } + case discriminatorOpValueField: + valueOff = valOff + + // If the type has been discovered then it is safe to stop walking + // over the current JSON object. + if t != nil { + dd.opcode = scanEndObject + } + } + + // Next token must be , or }. + if dd.opcode == scanSkipSpace { + dd.scanWhile(scanSkipSpace) + } + if dd.opcode == scanEndObject { + break + } + if dd.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + + // If there is not a type discriminator then return early. + if t == nil { + return reflect.Value{}, fmt.Errorf("json: missing discriminator") + } + + // Instantiate a new instance of the discriminated type. + var v reflect.Value + switch t.Kind() { + case reflect.Slice: + // MakeSlice returns a value that is not addressable. + // Instead, use MakeSlice to get the type, then use + // reflect.New to create an addressable value. + v = reflect.New(reflect.MakeSlice(t, 0, 0).Type()).Elem() + case reflect.Map: + // MakeMap returns a value that is not addressable. + // Instead, use MakeMap to get the type, then use + // reflect.New to create an addressable value. + v = reflect.New(reflect.MakeMap(t).Type()).Elem() + case reflect.Complex64, reflect.Complex128: + return reflect.Value{}, fmt.Errorf("json: unsupported discriminator type: %s", t.Kind()) + default: + v = reflect.New(t) + } + + // Reset the decode state to prepare for decoding the data. + dd.scan.reset() + + if useNestedDiscriminator(t) { + // Set the offset to zero since the entire object will be decoded + // into v. + dd.off = 0 + } else { + // Set the offset to what it was before the discriminator value was + // read so only the value field is decoded into v. + dd.off = valueOff + } + // This will initialize the correct scan step and op code. + dd.scanWhile(scanSkipSpace) + + // Decode the data into the value. + if err := dd.value(v); err != nil { + return reflect.Value{}, err + } + + // Check the saved error as well since the decoder.value function does not + // always return an error. If the reflected value is still zero, then it is + // likely the decoder was unable to decode the value. + if err := dd.savedError; err != nil { + switch v.Kind() { + case reflect.Ptr, reflect.Interface: + v = v.Elem() + } + if v.IsZero() { + return reflect.Value{}, err + } + } + + return v, nil +} + +func (d *decodeState) discriminatorInterfaceDecode(t reflect.Type, v reflect.Value) error { + + defer func() { + // Advance the decode state, throwing away the value. + _ = d.objectInterface() + }() + + dv, err := d.discriminatorGetValue() + if err != nil { + return err + } + + switch dv.Kind() { + case reflect.Map, reflect.Slice: + if dv.Type().AssignableTo(t) { + v.Set(dv) + return nil + } + if pdv := dv.Addr(); pdv.Type().AssignableTo(t) { + v.Set(pdv) + return nil + } + case reflect.Ptr: + if dve := dv.Elem(); dve.Type().AssignableTo(t) { + v.Set(dve) + return nil + } + if dv.Type().AssignableTo(t) { + v.Set(dv) + return nil + } + } + + return fmt.Errorf("json: unsupported discriminator kind: %s", dv.Kind()) +} + +func (o encOpts) isDiscriminatorSet() bool { + return o.discriminatorTypeFieldName != "" && + o.discriminatorValueFieldName != "" +} + +func discriminatorInterfaceEncode(e *encodeState, v reflect.Value, opts encOpts) { + v = v.Elem() + + if v.Type().Implements(marshalerType) { + discriminatorValue := opts.discriminatorValueFn(v.Type()) + if discriminatorValue == "" { + marshalerEncoder(e, v, opts) + } + e.WriteString(`{"`) + e.WriteString(opts.discriminatorTypeFieldName) + e.WriteString(`":"`) + e.WriteString(discriminatorValue) + e.WriteString(`","`) + e.WriteString(opts.discriminatorValueFieldName) + e.WriteString(`":`) + marshalerEncoder(e, v, opts) + e.WriteByte('}') + return + } + + switch v.Kind() { + case reflect.Chan, reflect.Func, reflect.Invalid: + e.error(&UnsupportedValueError{v, fmt.Sprintf("invalid kind: %s", v.Kind())}) + case reflect.Map: + e.discriminatorEncodeTypeName = true + newMapEncoder(v.Type())(e, v, opts) + case reflect.Struct: + e.discriminatorEncodeTypeName = true + newStructEncoder(v.Type())(e, v, opts) + case reflect.Ptr: + discriminatorInterfaceEncode(e, v, opts) + default: + discriminatorValue := opts.discriminatorValueFn(v.Type()) + if discriminatorValue == "" { + e.reflectValue(v, opts) + return + } + e.WriteString(`{"`) + e.WriteString(opts.discriminatorTypeFieldName) + e.WriteString(`":"`) + e.WriteString(discriminatorValue) + e.WriteString(`","`) + e.WriteString(opts.discriminatorValueFieldName) + e.WriteString(`":`) + e.reflectValue(v, opts) + e.WriteByte('}') + } +} + +func discriminatorMapEncode(e *encodeState, v reflect.Value, opts encOpts) { + if !e.discriminatorEncodeTypeName && !opts.discriminatorEncodeMode.all() { + return + } + discriminatorValue := opts.discriminatorValueFn(v.Type()) + if discriminatorValue == "" { + return + } + e.WriteByte('"') + e.WriteString(opts.discriminatorTypeFieldName) + e.WriteString(`":"`) + e.WriteString(discriminatorValue) + e.WriteByte('"') + if v.Len() > 0 { + e.WriteByte(',') + } + e.discriminatorEncodeTypeName = false +} + +func discriminatorStructEncode(e *encodeState, v reflect.Value, opts encOpts) byte { + if !e.discriminatorEncodeTypeName && !opts.discriminatorEncodeMode.all() { + return '{' + } + discriminatorValue := opts.discriminatorValueFn(v.Type()) + if discriminatorValue == "" { + return '{' + } + e.WriteString(`{"`) + e.WriteString(opts.discriminatorTypeFieldName) + e.WriteString(`":"`) + e.WriteString(discriminatorValue) + e.WriteByte('"') + e.discriminatorEncodeTypeName = false + return ',' +} + +var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() + +// Discriminator is nested in map and struct unless they implement Unmarshaler. +func useNestedDiscriminator(t reflect.Type) bool { + if t.Implements(unmarshalerType) || reflect.PtrTo(t).Implements(unmarshalerType) { + return false + } + kind := t.Kind() + if kind == reflect.Struct || kind == reflect.Map { + return true + } + return false +} + +var discriminatorTypeRegistry = map[string]reflect.Type{ + "uint": reflect.TypeOf(uint(0)), + "uint8": reflect.TypeOf(uint8(0)), + "uint16": reflect.TypeOf(uint16(0)), + "uint32": reflect.TypeOf(uint32(0)), + "uint64": reflect.TypeOf(uint64(0)), + "uintptr": reflect.TypeOf(uintptr(0)), + "int": reflect.TypeOf(int(0)), + "int8": reflect.TypeOf(int8(0)), + "int16": reflect.TypeOf(int16(0)), + "int32": reflect.TypeOf(int32(0)), + "int64": reflect.TypeOf(int64(0)), + "float32": reflect.TypeOf(float32(0)), + "float64": reflect.TypeOf(float64(0)), + "bool": reflect.TypeOf(true), + "string": reflect.TypeOf(""), + "any": reflect.TypeOf((*interface{})(nil)).Elem(), + "interface{}": reflect.TypeOf((*interface{})(nil)).Elem(), + "interface {}": reflect.TypeOf((*interface{})(nil)).Elem(), + + // Not supported, but here to prevent the decoder from panicing + // if encountered. + "complex64": reflect.TypeOf(complex64(0)), + "complex128": reflect.TypeOf(complex128(0)), +} + +// discriminatorPointerTypeCache caches the pointer type for another type. +// For example, a key that was the int type would have a value that is the +// *int type. +var discriminatorPointerTypeCache sync.Map // map[reflect.Type]reflect.Type + +// cachedPointerType returns the pointer type for another and avoids repeated +// work by using a cache. +func cachedPointerType(t reflect.Type) reflect.Type { + if value, ok := discriminatorPointerTypeCache.Load(t); ok { + return value.(reflect.Type) + } + pt := reflect.New(t).Type() + value, _ := discriminatorPointerTypeCache.LoadOrStore(t, pt) + return value.(reflect.Type) +} + +var ( + mapPatt = regexp.MustCompile(`^\*?map\[([^\]]+)\](.+)$`) + arrayPatt = regexp.MustCompile(`^\*?\[(\d+)\](.+)$`) + slicePatt = regexp.MustCompile(`^\*?\[\](.+)$`) +) + +// discriminatorParseTypeName returns a reflect.Type for the given type name. +func discriminatorParseTypeName( + typeName string, + typeFn DiscriminatorToTypeFunc) (reflect.Type, error) { + + // Check to see if the type is an array, map, or slice. + var ( + aln = -1 // array length + etn string // map or slice element type name + ktn string // map key type name + ) + if m := arrayPatt.FindStringSubmatch(typeName); len(m) > 0 { + i, err := strconv.Atoi(m[1]) + if err != nil { + return nil, err + } + aln = i + etn = m[2] + } else if m := slicePatt.FindStringSubmatch(typeName); len(m) > 0 { + etn = m[1] + } else if m := mapPatt.FindStringSubmatch(typeName); len(m) > 0 { + ktn = m[1] + etn = m[2] + } + + // indirectTypeName checks to see if the type name begins with a + // "*" characters. If it does, then the type name sans the "*" + // character is returned along with a true value indicating the + // type is a pointer. Otherwise the original type name is returned + // along with a false value. + indirectTypeName := func(tn string) (string, bool) { + if len(tn) > 1 && tn[0] == '*' { + return tn[1:], true + } + return tn, false + } + + lookupType := func(tn string) (reflect.Type, bool) { + // Get the actual type name and a flag indicating whether the + // type is a pointer. + n, p := indirectTypeName(tn) + + var t reflect.Type + ok := false + // look up the type in the external registry to allow name override. + if typeFn != nil { + t, ok = typeFn(n) + } + if !ok { + // Use the built-in registry if the external registry fails + if t, ok = discriminatorTypeRegistry[n]; !ok { + return nil, false + } + } + // If the type was a pointer then get the type's pointer type. + if p { + t = cachedPointerType(t) + } + return t, true + } + + var t reflect.Type + + if ktn == "" && etn != "" { + et, ok := lookupType(etn) + if !ok { + return nil, fmt.Errorf("json: invalid array/slice element type: %s", etn) + } + if aln > -1 { + // Array + t = reflect.ArrayOf(aln, et) + } else { + // Slice + t = reflect.SliceOf(et) + } + } else if ktn != "" && etn != "" { + // Map + kt, ok := lookupType(ktn) + if !ok { + return nil, fmt.Errorf("json: invalid map key type: %s", ktn) + } + et, ok := lookupType(etn) + if !ok { + return nil, fmt.Errorf("json: invalid map element type: %s", etn) + } + t = reflect.MapOf(kt, et) + } else { + var ok bool + if t, ok = lookupType(typeName); !ok { + return nil, fmt.Errorf("json: invalid discriminator type: %s", typeName) + } + } + + return t, nil +} diff --git a/vendor/github.com/vmware/govmomi/vim25/json/encode.go b/vendor/github.com/vmware/govmomi/vim25/json/encode.go new file mode 100644 index 0000000000..0c8aa202fe --- /dev/null +++ b/vendor/github.com/vmware/govmomi/vim25/json/encode.go @@ -0,0 +1,1453 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package json implements encoding and decoding of JSON as defined in +// RFC 7159. The mapping between JSON and Go values is described +// in the documentation for the Marshal and Unmarshal functions. +// +// See "JSON and Go" for an introduction to this package: +// https://golang.org/doc/articles/json_and_go.html +package json + +import ( + "bytes" + "encoding" + "encoding/base64" + "fmt" + "math" + "reflect" + "sort" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// Marshal returns the JSON encoding of v. +// +// Marshal traverses the value v recursively. +// If an encountered value implements the Marshaler interface +// and is not a nil pointer, Marshal calls its MarshalJSON method +// to produce JSON. If no MarshalJSON method is present but the +// value implements encoding.TextMarshaler instead, Marshal calls +// its MarshalText method and encodes the result as a JSON string. +// The nil pointer exception is not strictly necessary +// but mimics a similar, necessary exception in the behavior of +// UnmarshalJSON. +// +// Otherwise, Marshal uses the following type-dependent default encodings: +// +// Boolean values encode as JSON booleans. +// +// Floating point, integer, and Number values encode as JSON numbers. +// +// String values encode as JSON strings coerced to valid UTF-8, +// replacing invalid bytes with the Unicode replacement rune. +// So that the JSON will be safe to embed inside HTML