Repository: vmware/govmomi
Pull request #3570 (2024-10-03 17:04:35)

govc: add storage.policy.info flag to query IO filters
- Use internalpbm namespace for PbmQueryIOFiltersFromProfileId
- vcsim: override response namespace from struct tag


Patch:
diff --git a/govc/storage/policy/info.go b/govc/storage/policy/info.go
index 99a464f1..11621c85 100644
--- a/govc/storage/policy/info.go
+++ b/govc/storage/policy/info.go
@@ -38,6 +38,7 @@ type info struct {
 
 	compliance bool
 	storage    bool
+	iofilters  bool
 }
 
 func init() {
@@ -53,6 +54,10 @@ func (cmd *info) Register(ctx context.Context, f *flag.FlagSet) {
 
 	f.BoolVar(&cmd.storage, "s", false, "Check Storage Compatibility")
 	f.BoolVar(&cmd.compliance, "c", false, "Check VM Compliance")
+
+	if cli.ShowUnreleased() {
+		f.BoolVar(&cmd.iofilters, "i", false, "Query IO Filters")
+	}
 }
 
 func (cmd *info) Process(ctx context.Context) error {
@@ -79,9 +84,10 @@ Examples:
 }
 
 type Policy struct {
-	Profile              types.BasePbmProfile `json:"profile"`
-	CompliantVM          []string             `json:"compliantVM"`
-	CompatibleDatastores []string             `json:"compatibleDatastores"`
+	Profile              types.BasePbmProfile            `json:"profile"`
+	CompliantVM          []string                        `json:"compliantVM"`
+	CompatibleDatastores []string                        `json:"compatibleDatastores"`
+	FilterMap            []types.PbmProfileToIofilterMap `json:"filterMap,omitempty"`
 }
 
 type infoResult struct {
@@ -190,6 +196,13 @@ func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error {
 			}
 		}
 
+		if cmd.iofilters {
+			policy.FilterMap, err = c.QueryIOFiltersFromProfileId(ctx, p.ProfileId.UniqueId)
+			if err != nil {
+				return err
+			}
+		}
+
 		policies = append(policies, policy)
 	}
 
