Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package govc for openSUSE:Factory checked in at 2026-07-06 12:33:55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/govc (Old) and /work/SRC/openSUSE:Factory/.govc.new.1982 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "govc" Mon Jul 6 12:33:55 2026 rev:34 rq:1363935 version:0.55.1 Changes: -------- --- /work/SRC/openSUSE:Factory/govc/govc.changes 2026-06-28 21:08:30.534066576 +0200 +++ /work/SRC/openSUSE:Factory/.govc.new.1982/govc.changes 2026-07-06 12:36:24.743915461 +0200 @@ -1,0 +2,16 @@ +Mon Jul 06 05:04:24 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 0.55.1: + * Fix + - [ea8603d] remove ovf test files with non-ascii names + * Chore + - [1e372f1] Update version.go for v0.55.1 + * Commits + - [1e372f1] chore: Update version.go for v0.55.1 + - [18b33ca] feat(cns): add ActiveClusters to + CnsVolumePolicyReconfigSpec + - [e5a1169] Add simulator methods for eam2 cluster solutions + api + - [ea8603d] fix: remove ovf test files with non-ascii names + +------------------------------------------------------------------- Old: ---- govc-0.55.0.obscpio New: ---- govc-0.55.1.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ govc.spec ++++++ --- /var/tmp/diff_new_pack.9YSp1j/_old 2026-07-06 12:36:27.460009672 +0200 +++ /var/tmp/diff_new_pack.9YSp1j/_new 2026-07-06 12:36:27.484010505 +0200 @@ -17,7 +17,7 @@ Name: govc -Version: 0.55.0 +Version: 0.55.1 Release: 0 Summary: vSphere CLI built on top of govmomi License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.9YSp1j/_old 2026-07-06 12:36:27.936026184 +0200 +++ /var/tmp/diff_new_pack.9YSp1j/_new 2026-07-06 12:36:27.972027433 +0200 @@ -3,8 +3,8 @@ <param name="url">https://github.com/vmware/govmomi.git</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">refs/tags/v0.55.0</param> - <param name="match-tag">v0.55.0</param> + <param name="revision">refs/tags/v0.55.1</param> + <param name="match-tag">v*</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.9YSp1j/_old 2026-07-06 12:36:28.128032844 +0200 +++ /var/tmp/diff_new_pack.9YSp1j/_new 2026-07-06 12:36:28.196035203 +0200 @@ -3,6 +3,6 @@ <param name="url">https://github.com/vmware/govmomi</param> <param name="changesrevision">df7c057af6c06430955ce56d6f04b7e49138f9b3</param></service><service name="tar_scm"> <param name="url">https://github.com/vmware/govmomi.git</param> - <param name="changesrevision">cb2d98b50e63532939817ffb86ca87fe748ff3f0</param></service></servicedata> + <param name="changesrevision">1e372f1c01953d43fe4d573eb60f33f7e3d3aa41</param></service></servicedata> (No newline at EOF) ++++++ govc-0.55.0.obscpio -> govc-0.55.1.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/govc-0.55.0/cns/types/activeclusters_test.go new/govc-0.55.1/cns/types/activeclusters_test.go --- old/govc-0.55.0/cns/types/activeclusters_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/govc-0.55.1/cns/types/activeclusters_test.go 2026-07-03 16:30:07.000000000 +0200 @@ -0,0 +1,52 @@ +// © Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "strings" + "testing" + + "github.com/vmware/govmomi/vim25/types" + "github.com/vmware/govmomi/vim25/xml" +) + +// TestCnsVolumePolicyReconfigSpecActiveClusters verifies that the +// ActiveClusters field serializes into the CNS ReconfigPolicy request, so CNS +// can auto-relocate a volume whose target profile differs. It mirrors the +// existing CnsVolumeCreateSpec.ActiveClusters serialization. +func TestCnsVolumePolicyReconfigSpecActiveClusters(t *testing.T) { + spec := CnsVolumePolicyReconfigSpec{ + VolumeId: CnsVolumeId{Id: "vol-1"}, + Profile: []types.BaseVirtualMachineProfileSpec{ + &types.VirtualMachineDefinedProfileSpec{ProfileId: "policy-1"}, + }, + ActiveClusters: []types.ManagedObjectReference{ + {Type: "ClusterComputeResource", Value: "domain-c1"}, + }, + } + + b, err := xml.Marshal(spec) + if err != nil { + t.Fatalf("marshal: %v", err) + } + + out := string(b) + if !strings.Contains(out, "activeClusters") { + t.Errorf("expected activeClusters element in:\n%s", out) + } + if !strings.Contains(out, "domain-c1") { + t.Errorf("expected cluster moref value domain-c1 in:\n%s", out) + } + + // omitempty: no ActiveClusters -> no element (an in-place reconfigure). + spec.ActiveClusters = nil + b, err = xml.Marshal(spec) + if err != nil { + t.Fatalf("marshal (empty): %v", err) + } + if strings.Contains(string(b), "activeClusters") { + t.Errorf("expected no activeClusters element when empty, got:\n%s", string(b)) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/govc-0.55.0/cns/types/types.go new/govc-0.55.1/cns/types/types.go --- old/govc-0.55.0/cns/types/types.go 2026-06-26 18:42:07.000000000 +0200 +++ new/govc-0.55.1/cns/types/types.go 2026-07-03 16:30:07.000000000 +0200 @@ -986,8 +986,9 @@ type CnsVolumePolicyReconfigSpec struct { types.DynamicData - VolumeId CnsVolumeId `xml:"volumeId" json:"volumeId"` - Profile []types.BaseVirtualMachineProfileSpec `xml:"profile,omitempty,typeattr" json:"profile"` + VolumeId CnsVolumeId `xml:"volumeId" json:"volumeId"` + Profile []types.BaseVirtualMachineProfileSpec `xml:"profile,omitempty,typeattr" json:"profile"` + ActiveClusters []types.ManagedObjectReference `xml:"activeClusters,omitempty,typeattr" json:"activeClusters"` } func init() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/govc-0.55.0/internal/version/version.go new/govc-0.55.1/internal/version/version.go --- old/govc-0.55.0/internal/version/version.go 2026-06-26 18:42:07.000000000 +0200 +++ new/govc-0.55.1/internal/version/version.go 2026-07-03 16:30:07.000000000 +0200 @@ -9,5 +9,5 @@ ClientName = "govmomi" // ClientVersion is the version of this SDK - ClientVersion = "0.55.0" + ClientVersion = "0.55.1" ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' "old/govc-0.55.0/ovf/fixtures/external/standard_ovas/non-ascii/chinese/chinese_characters/\350\231\232\346\213\237\346\234\272.ovf" "new/govc-0.55.1/ovf/fixtures/external/standard_ovas/non-ascii/chinese/chinese_characters/\350\231\232\346\213\237\346\234\272.ovf" --- "old/govc-0.55.0/ovf/fixtures/external/standard_ovas/non-ascii/chinese/chinese_characters/\350\231\232\346\213\237\346\234\272.ovf" 2026-06-26 18:42:07.000000000 +0200 +++ "new/govc-0.55.1/ovf/fixtures/external/standard_ovas/non-ascii/chinese/chinese_characters/\350\231\232\346\213\237\346\234\272.ovf" 1970-01-01 01:00:00.000000000 +0100 @@ -1,115 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<Envelope xmlns="http://schemas.dmtf.org/ovf/envelope/1" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"> - <References> - <File ovf:href="虚拟机-disk1.vmdk" ovf:id="file1" ovf:size="68096"/> - </References> - <DiskSection> - <Info>List of the virtual disks</Info> - <Disk ovf:capacity="40" ovf:capacityAllocationUnits="byte * 2^20" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:populatedSize="0"/> - </DiskSection> - <NetworkSection> - <Info>The list of logical networks</Info> - <Network ovf:name="VM Network"> - <Description>The VM Network network</Description> - </Network> - </NetworkSection> - <VirtualSystem ovf:id="虚拟机"> - <Info>A Virtual system</Info> - <Name>虚拟机</Name> - <OperatingSystemSection ovf:id="103" vmw:osType="windows7Server64Guest"> - <Info>The operating system installed</Info> - <Description>Microsoft Windows Server 2008 R2 (64-bit)</Description> - </OperatingSystemSection> - <VirtualHardwareSection> - <Info>Virtual hardware requirements</Info> - <System> - <vssd:ElementName>Virtual Hardware Family</vssd:ElementName> - <vssd:InstanceID>0</vssd:InstanceID> - <vssd:VirtualSystemType>vmx-13</vssd:VirtualSystemType> - </System> - <Item> - <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits> - <rasd:Description>Number of Virtual CPUs</rasd:Description> - <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName> - <rasd:InstanceID>1</rasd:InstanceID> - <rasd:ResourceType>3</rasd:ResourceType> - <rasd:VirtualQuantity>1</rasd:VirtualQuantity> - <vmw:CoresPerSocket ovf:required="false">1</vmw:CoresPerSocket> - </Item> - <Item> - <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits> - <rasd:Description>Memory Size</rasd:Description> - <rasd:ElementName>40MB of memory</rasd:ElementName> - <rasd:InstanceID>2</rasd:InstanceID> - <rasd:ResourceType>4</rasd:ResourceType> - <rasd:VirtualQuantity>40</rasd:VirtualQuantity> - </Item> - <Item> - <rasd:Address>0</rasd:Address> - <rasd:Description>SCSI Controller</rasd:Description> - <rasd:ElementName>SCSI Controller 1</rasd:ElementName> - <rasd:InstanceID>3</rasd:InstanceID> - <rasd:ResourceSubType>lsilogicsas</rasd:ResourceSubType> - <rasd:ResourceType>6</rasd:ResourceType> - </Item> - <Item> - <rasd:Address>0</rasd:Address> - <rasd:Description>SATA Controller</rasd:Description> - <rasd:ElementName>SATA Controller 1</rasd:ElementName> - <rasd:InstanceID>4</rasd:InstanceID> - <rasd:ResourceSubType>vmware.sata.ahci</rasd:ResourceSubType> - <rasd:ResourceType>20</rasd:ResourceType> - </Item> - <Item> - <rasd:AddressOnParent>0</rasd:AddressOnParent> - <rasd:ElementName>Hard Disk 1</rasd:ElementName> - <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource> - <rasd:InstanceID>5</rasd:InstanceID> - <rasd:Parent>3</rasd:Parent> - <rasd:ResourceType>17</rasd:ResourceType> - </Item> - <Item> - <rasd:AddressOnParent>0</rasd:AddressOnParent> - <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation> - <rasd:ElementName>CD/DVD Drive 1</rasd:ElementName> - <rasd:InstanceID>6</rasd:InstanceID> - <rasd:Parent>4</rasd:Parent> - <rasd:ResourceSubType>vmware.cdrom.remotepassthrough</rasd:ResourceSubType> - <rasd:ResourceType>15</rasd:ResourceType> - </Item> - <Item> - <rasd:AddressOnParent>0</rasd:AddressOnParent> - <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation> - <rasd:Description>Floppy Drive</rasd:Description> - <rasd:ElementName>Floppy Drive 1</rasd:ElementName> - <rasd:InstanceID>7</rasd:InstanceID> - <rasd:ResourceSubType>vmware.floppy.remotedevice</rasd:ResourceSubType> - <rasd:ResourceType>14</rasd:ResourceType> - </Item> - <Item> - <rasd:AddressOnParent>0</rasd:AddressOnParent> - <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation> - <rasd:Connection>VM Network</rasd:Connection> - <rasd:ElementName>Network adapter 1</rasd:ElementName> - <rasd:InstanceID>8</rasd:InstanceID> - <rasd:ResourceSubType>E1000</rasd:ResourceSubType> - <rasd:ResourceType>10</rasd:ResourceType> - <vmw:Config ovf:required="false" vmw:key="wakeOnLanEnabled" vmw:value="true"/> - <vmw:Config ovf:required="false" vmw:key="connectable.allowGuestControl" vmw:value="true"/> - </Item> - <Item ovf:required="false"> - <rasd:ElementName>Video card</rasd:ElementName> - <rasd:InstanceID>9</rasd:InstanceID> - <rasd:ResourceType>24</rasd:ResourceType> - <vmw:Config ovf:required="false" vmw:key="enable3DSupport" vmw:value="false"/> - <vmw:Config ovf:required="false" vmw:key="useAutoDetect" vmw:value="false"/> - <vmw:Config ovf:required="false" vmw:key="numDisplays" vmw:value="1"/> - <vmw:Config ovf:required="false" vmw:key="graphicsMemorySizeInKB" vmw:value="262144"/> - <vmw:Config ovf:required="false" vmw:key="videoRamSizeInKB" vmw:value="8192"/> - <vmw:Config ovf:required="false" vmw:key="enableMPTSupport" vmw:value="false"/> - <vmw:Config ovf:required="false" vmw:key="use3dRenderer" vmw:value="automatic"/> - </Item> - <vmw:Config ovf:required="false" vmw:key="nestedHVEnabled" vmw:value="false"/> - </VirtualHardwareSection> - </VirtualSystem> -</Envelope> \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' "old/govc-0.55.0/ovf/fixtures/external/standard_ovas/non-ascii/highascii/high_ascii_characters/\303\271\303\240\303\247\303\251\303\250.ovf" "new/govc-0.55.1/ovf/fixtures/external/standard_ovas/non-ascii/highascii/high_ascii_characters/\303\271\303\240\303\247\303\251\303\250.ovf" --- "old/govc-0.55.0/ovf/fixtures/external/standard_ovas/non-ascii/highascii/high_ascii_characters/\303\271\303\240\303\247\303\251\303\250.ovf" 2026-06-26 18:42:07.000000000 +0200 +++ "new/govc-0.55.1/ovf/fixtures/external/standard_ovas/non-ascii/highascii/high_ascii_characters/\303\271\303\240\303\247\303\251\303\250.ovf" 1970-01-01 01:00:00.000000000 +0100 @@ -1,114 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<Envelope xmlns="http://schemas.dmtf.org/ovf/envelope/1" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"> - <References> - <File ovf:id="file1" ovf:href="ùàçéè-1.vmdk"/> - </References> - <DiskSection> - <Info>List of the virtual disks</Info> - <Disk ovf:capacityAllocationUnits="byte" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized" ovf:diskId="vmdisk1" ovf:capacity="41943040" ovf:fileRef="file1"/> - </DiskSection> - <NetworkSection> - <Info>The list of logical networks</Info> - <Network ovf:name="VM Network"> - <Description>The VM Network network</Description> - </Network> - </NetworkSection> - <VirtualSystem ovf:id="ùàçéè"> - <Info>A Virtual system</Info> - <Name>ùàçéè</Name> - <OperatingSystemSection ovf:id="103" vmw:osType="windows7Server64Guest"> - <Info>The operating system installed</Info> - <Description>Microsoft Windows Server 2008 R2 (64-bit)</Description> - </OperatingSystemSection> - <VirtualHardwareSection> - <Info>Virtual hardware requirements</Info> - <System> - <vssd:ElementName>Virtual Hardware Family</vssd:ElementName> - <vssd:InstanceID>0</vssd:InstanceID> - <vssd:VirtualSystemType>vmx-13</vssd:VirtualSystemType> - </System> - <Item> - <rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits> - <rasd:Description>Number of Virtual CPUs</rasd:Description> - <rasd:ElementName>1 virtual CPU(s)</rasd:ElementName> - <rasd:InstanceID>1</rasd:InstanceID> - <rasd:ResourceType>3</rasd:ResourceType> - <rasd:VirtualQuantity>1</rasd:VirtualQuantity> - <vmw:CoresPerSocket ovf:required="false">1</vmw:CoresPerSocket> - </Item> - <Item> - <rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits> - <rasd:Description>Memory Size</rasd:Description> - <rasd:ElementName>40MB of memory</rasd:ElementName> - <rasd:InstanceID>2</rasd:InstanceID> - <rasd:ResourceType>4</rasd:ResourceType> - <rasd:VirtualQuantity>40</rasd:VirtualQuantity> - </Item> - <Item> - <rasd:Address>0</rasd:Address> - <rasd:Description>SCSI Controller</rasd:Description> - <rasd:ElementName>SCSI Controller 1</rasd:ElementName> - <rasd:InstanceID>3</rasd:InstanceID> - <rasd:ResourceSubType>lsilogicsas</rasd:ResourceSubType> - <rasd:ResourceType>6</rasd:ResourceType> - </Item> - <Item> - <rasd:Address>0</rasd:Address> - <rasd:Description>SATA Controller</rasd:Description> - <rasd:ElementName>SATA Controller 1</rasd:ElementName> - <rasd:InstanceID>4</rasd:InstanceID> - <rasd:ResourceSubType>vmware.sata.ahci</rasd:ResourceSubType> - <rasd:ResourceType>20</rasd:ResourceType> - </Item> - <Item> - <rasd:AddressOnParent>0</rasd:AddressOnParent> - <rasd:ElementName>Hard Disk 1</rasd:ElementName> - <rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource> - <rasd:InstanceID>5</rasd:InstanceID> - <rasd:Parent>3</rasd:Parent> - <rasd:ResourceType>17</rasd:ResourceType> - </Item> - <Item> - <rasd:AddressOnParent>0</rasd:AddressOnParent> - <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation> - <rasd:ElementName>CD/DVD Drive 1</rasd:ElementName> - <rasd:InstanceID>6</rasd:InstanceID> - <rasd:Parent>4</rasd:Parent> - <rasd:ResourceSubType>vmware.cdrom.remotepassthrough</rasd:ResourceSubType> - <rasd:ResourceType>15</rasd:ResourceType> - </Item> - <Item> - <rasd:AddressOnParent>0</rasd:AddressOnParent> - <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation> - <rasd:Description>Floppy Drive</rasd:Description> - <rasd:ElementName>Floppy Drive 1</rasd:ElementName> - <rasd:InstanceID>7</rasd:InstanceID> - <rasd:ResourceSubType>vmware.floppy.remotedevice</rasd:ResourceSubType> - <rasd:ResourceType>14</rasd:ResourceType> - </Item> - <Item> - <rasd:AddressOnParent>0</rasd:AddressOnParent> - <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation> - <rasd:Connection>VM Network</rasd:Connection> - <rasd:ElementName>Network adapter 1</rasd:ElementName> - <rasd:InstanceID>8</rasd:InstanceID> - <rasd:ResourceSubType>E1000</rasd:ResourceSubType> - <rasd:ResourceType>10</rasd:ResourceType> - <vmw:Config ovf:required="false" vmw:key="wakeOnLanEnabled" vmw:value="true"/> - <vmw:Config ovf:required="false" vmw:key="connectable.allowGuestControl" vmw:value="true"/> - </Item> - <Item ovf:required="false"> - <rasd:ElementName>Video card</rasd:ElementName> - <rasd:InstanceID>9</rasd:InstanceID> - <rasd:ResourceType>24</rasd:ResourceType> - <vmw:Config ovf:required="false" vmw:key="graphicsMemorySizeInKB" vmw:value="262144"/> - <vmw:Config ovf:required="false" vmw:key="useAutoDetect" vmw:value="false"/> - <vmw:Config ovf:required="false" vmw:key="use3dRenderer" vmw:value="automatic"/> - <vmw:Config ovf:required="false" vmw:key="enable3DSupport" vmw:value="false"/> - <vmw:Config ovf:required="false" vmw:key="videoRamSizeInKB" vmw:value="8192"/> - <vmw:Config ovf:required="false" vmw:key="numDisplays" vmw:value="1"/> - </Item> - <vmw:Config ovf:required="false" vmw:key="nestedHVEnabled" vmw:value="false"/> - </VirtualHardwareSection> - </VirtualSystem> -</Envelope> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/govc-0.55.0/vapi/esx/settings/clusters/vms/simulator/simulator.go new/govc-0.55.1/vapi/esx/settings/clusters/vms/simulator/simulator.go --- old/govc-0.55.0/vapi/esx/settings/clusters/vms/simulator/simulator.go 1970-01-01 01:00:00.000000000 +0100 +++ new/govc-0.55.1/vapi/esx/settings/clusters/vms/simulator/simulator.go 2026-07-03 16:30:07.000000000 +0200 @@ -0,0 +1,255 @@ +// © Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// SPDX-License-Identifier: Apache-2.0 + +package simulator + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + + "github.com/vmware/govmomi/simulator" + "github.com/vmware/govmomi/vapi/esx/settings/clusters/vms" + vapi "github.com/vmware/govmomi/vapi/simulator" +) + +func init() { + simulator.RegisterEndpoint(func(s *simulator.Service, r *simulator.Registry) { + New(s.Listen).Register(s, r) + }) +} + +// Handler implements the EAM vms API simulator. +type Handler struct { + URL *url.URL + Solutions map[string]map[string]vms.SolutionInfo // clusterID → solutionID → info + Hooks map[string]map[string][]vms.LifecycleHookInfo // clusterID → solutionID → hooks + Tasks map[string]json.RawMessage // taskID → task JSON + taskCount int +} + +// New creates a Handler instance. +func New(u *url.URL) *Handler { + return &Handler{ + URL: u, + Solutions: make(map[string]map[string]vms.SolutionInfo), + Hooks: make(map[string]map[string][]vms.LifecycleHookInfo), + Tasks: make(map[string]json.RawMessage), + } +} + +// Register adds all VMS API paths to the simulator's HTTP mux. +func (h *Handler) Register(s *simulator.Service, r *simulator.Registry) { + if r.IsVPX() { + s.HandleFunc("/api/esx/settings/clusters/{cluster}/vms/solutions", h.solutions) + s.HandleFunc("/api/esx/settings/clusters/{cluster}/vms/solutions/{solution}", h.solution) + s.HandleFunc("/api/esx/settings/clusters/{cluster}/vms/lifecycle-hooks", h.hooksCollection) + s.HandleFunc("/api/esx/settings/clusters/{cluster}/vms/lifecycle-hooks/{solution}", h.hooksSolution) + s.HandleFunc("/api/esx/settings/clusters/{cluster}/vms/transition/{solution}", h.transition) + s.HandleFunc("/api/cis/tasks/{task}", h.taskGet) + } +} + +// newTask stores a SUCCEEDED task and returns its ID. +func (h *Handler) newTask() string { + h.taskCount++ + id := fmt.Sprintf("vms-task-%d", h.taskCount) + h.Tasks[id] = json.RawMessage(`{"status":"SUCCEEDED","result":null}`) + return id +} + +// clusterSolutions returns (and lazily initialises) the solution map for a cluster. +func (h *Handler) clusterSolutions(cluster string) map[string]vms.SolutionInfo { + if h.Solutions[cluster] == nil { + h.Solutions[cluster] = make(map[string]vms.SolutionInfo) + } + return h.Solutions[cluster] +} + +// solutions handles the solutions collection endpoint. +// +// GET /api/esx/settings/clusters/{cluster}/vms/solutions +// POST /api/esx/settings/clusters/{cluster}/vms/solutions?action=apply&vmw-task=true +// POST /api/esx/settings/clusters/{cluster}/vms/solutions?action=check-compliance&vmw-task=true +func (h *Handler) solutions(w http.ResponseWriter, r *http.Request) { + cluster := r.PathValue("cluster") + action := r.URL.Query().Get("action") + + switch r.Method { + case http.MethodGet: + vapi.StatusOK(w, vms.ListResult{Solutions: h.clusterSolutions(cluster)}) + + case http.MethodPost: + switch action { + case "apply": + var spec vms.ApplySpec + if vapi.Decode(r, w, &spec) { + vapi.StatusOK(w, h.newTask()) + } + case "check-compliance": + var spec vms.CheckComplianceFilterSpec + if vapi.Decode(r, w, &spec) { + vapi.StatusOK(w, h.newTask()) + } + default: + vapi.ApiErrorInvalidArgument(w) + } + + default: + w.WriteHeader(http.StatusMethodNotAllowed) + } +} + +// solution handles the per-solution endpoint. +// +// GET /api/esx/settings/clusters/{cluster}/vms/solutions/{solution} +// PUT /api/esx/settings/clusters/{cluster}/vms/solutions/{solution}?vmw-task=true +// DELETE /api/esx/settings/clusters/{cluster}/vms/solutions/{solution}?vmw-task=true +func (h *Handler) solution(w http.ResponseWriter, r *http.Request) { + cluster := r.PathValue("cluster") + solution := r.PathValue("solution") + sols := h.clusterSolutions(cluster) + + switch r.Method { + case http.MethodGet: + info, ok := sols[solution] + if !ok { + vapi.ApiErrorNotFound(w) + return + } + vapi.StatusOK(w, info) + + case http.MethodPut: + var spec vms.SolutionSpec + if !vapi.Decode(r, w, &spec) { + return + } + // Round-trip through JSON to populate the overlapping SolutionInfo fields. + data, _ := json.Marshal(spec) + var info vms.SolutionInfo + _ = json.Unmarshal(data, &info) + sols[solution] = info + vapi.StatusOK(w, h.newTask()) + + case http.MethodDelete: + if _, ok := sols[solution]; !ok { + vapi.ApiErrorNotFound(w) + return + } + delete(sols, solution) + vapi.StatusOK(w, h.newTask()) + + default: + w.WriteHeader(http.StatusMethodNotAllowed) + } +} + +// hooksCollection handles POST actions on the lifecycle-hooks collection. +// +// POST /api/esx/settings/clusters/{cluster}/vms/lifecycle-hooks?action=mark-as-processed +// POST /api/esx/settings/clusters/{cluster}/vms/lifecycle-hooks?action=process-dynamic-update +func (h *Handler) hooksCollection(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + action := r.URL.Query().Get("action") + switch action { + case "mark-as-processed": + var spec vms.ProcessedHookSpec + if vapi.Decode(r, w, &spec) { + vapi.StatusOK(w, nil) + } + case "process-dynamic-update": + var spec vms.DynamicUpdateSpec + if vapi.Decode(r, w, &spec) { + vapi.StatusOK(w, nil) + } + default: + vapi.ApiErrorInvalidArgument(w) + } +} + +// hooksSolution handles GET on a per-solution hooks endpoint. +// +// GET /api/esx/settings/clusters/{cluster}/vms/lifecycle-hooks/{solution} +func (h *Handler) hooksSolution(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + cluster := r.PathValue("cluster") + solution := r.PathValue("solution") + + var hooks []vms.LifecycleHookInfo + if clusterHooks, ok := h.Hooks[cluster]; ok { + hooks = clusterHooks[solution] + } + if hooks == nil { + hooks = []vms.LifecycleHookInfo{} + } + vapi.StatusOK(w, vms.HookListResult{Hooks: hooks}) +} + +// transition handles transition actions for a solution. +// +// POST /api/esx/settings/clusters/{cluster}/vms/transition/{solution}?action=enable&vmw-task=true +// POST /api/esx/settings/clusters/{cluster}/vms/transition/{solution}?action=multi-source-enable&vmw-task=true +// POST /api/esx/settings/clusters/{cluster}/vms/transition/{solution}?action=transition&vmw-task=true +// POST /api/esx/settings/clusters/{cluster}/vms/transition/{solution}?action=delete-solution-only +func (h *Handler) transition(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + cluster := r.PathValue("cluster") + solution := r.PathValue("solution") + action := r.URL.Query().Get("action") + + switch action { + case "enable": + var spec vms.EnableSpec + if vapi.Decode(r, w, &spec) { + vapi.StatusOK(w, h.newTask()) + } + case "multi-source-enable": + var spec vms.MultiSourceEnableSpec + if vapi.Decode(r, w, &spec) { + vapi.StatusOK(w, h.newTask()) + } + case "transition": + var spec vms.TransitionSpec + if vapi.Decode(r, w, &spec) { + vapi.StatusOK(w, h.newTask()) + } + case "delete-solution-only": + sols := h.clusterSolutions(cluster) + if _, ok := sols[solution]; !ok { + vapi.ApiErrorNotFound(w) + return + } + delete(sols, solution) + vapi.StatusOK(w) + default: + vapi.ApiErrorInvalidArgument(w) + } +} + +// taskGet handles task status polls from the task manager. +// +// GET /api/cis/tasks/{task} +func (h *Handler) taskGet(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + result, ok := h.Tasks[r.PathValue("task")] + if !ok { + vapi.ApiErrorNotFound(w) + return + } + vapi.StatusOK(w, result) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/govc-0.55.0/vapi/esx/settings/clusters/vms/simulator/simulator_test.go new/govc-0.55.1/vapi/esx/settings/clusters/vms/simulator/simulator_test.go --- old/govc-0.55.0/vapi/esx/settings/clusters/vms/simulator/simulator_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/govc-0.55.1/vapi/esx/settings/clusters/vms/simulator/simulator_test.go 2026-07-03 16:30:07.000000000 +0200 @@ -0,0 +1,231 @@ +// © Broadcom. All Rights Reserved. +// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. +// SPDX-License-Identifier: Apache-2.0 + +package simulator + +import ( + "context" + "testing" + + "github.com/vmware/govmomi/simulator" + "github.com/vmware/govmomi/vapi/esx/settings/clusters/vms" + "github.com/vmware/govmomi/vapi/rest" + _ "github.com/vmware/govmomi/vapi/simulator" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/types" +) + +// testSetup returns a logged-in vms.Manager and a cluster MOR from the simulator. +func testSetup(ctx context.Context, vc *vim25.Client, t *testing.T) (*vms.Manager, types.ManagedObjectReference) { + t.Helper() + + c := rest.NewClient(vc) + if err := c.Login(ctx, simulator.DefaultLogin); err != nil { + t.Fatal(err) + } + t.Cleanup(func() { _ = c.Logout(ctx) }) + + m := &vms.Manager{Client: c} + + ccr := simulator.Map(ctx).Any("ClusterComputeResource") + if ccr == nil { + t.Fatal("no ClusterComputeResource found in simulator") + } + return m, ccr.Reference() +} + +// minimalSpec returns a SolutionSpec with the minimum fields populated. +func minimalSpec(name string) *vms.SolutionSpec { + return &vms.SolutionSpec{ + DeploymentType: vms.EveryHostPinned, + DisplayName: name, + DisplayVersion: "1.0.0", + VmNameTemplate: vms.VmNameTemplate{Prefix: name + "-vm", Suffix: vms.Uuid}, + VmCloneConfig: vms.NoClones, + VmStoragePolicy: vms.Default, + VmDiskType: vms.DiskTypeDefault, + RedeploymentPolicy: vms.ReCreate, + OvfResource: vms.OvfResource{LocationType: vms.RemoteFile}, + } +} + +// TestSetGetDelete exercises the basic CRUD lifecycle via task-based operations. +func TestSetGetDelete(t *testing.T) { + simulator.Test(func(ctx context.Context, vc *vim25.Client) { + m, cluster := testSetup(ctx, vc, t) + + const id = "sol-a" + spec := minimalSpec(id) + + if err := m.Set(ctx, cluster, id, spec); err != nil { + t.Fatalf("Set: %v", err) + } + + info, err := m.Get(ctx, cluster, id) + if err != nil { + t.Fatalf("Get: %v", err) + } + if info.DisplayName != spec.DisplayName { + t.Errorf("DisplayName: got %q, want %q", info.DisplayName, spec.DisplayName) + } + + if err := m.Delete(ctx, cluster, id); err != nil { + t.Fatalf("Delete: %v", err) + } + + if _, err := m.Get(ctx, cluster, id); err == nil { + t.Fatal("Get after Delete: expected error, got nil") + } + }) +} + +// TestList verifies that List returns an accurate count of known solutions. +func TestList(t *testing.T) { + simulator.Test(func(ctx context.Context, vc *vim25.Client) { + m, cluster := testSetup(ctx, vc, t) + + result, err := m.List(ctx, cluster) + if err != nil { + t.Fatalf("List (empty): %v", err) + } + if len(result.Solutions) != 0 { + t.Fatalf("expected 0 solutions initially, got %d", len(result.Solutions)) + } + + for _, id := range []string{"sol-1", "sol-2"} { + if err := m.Set(ctx, cluster, id, minimalSpec(id)); err != nil { + t.Fatalf("Set %s: %v", id, err) + } + } + + result, err = m.List(ctx, cluster) + if err != nil { + t.Fatalf("List: %v", err) + } + if len(result.Solutions) != 2 { + t.Fatalf("expected 2 solutions, got %d", len(result.Solutions)) + } + }) +} + +// TestApply verifies that Apply returns a task ID and the task completes. +func TestApply(t *testing.T) { + simulator.Test(func(ctx context.Context, vc *vim25.Client) { + m, cluster := testSetup(ctx, vc, t) + + taskID, err := m.Apply(ctx, cluster, &vms.ApplySpec{}) + if err != nil { + t.Fatalf("Apply: %v", err) + } + if taskID == "" { + t.Fatal("Apply: empty task ID") + } + if _, err := m.ApplyWaitForCompletion(ctx, taskID); err != nil { + t.Fatalf("ApplyWaitForCompletion: %v", err) + } + }) +} + +// TestCheckCompliance verifies that CheckCompliance completes without error. +func TestCheckCompliance(t *testing.T) { + simulator.Test(func(ctx context.Context, vc *vim25.Client) { + m, cluster := testSetup(ctx, vc, t) + + if _, err := m.CheckCompliance(ctx, cluster, &vms.CheckComplianceFilterSpec{}); err != nil { + t.Fatalf("CheckCompliance: %v", err) + } + }) +} + +// TestListHooks verifies that ListHooks returns a non-nil hooks slice. +func TestListHooks(t *testing.T) { + simulator.Test(func(ctx context.Context, vc *vim25.Client) { + m, cluster := testSetup(ctx, vc, t) + + result, err := m.ListHooks(ctx, cluster, "any-solution") + if err != nil { + t.Fatalf("ListHooks: %v", err) + } + if result.Hooks == nil { + t.Fatal("ListHooks: expected non-nil hooks slice") + } + }) +} + +// TestMarkAsProcessed verifies that MarkAsProcessed succeeds. +func TestMarkAsProcessed(t *testing.T) { + simulator.Test(func(ctx context.Context, vc *vim25.Client) { + m, cluster := testSetup(ctx, vc, t) + + spec := &vms.ProcessedHookSpec{ + Vm: "vm-1", + LifecycleState: vms.PostPowerOn, + ProcessedSuccessfully: true, + } + if _, err := m.MarkAsProcessed(ctx, cluster, spec); err != nil { + t.Fatalf("MarkAsProcessed: %v", err) + } + }) +} + +// TestProcessDynamicUpdate verifies that ProcessDynamicUpdate succeeds. +func TestProcessDynamicUpdate(t *testing.T) { + simulator.Test(func(ctx context.Context, vc *vim25.Client) { + m, cluster := testSetup(ctx, vc, t) + + spec := &vms.DynamicUpdateSpec{ + Vm: "vm-1", + Solution: "sol-a", + LifecycleState: vms.PostPowerOn, + } + if err := m.ProcessDynamicUpdate(ctx, cluster, spec); err != nil { + t.Fatalf("ProcessDynamicUpdate: %v", err) + } + }) +} + +// TestEnable verifies that Enable (transition from EAM-managed to vLCM) succeeds. +func TestEnable(t *testing.T) { + simulator.Test(func(ctx context.Context, vc *vim25.Client) { + m, cluster := testSetup(ctx, vc, t) + + spec := &vms.EnableSpec{ + EamAgencyID: "agency-1", + Solution: minimalSpec("sol-enable"), + } + if err := m.Enable(ctx, cluster, "sol-enable", spec); err != nil { + t.Fatalf("Enable: %v", err) + } + }) +} + +// TestMultiSourceEnable verifies that MultiSourceEnable succeeds. +func TestMultiSourceEnable(t *testing.T) { + simulator.Test(func(ctx context.Context, vc *vim25.Client) { + m, cluster := testSetup(ctx, vc, t) + + spec := &vms.MultiSourceEnableSpec{ + EamAgencyIDs: []string{"agency-1", "agency-2"}, + Solution: minimalSpec("sol-multi"), + } + if err := m.MultiSourceEnable(ctx, cluster, "sol-multi", spec); err != nil { + t.Fatalf("MultiSourceEnable: %v", err) + } + }) +} + +// TestTransition verifies that Transition (move solution to another cluster) succeeds. +func TestTransition(t *testing.T) { + simulator.Test(func(ctx context.Context, vc *vim25.Client) { + m, cluster := testSetup(ctx, vc, t) + + spec := &vms.TransitionSpec{ + SourceCluster: "domain-c8", + Solution: minimalSpec("sol-transition"), + } + if err := m.Transition(ctx, cluster, "sol-transition", spec); err != nil { + t.Fatalf("Transition: %v", err) + } + }) +} ++++++ govc.obsinfo ++++++ --- /var/tmp/diff_new_pack.9YSp1j/_old 2026-07-06 12:36:36.948338790 +0200 +++ /var/tmp/diff_new_pack.9YSp1j/_new 2026-07-06 12:36:36.992340316 +0200 @@ -1,5 +1,5 @@ name: govc -version: 0.55.0 -mtime: 1782492127 -commit: cb2d98b50e63532939817ffb86ca87fe748ff3f0 +version: 0.55.1 +mtime: 1783089007 +commit: 1e372f1c01953d43fe4d573eb60f33f7e3d3aa41 ++++++ vendor.tar.gz ++++++