diff --git a/pbm/methods/internal_methods.go b/pbm/methods/internal_methods.go
index 11b6fc50..3c82f7ef 100644
--- a/pbm/methods/internal_methods.go
+++ b/pbm/methods/internal_methods.go
@@ -24,8 +24,8 @@ import (
 )
 
 type PbmQueryIOFiltersFromProfileIdBody struct {
-	Req    *types.PbmQueryIOFiltersFromProfileId         `xml:"urn:pbm PbmQueryIOFiltersFromProfileId,omitempty"`
-	Res    *types.PbmQueryIOFiltersFromProfileIdResponse `xml:"urn:pbm PbmQueryIOFiltersFromProfileIdResponse,omitempty"`
+	Req    *types.PbmQueryIOFiltersFromProfileId         `xml:"urn:internalpbm PbmQueryIOFiltersFromProfileId,omitempty"`
+	Res    *types.PbmQueryIOFiltersFromProfileIdResponse `xml:"urn:internalpbm PbmQueryIOFiltersFromProfileIdResponse,omitempty"`
 	Fault_ *soap.Fault                                   `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
 }
 
diff --git a/simulator/folder.go b/simulator/folder.go
index dcf2dfa7..bd97e6b4 100644
--- a/simulator/folder.go
+++ b/simulator/folder.go
@@ -772,274 +772,6 @@ func (f *Folder) DestroyTask(ctx *Context, req *types.Destroy_Task) soap.HasFaul
 	}
 }
 
-func addPlacementFault(body *methods.PlaceVmsXClusterBody, vmName string, vmRef *types.ManagedObjectReference, poolRef types.ManagedObjectReference) {
-	faults := types.PlaceVmsXClusterResultPlacementFaults{
-		VmName:       vmName,
-		ResourcePool: poolRef,
-		Vm:           vmRef,
-		Faults: []types.LocalizedMethodFault{
-			{
-				Fault: &types.GenericDrsFault{},
-			},
-		},
-	}
-	body.Res.Returnval.Faults = append(body.Res.Returnval.Faults, faults)
-}
-
-func generateInitialPlacementAction(ctx *Context, inputConfigSpec *types.VirtualMachineConfigSpec, pool *ResourcePool,
-	cluster *ClusterComputeResource, hostRequired, datastoreRequired bool) *types.ClusterClusterInitialPlacementAction {
-	var configSpec *types.VirtualMachineConfigSpec
-
-	placementAction := types.ClusterClusterInitialPlacementAction{
-		Pool: pool.Self,
-	}
-
-	if hostRequired {
-		randomHost := cluster.Host[rand.Intn(len(cluster.Host))]
-		placementAction.TargetHost = &randomHost
-	}
-
-	if datastoreRequired {
-		configSpec = inputConfigSpec
-
-		// TODO: This is just an initial implementation aimed at returning some data but it is not
-		// necessarily fully consistent, like we should ensure the host, if also required, has the
-		// datastore mounted.
-		ds := ctx.Map.Get(cluster.Datastore[rand.Intn(len(cluster.Datastore))]).(*Datastore)
-
-		if configSpec.Files == nil {
-			configSpec.Files = new(types.VirtualMachineFileInfo)
-		}
-		configSpec.Files.VmPathName = fmt.Sprintf("[%[1]s] %[2]s/%[2]s.vmx", ds.Name, inputConfigSpec.Name)
-
-		for _, change := range configSpec.DeviceChange {
-			dspec := change.GetVirtualDeviceConfigSpec()
-
-			if dspec.FileOperation != types.VirtualDeviceConfigSpecFileOperationCreate {
-				continue
-			}
-
-			switch dspec.Operation {
-			case types.VirtualDeviceConfigSpecOperationAdd:
-				device := dspec.Device
-				d := device.GetVirtualDevice()
-
-				switch device.(type) {
-				case *types.VirtualDisk:
-					switch b := d.Backing.(type) {
-					case types.BaseVirtualDeviceFileBackingInfo:
-						info := b.GetVirtualDeviceFileBackingInfo()
-						info.Datastore = types.NewReference(ds.Reference())
-
-						var dsPath object.DatastorePath
-						if dsPath.FromString(info.FileName) {
-							dsPath.Datastore = ds.Name
-							info.FileName = dsPath.String()
-						}
-					}
-				}
-			}
-		}
-	}
-
-	placementAction.ConfigSpec = configSpec
-	return &placementAction
-}
-
-func generateRecommendationForRelocate(ctx *Context, req *types.PlaceVmsXCluster) *methods.PlaceVmsXClusterBody {
-
-	pools := req.PlacementSpec.ResourcePools
-	specs := req.PlacementSpec.VmPlacementSpecs
-
-	body := new(methods.PlaceVmsXClusterBody)
-	body.Res = new(types.PlaceVmsXClusterResponse)
-	hostRequired := req.PlacementSpec.HostRecommRequired != nil && *req.PlacementSpec.HostRecommRequired
-	datastoreRequired := req.PlacementSpec.DatastoreRecommRequired != nil && *req.PlacementSpec.DatastoreRecommRequired
-
-	for _, spec := range specs {
-
-		// The RelocateSpec must be set.
-		if spec.RelocateSpec == nil {
-			body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "relocateSpec"})
-			return body
-		}
-
-		// The VM Reference must be set.
-		if spec.Vm == nil {
-			body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "vm"})
-			return body
-		}
-
-		vmRef := ctx.Map.Get(*spec.Vm)
-		if vmRef == nil {
-			body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "vm"})
-			return body
-		}
-
-		vm := vmRef.(*VirtualMachine)
-		pool := ctx.Map.Get(pools[rand.Intn(len(pools))]).(*ResourcePool)
-		cluster := ctx.Map.Get(pool.Owner).(*ClusterComputeResource)
-
-		if len(cluster.Host) == 0 {
-			addPlacementFault(body, spec.ConfigSpec.Name, &vm.Self, pool.Self)
-			continue
-		}
-
-		reco := types.ClusterRecommendation{
-			Key:        "1",
-			Type:       "V1",
-			Time:       time.Now(),
-			Rating:     1,
-			Reason:     string(types.RecommendationReasonCodeXClusterPlacement),
-			ReasonText: string(types.RecommendationReasonCodeXClusterPlacement),
-			Target:     &cluster.Self,
-		}
-
-		placementAction := generateInitialPlacementAction(ctx, &spec.ConfigSpec, pool, cluster, hostRequired, datastoreRequired)
-
-		reco.Action = append(reco.Action, placementAction)
-
-		body.Res.Returnval.PlacementInfos = append(body.Res.Returnval.PlacementInfos,
-			types.PlaceVmsXClusterResultPlacementInfo{
-				VmName:         vm.Name,
-				Recommendation: reco,
-				Vm:             &vm.Self,
-			},
-		)
-	}
-	return body
-}
-
-func generateRecommendationForReconfigure(ctx *Context, req *types.PlaceVmsXCluster) *methods.PlaceVmsXClusterBody {
-
-	pools := req.PlacementSpec.ResourcePools
-	specs := req.PlacementSpec.VmPlacementSpecs
-
-	body := new(methods.PlaceVmsXClusterBody)
-	body.Res = new(types.PlaceVmsXClusterResponse)
-	hostRequired := req.PlacementSpec.HostRecommRequired != nil && *req.PlacementSpec.HostRecommRequired
-	datastoreRequired := req.PlacementSpec.DatastoreRecommRequired != nil && *req.PlacementSpec.DatastoreRecommRequired
-
-	for _, spec := range specs {
-
-		// Only a single pool must be set
-		if len(pools) != 1 {
-			body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "resourcePools"})
-			return body
-		}
-
-		// The RelocateSpec must not be set.
-		if spec.RelocateSpec != nil {
-			body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "relocateSpec"})
-			return body
-		}
-
-		// The VM Reference must be set.
-		if spec.Vm == nil {
-			body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "vm"})
-			return body
-		}
-
-		vmRef := ctx.Map.Get(*spec.Vm)
-		if vmRef == nil {
-			body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "vm"})
-			return body
-		}
-
-		vm := vmRef.(*VirtualMachine)
-
-		// Use VM's current host
-		host := Map.Get(vm.Runtime.Host.Reference()).(*HostSystem)
-
-		if host.Parent.Type != "ClusterComputeResource" {
-			addPlacementFault(body, spec.ConfigSpec.Name, &vm.Self, host.Self)
-			continue
-		}
-
-		cluster := ctx.Map.Get(*host.Parent).(*ClusterComputeResource)
-		pool := ctx.Map.Get(*cluster.ResourcePool).(*ResourcePool)
-
-		reco := types.ClusterRecommendation{
-			Key:        "1",
-			Type:       "V1",
-			Time:       time.Now(),
-			Rating:     1,
-			Reason:     string(types.RecommendationReasonCodeXClusterPlacement),
-			ReasonText: string(types.RecommendationReasonCodeXClusterPlacement),
-			Target:     &cluster.Self,
-		}
-
-		placementAction := generateInitialPlacementAction(ctx, &spec.ConfigSpec, pool, cluster, hostRequired, datastoreRequired)
-
-		reco.Action = append(reco.Action, placementAction)
-
-		body.Res.Returnval.PlacementInfos = append(body.Res.Returnval.PlacementInfos,
-			types.PlaceVmsXClusterResultPlacementInfo{
-				VmName:         vm.Name,
-				Recommendation: reco,
-				Vm:             &vm.Self,
-			},
-		)
-	}
-	return body
-}
-
-func generateRecommendationForCreateAndPowerOn(ctx *Context, req *types.PlaceVmsXCluster) *methods.PlaceVmsXClusterBody {
-
-	pools := req.PlacementSpec.ResourcePools
-	specs := req.PlacementSpec.VmPlacementSpecs
-
-	body := new(methods.PlaceVmsXClusterBody)
-	body.Res = new(types.PlaceVmsXClusterResponse)
-	hostRequired := req.PlacementSpec.HostRecommRequired != nil && *req.PlacementSpec.HostRecommRequired
-	datastoreRequired := req.PlacementSpec.DatastoreRecommRequired != nil && *req.PlacementSpec.DatastoreRecommRequired
-
-	for _, spec := range specs {
-
-		// The RelocateSpec must not be set.
-		if spec.RelocateSpec != nil {
-			body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "relocateSpec"})
-			return body
-		}
-
-		// The name in the ConfigSpec must set.
-		if spec.ConfigSpec.Name == "" {
-			body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "configSpec.name"})
-			return body
-		}
-
-		pool := ctx.Map.Get(pools[rand.Intn(len(pools))]).(*ResourcePool)
-		cluster := ctx.Map.Get(pool.Owner).(*ClusterComputeResource)
-
-		if len(cluster.Host) == 0 {
-			addPlacementFault(body, spec.ConfigSpec.Name, nil, pool.Self)
-			continue
-		}
-
-		reco := types.ClusterRecommendation{
-			Key:        "1",
-			Type:       "V1",
-			Time:       time.Now(),
-			Rating:     1,
-			Reason:     string(types.RecommendationReasonCodeXClusterPlacement),
-			ReasonText: string(types.RecommendationReasonCodeXClusterPlacement),
-			Target:     &cluster.Self,
-		}
-
-		placementAction := generateInitialPlacementAction(ctx, &spec.ConfigSpec, pool, cluster, hostRequired, datastoreRequired)
-
-		reco.Action = append(reco.Action, placementAction)
-
-		body.Res.Returnval.PlacementInfos = append(body.Res.Returnval.PlacementInfos,
-			types.PlaceVmsXClusterResultPlacementInfo{
-				VmName:         spec.ConfigSpec.Name,
-				Recommendation: reco,
-			},
-		)
-	}
-	return body
-}
-
 func (f *Folder) PlaceVmsXCluster(ctx *Context, req *types.PlaceVmsXCluster) soap.HasFault {
 	body := new(methods.PlaceVmsXClusterBody)
 
@@ -1073,28 +805,115 @@ func (f *Folder) PlaceVmsXCluster(ctx *Context, req *types.PlaceVmsXCluster) soa
 		clusters[pool.Owner] = struct{}{}
 	}
 
-	// MVP: Only a single VM placement spec is supported.
+	// MVP: Only a single VM is supported.
 	if len(specs) != 1 {
 		body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "vmPlacementSpecs"})
 		return body
 	}
 
-	placementType := types.PlaceVmsXClusterSpecPlacementType(req.PlacementSpec.PlacementType)
-
-	// An empty placement type defaults to CreateAndPowerOn.
-	if req.PlacementSpec.PlacementType == "" {
-		placementType = types.PlaceVmsXClusterSpecPlacementTypeCreateAndPowerOn
+	for _, spec := range specs {
+		if spec.ConfigSpec.Name == "" {
+			body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "configSpec.name"})
+			return body
+		}
 	}
 
-	switch placementType {
-	case types.PlaceVmsXClusterSpecPlacementTypeCreateAndPowerOn:
-		return generateRecommendationForCreateAndPowerOn(ctx, req)
-	case types.PlaceVmsXClusterSpecPlacementTypeRelocate:
-		return generateRecommendationForRelocate(ctx, req)
-	case types.PlaceVmsXClusterSpecPlacementTypeReconfigure:
-		return generateRecommendationForReconfigure(ctx, req)
+	body.Res = new(types.PlaceVmsXClusterResponse)
+	hostRequired := req.PlacementSpec.HostRecommRequired != nil && *req.PlacementSpec.HostRecommRequired
+	datastoreRequired := req.PlacementSpec.DatastoreRecommRequired != nil && *req.PlacementSpec.DatastoreRecommRequired
+
+	for _, spec := range specs {
+		pool := ctx.Map.Get(pools[rand.Intn(len(pools))]).(*ResourcePool)
+		cluster := ctx.Map.Get(pool.Owner).(*ClusterComputeResource)
+
+		if len(cluster.Host) == 0 {
+			faults := types.PlaceVmsXClusterResultPlacementFaults{
+				VmName:       spec.ConfigSpec.Name,
+				ResourcePool: pool.Self,
+				Faults: []types.LocalizedMethodFault{
+					{
+						Fault: &types.GenericDrsFault{},
+					},
+				},
+			}
+			body.Res.Returnval.Faults = append(body.Res.Returnval.Faults, faults)
+		} else {
+			var configSpec *types.VirtualMachineConfigSpec
+
+			res := types.ClusterRecommendation{
+				Key:        "1",
+				Type:       "V1",
+				Time:       time.Now(),
+				Rating:     1,
+				Reason:     string(types.RecommendationReasonCodeXClusterPlacement),
+				ReasonText: string(types.RecommendationReasonCodeXClusterPlacement),
+				Target:     &cluster.Self,
+			}
+
+			placementAction := types.ClusterClusterInitialPlacementAction{
+				Pool: pool.Self,
+			}
+
+			if hostRequired {
+				randomHost := cluster.Host[rand.Intn(len(cluster.Host))]
+				placementAction.TargetHost = &randomHost
+			}
+
+			if datastoreRequired {
+				configSpec = &spec.ConfigSpec
+
+				// TODO: This is just an initial implementation aimed at returning some data but it is not
+				// necessarily fully consistent, like we should ensure the host, if also required, has the
+				// datastore mounted.
+				ds := ctx.Map.Get(cluster.Datastore[rand.Intn(len(cluster.Datastore))]).(*Datastore)
+
+				if configSpec.Files == nil {
+					configSpec.Files = new(types.VirtualMachineFileInfo)
+				}
+				configSpec.Files.VmPathName = fmt.Sprintf("[%[1]s] %[2]s/%[2]s.vmx", ds.Name, spec.ConfigSpec.Name)
+
+				for _, change := range configSpec.DeviceChange {
+					dspec := change.GetVirtualDeviceConfigSpec()
+
+					if dspec.FileOperation != types.VirtualDeviceConfigSpecFileOperationCreate {
+						continue
+					}
+
+					switch dspec.Operation {
+					case types.VirtualDeviceConfigSpecOperationAdd:
+						device := dspec.Device
+						d := device.GetVirtualDevice()
+
+						switch device.(type) {
+						case *types.VirtualDisk:
+							switch b := d.Backing.(type) {
+							case types.BaseVirtualDeviceFileBackingInfo:
+								info := b.GetVirtualDeviceFileBackingInfo()
+								info.Datastore = types.NewReference(ds.Reference())
+
+								var dsPath object.DatastorePath
+								if dsPath.FromString(info.FileName) {
+									dsPath.Datastore = ds.Name
+									info.FileName = dsPath.String()
+								}
+							}
+						}
+					}
+				}
+
+				placementAction.ConfigSpec = configSpec
+			}
+
+			res.Action = append(res.Action, &placementAction)
+
+			body.Res.Returnval.PlacementInfos = append(body.Res.Returnval.PlacementInfos,
+				types.PlaceVmsXClusterResultPlacementInfo{
+					VmName:         spec.ConfigSpec.Name,
+					Recommendation: res,
+				},
+			)
+		}
 	}
 
-	body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "placementType"})
 	return body
 }
diff --git a/simulator/simulator.go b/simulator/simulator.go
index 4215df11..71c0037c 100644
--- a/simulator/simulator.go
+++ b/simulator/simulator.go
@@ -315,16 +315,29 @@ type response struct {
 }
 
 func (r *response) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
-	val := reflect.ValueOf(r.Body).Elem().FieldByName("Res")
+	body := reflect.ValueOf(r.Body).Elem()
+	val := body.FieldByName("Res")
 	if !val.IsValid() {
 		return fmt.Errorf("%T: invalid response type (missing 'Res' field)", r.Body)
 	}
 	if val.IsNil() {
 		return fmt.Errorf("%T: invalid response (nil 'Res' field)", r.Body)
 	}
+
+	// Default response namespace
+	ns := "urn:" + r.Namespace
+	// Override namespace from struct tag if defined
+	field, _ := body.Type().FieldByName("Res")
+	if tag := field.Tag.Get("xml"); tag != "" {
+		tags := strings.Split(tag, " ")
+		if len(tags) > 0 && strings.HasPrefix(tags[0], "urn") {
+			ns = tags[0]
+		}
+	}
+
 	res := xml.StartElement{
 		Name: xml.Name{
-			Space: "urn:" + r.Namespace,
+			Space: ns,
 			Local: val.Elem().Type().Name(),
 		},
 	}
diff --git a/vim25/types/unreleased.go b/vim25/types/unreleased.go
index 57bc82a1..72bc1082 100644
--- a/vim25/types/unreleased.go
+++ b/vim25/types/unreleased.go
@@ -1,17 +1,17 @@
 /*
-Copyright (c) 2022-2024 VMware, Inc. All Rights Reserved.
+   Copyright (c) 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
+   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.
+   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
@@ -75,10 +75,9 @@ func init() {
 type PlaceVmsXClusterResultPlacementFaults struct {
 	DynamicData
 
-	ResourcePool ManagedObjectReference  `xml:"resourcePool"`
-	VmName       string                  `xml:"vmName"`
-	Faults       []LocalizedMethodFault  `xml:"faults,omitempty"`
-	Vm           *ManagedObjectReference `xml:"vm,omitempty"`
+	ResourcePool ManagedObjectReference `xml:"resourcePool"`
+	VmName       string                 `xml:"vmName"`
+	Faults       []LocalizedMethodFault `xml:"faults,omitempty"`
 }
 
 func init() {
@@ -88,48 +87,18 @@ func init() {
 type PlaceVmsXClusterResultPlacementInfo struct {
 	DynamicData
 
-	VmName         string                  `xml:"vmName"`
-	Recommendation ClusterRecommendation   `xml:"recommendation"`
-	Vm             *ManagedObjectReference `xml:"vm,omitempty"`
+	VmName         string                `xml:"vmName"`
+	Recommendation ClusterRecommendation `xml:"recommendation"`
 }
 
 func init() {
 	t["PlaceVmsXClusterResultPlacementInfo"] = reflect.TypeOf((*PlaceVmsXClusterResultPlacementInfo)(nil)).Elem()
 }
 
-// Defines the type of placement
-type PlaceVmsXClusterSpecPlacementType string
-
-const (
-	// Create a new VM to be powered On
-	PlaceVmsXClusterSpecPlacementTypeCreateAndPowerOn = PlaceVmsXClusterSpecPlacementType("createAndPowerOn")
-	// Reconfigure a VM
-	PlaceVmsXClusterSpecPlacementTypeReconfigure = PlaceVmsXClusterSpecPlacementType("reconfigure")
-	// Relocate a VM
-	PlaceVmsXClusterSpecPlacementTypeRelocate = PlaceVmsXClusterSpecPlacementType("relocate")
-)
-
-func (e PlaceVmsXClusterSpecPlacementType) Values() []PlaceVmsXClusterSpecPlacementType {
-	return []PlaceVmsXClusterSpecPlacementType{
-		PlaceVmsXClusterSpecPlacementTypeCreateAndPowerOn,
-		PlaceVmsXClusterSpecPlacementTypeReconfigure,
-		PlaceVmsXClusterSpecPlacementTypeRelocate,
-	}
-}
-
-func (e PlaceVmsXClusterSpecPlacementType) Strings() []string {
-	return EnumValuesAsStrings(e.Values())
-}
-
-func init() {
-	t["PlaceVmsXClusterSpecPlacementType"] = reflect.TypeOf((*PlaceVmsXClusterSpecPlacementType)(nil)).Elem()
-}
-
 type PlaceVmsXClusterSpec struct {
 	DynamicData
 
 	ResourcePools           []ManagedObjectReference              `xml:"resourcePools,omitempty"`
-	PlacementType           string                                `xml:"placementType,omitempty"`
 	VmPlacementSpecs        []PlaceVmsXClusterSpecVmPlacementSpec `xml:"vmPlacementSpecs,omitempty"`
 	HostRecommRequired      *bool                                 `xml:"hostRecommRequired"`
 	DatastoreRecommRequired *bool                                 `xml:"datastoreRecommRequired"`
@@ -142,9 +111,7 @@ func init() {
 type PlaceVmsXClusterSpecVmPlacementSpec struct {
 	DynamicData
 
-	Vm           *ManagedObjectReference     `xml:"vm,omitempty"`
-	ConfigSpec   VirtualMachineConfigSpec    `xml:"configSpec"`
-	RelocateSpec *VirtualMachineRelocateSpec `xml:"relocateSpec,omitempty"`
+	ConfigSpec VirtualMachineConfigSpec `xml:"configSpec"`
 }
 
 func init() {
@@ -152,25 +119,3 @@ func init() {
 }
 
 const RecommendationReasonCodeXClusterPlacement = RecommendationReasonCode("xClusterPlacement")
-
-type ClusterReconfigurePlacementAction struct {
-	ClusterAction
-	TargetHost *ManagedObjectReference   `xml:"targetHost,omitempty"`
-	Pool       ManagedObjectReference    `xml:"pool"`
-	ConfigSpec *VirtualMachineConfigSpec `xml:"configSpec,omitempty"`
-}
-
-func init() {
-	t["ClusterReconfigurePlacementAction"] = reflect.TypeOf((*ClusterReconfigurePlacementAction)(nil)).Elem()
-}
-
-type ClusterRelocatePlacementAction struct {
-	ClusterAction
-	TargetHost   *ManagedObjectReference     `xml:"targetHost,omitempty"`
-	Pool         ManagedObjectReference      `xml:"pool"`
-	RelocateSpec *VirtualMachineRelocateSpec `xml:"relocateSpec,omitempty"`
-}
-
-func init() {
-	t["ClusterRelocatePlacementAction"] = reflect.TypeOf((*ClusterRelocatePlacementAction)(nil)).Elem()
-}


Test patch:
diff --git a/govc/test/storage.bats b/govc/test/storage.bats
index e31dd910..8a10aec9 100755
--- a/govc/test/storage.bats
+++ b/govc/test/storage.bats
@@ -25,6 +25,12 @@ load test_helper
 
     run govc storage.policy.info "vSAN Default Storage Policy"
     assert_success
+
+    run env GOVC_SHOW_UNRELEASED=true govc storage.policy.info -json -i "VM Encryption Policy"
+    assert_success
+
+    kind="$(jq -r .policies[].filterMap[].iofilters[].filterType <<<"$output")"
+    assert_equal "ENCRYPTION" "$kind"
 }
 
 @test "storage.policy.create" {
diff --git a/simulator/cluster_compute_resource_test.go b/simulator/cluster_compute_resource_test.go
index 915b3443..9ff0ad11 100644
--- a/simulator/cluster_compute_resource_test.go
+++ b/simulator/cluster_compute_resource_test.go
@@ -1,11 +1,11 @@
 /*
-Copyright (c) 2017-2024 VMware, Inc. All Rights Reserved.
+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
+    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,
@@ -259,7 +259,7 @@ func TestPlaceVmRelocate(t *testing.T) {
 				"InvalidArgument",
 			},
 			{
-				"relocate with a diskId in spec.disk that does not exist in the vm",
+				"relocate with a diskId in spec.dick that does not exist in the vm",
 				&types.VirtualMachineRelocateSpec{
 					Host: &hostMoRef,
 					Disk: []types.VirtualMachineRelocateSpecDiskLocator{
diff --git a/simulator/folder_test.go b/simulator/folder_test.go
index 796cbb37..c898fbc9 100644
--- a/simulator/folder_test.go
+++ b/simulator/folder_test.go
@@ -1,11 +1,11 @@
 /*
-Copyright (c) 2017-2024 VMware, Inc. All Rights Reserved.
+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
+    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 (
 	"context"
 	"reflect"
-	"strings"
 	"testing"
 
 	"github.com/vmware/govmomi"
@@ -611,7 +610,7 @@ func TestFolderCreateDVS(t *testing.T) {
 	}
 }
 
-func TestPlaceVmsXClusterCreateAndPowerOn(t *testing.T) {
+func TestPlaceVmsXCluster(t *testing.T) {
 	vpx := VPX()
 	vpx.Cluster = 3
 
@@ -646,224 +645,3 @@ func TestPlaceVmsXClusterCreateAndPowerOn(t *testing.T) {
 		}
 	}, vpx)
 }
-
-func TestPlaceVmsXClusterRelocate(t *testing.T) {
-	vpx := VPX()
-	vpx.Cluster = 3
-
-	Test(func(ctx context.Context, c *vim25.Client) {
-		finder := find.NewFinder(c, true)
-		datacenter, err := finder.DefaultDatacenter(ctx)
-		if err != nil {
-			t.Fatalf("failed to get default datacenter: %v", err)
-		}
-		finder.SetDatacenter(datacenter)
-
-		pools, err := finder.ResourcePoolList(ctx, "/DC0/host/DC0_C*/*")
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		var poolMoRefs []types.ManagedObjectReference
-		for _, pool := range pools {
-			poolMoRefs = append(poolMoRefs, pool.Reference())
-		}
-
-		vmMoRef := Map.Any("VirtualMachine").(*VirtualMachine).Reference()
-
-		cfgSpec := types.VirtualMachineConfigSpec{}
-
-		tests := []struct {
-			name         string
-			poolMoRefs   []types.ManagedObjectReference
-			configSpec   types.VirtualMachineConfigSpec
-			relocateSpec *types.VirtualMachineRelocateSpec
-			vmMoRef      *types.ManagedObjectReference
-			expectedErr  string
-		}{
-			{
-				"relocate without any resource pools",
-				nil,
-				cfgSpec,
-				&types.VirtualMachineRelocateSpec{},
-				&vmMoRef,
-				"InvalidArgument",
-			},
-			{
-				"relocate without a relocate spec",
-				poolMoRefs,
-				cfgSpec,
-				nil,
-				&vmMoRef,
-				"InvalidArgument",
-			},
-			{
-				"relocate without a vm in the placement spec",
-				poolMoRefs,
-				cfgSpec,
-				&types.VirtualMachineRelocateSpec{},
-				nil,
-				"InvalidArgument",
-			},
-			{
-				"relocate with a non-existing vm in the placement spec",
-				poolMoRefs,
-				cfgSpec,
-				&types.VirtualMachineRelocateSpec{},
-				&types.ManagedObjectReference{
-					Type:  "VirtualMachine",
-					Value: "fake-vm-999",
-				},
-				"InvalidArgument",
-			},
-			{
-				"relocate with an empty relocate spec",
-				poolMoRefs,
-				cfgSpec,
-				&types.VirtualMachineRelocateSpec{},
-				&vmMoRef,
-				"",
-			},
-		}
-
-		for testNo, test := range tests {
-			test := test // assign to local var since loop var is reused
-
-			placeVmsXClusterSpec := types.PlaceVmsXClusterSpec{
-				ResourcePools: test.poolMoRefs,
-				PlacementType: string(types.PlaceVmsXClusterSpecPlacementTypeRelocate),
-			}
-
-			placeVmsXClusterSpec.VmPlacementSpecs = []types.PlaceVmsXClusterSpecVmPlacementSpec{{
-				ConfigSpec:   test.configSpec,
-				Vm:           test.vmMoRef,
-				RelocateSpec: test.relocateSpec,
-			}}
-
-			folder := object.NewRootFolder(c)
-			res, err := folder.PlaceVmsXCluster(ctx, placeVmsXClusterSpec)
-
-			if err == nil && test.expectedErr != "" {
-				t.Fatalf("Test %v: expected error %q, received nil", testNo, test.expectedErr)
-			} else if err != nil &&
-				(test.expectedErr == "" || !strings.Contains(err.Error(), test.expectedErr)) {
-				t.Fatalf("Test %v: expected error %q, received %v", testNo, test.expectedErr, err)
-			}
-
-			if err == nil {
-				if len(res.PlacementInfos) != len(placeVmsXClusterSpec.VmPlacementSpecs) {
-					t.Errorf("%d PlacementInfos vs %d VmPlacementSpecs", len(res.PlacementInfos), len(placeVmsXClusterSpec.VmPlacementSpecs))
-				}
-			}
-		}
-	}, vpx)
-}
-
-func TestPlaceVmsXClusterReconfigure(t *testing.T) {
-	vpx := VPX()
-	// All hosts are cluster hosts
-	vpx.Host = 0
-
-	Test(func(ctx context.Context, c *vim25.Client) {
-		finder := find.NewFinder(c, true)
-		datacenter, err := finder.DefaultDatacenter(ctx)
-		if err != nil {
-			t.Fatalf("failed to get default datacenter: %v", err)
-		}
-		finder.SetDatacenter(datacenter)
-
-		vm := Map.Any("VirtualMachine").(*VirtualMachine)
-		host := Map.Get(vm.Runtime.Host.Reference()).(*HostSystem)
-		cluster := Map.Get(*host.Parent).(*ClusterComputeResource)
-		pool := Map.Get(*cluster.ResourcePool).(*ResourcePool)
-
-		var poolMoRefs []types.ManagedObjectReference
-		poolMoRefs = append(poolMoRefs, pool.Reference())
-
-		cfgSpec := types.VirtualMachineConfigSpec{}
-
-		tests := []struct {
-			name         string
-			poolMoRefs   []types.ManagedObjectReference
-			configSpec   types.VirtualMachineConfigSpec
-			relocateSpec *types.VirtualMachineRelocateSpec
-			vmMoRef      *types.ManagedObjectReference
-			expectedErr  string
-		}{
-			{
-				"reconfigure without any resource pools",
-				nil,
-				cfgSpec,
-				nil,
-				&vm.Self,
-				"InvalidArgument",
-			},
-			{
-				"reconfigure with a relocate spec",
-				poolMoRefs,
-				cfgSpec,
-				&types.VirtualMachineRelocateSpec{},
-				&vm.Self,
-				"InvalidArgument",
-			},
-			{
-				"reconfigure without a vm in the placement spec",
-				poolMoRefs,
-				cfgSpec,
-				nil,
-				nil,
-				"InvalidArgument",
-			},
-			{
-				"reconfigure with a non-existing vm in the placement spec",
-				poolMoRefs,
-				cfgSpec,
-				nil,
-				&types.ManagedObjectReference{
-					Type:  "VirtualMachine",
-					Value: "fake-vm-999",
-				},
-				"InvalidArgument",
-			},
-			{
-				"reconfigure with an empty config spec",
-				poolMoRefs,
-				cfgSpec,
-				nil,
-				&vm.Self,
-				"",
-			},
-		}
-
-		for testNo, test := range tests {
-			test := test // assign to local var since loop var is reused
-
-			placeVmsXClusterSpec := types.PlaceVmsXClusterSpec{
-				ResourcePools: test.poolMoRefs,
-				PlacementType: string(types.PlaceVmsXClusterSpecPlacementTypeReconfigure),
-			}
-
-			placeVmsXClusterSpec.VmPlacementSpecs = []types.PlaceVmsXClusterSpecVmPlacementSpec{{
-				ConfigSpec:   test.configSpec,
-				Vm:           test.vmMoRef,
-				RelocateSpec: test.relocateSpec,
-			}}
-
-			folder := object.NewRootFolder(c)
-			res, err := folder.PlaceVmsXCluster(ctx, placeVmsXClusterSpec)
-
-			if err == nil && test.expectedErr != "" {
-				t.Fatalf("Test %v: expected error %q, received nil", testNo, test.expectedErr)
-			} else if err != nil &&
-				(test.expectedErr == "" || !strings.Contains(err.Error(), test.expectedErr)) {
-				t.Fatalf("Test %v: expected error %q, received %v", testNo, test.expectedErr, err)
-			}
-
-			if err == nil {
-				if len(res.PlacementInfos) != len(placeVmsXClusterSpec.VmPlacementSpecs) {
-					t.Errorf("%d PlacementInfos vs %d VmPlacementSpecs", len(res.PlacementInfos), len(placeVmsXClusterSpec.VmPlacementSpecs))
-				}
-			}
-		}
-	}, vpx)
-}