Skip to content

Commit 3b24a71

Browse files
authored
Merge pull request #3815 from Pradeepbr/topic/pr026965/AddCandidateNetworks
api: Update folder.PlaceVMsXCluster to filter clusters based on candidate networks availability
2 parents 91f991f + d25f318 commit 3b24a71

File tree

4 files changed

+176
-17
lines changed

4 files changed

+176
-17
lines changed

cli/folder/place.go

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,13 @@ type place struct {
8686
*flags.VirtualMachineFlag
8787
*flags.OutputFlag
8888

89-
pool flags.StringList
90-
Type typeFlag
89+
pool flags.StringList
90+
Type typeFlag
91+
CandidateNetworks flags.StringList
9192
}
9293

9394
func init() {
94-
cli.Register("folder.place", &place{}, true)
95+
cli.Register("folder.place", &place{}, false)
9596
}
9697

9798
func (cmd *place) Register(ctx context.Context, f *flag.FlagSet) {
@@ -106,6 +107,7 @@ func (cmd *place) Register(ctx context.Context, f *flag.FlagSet) {
106107

107108
f.Var(&cmd.pool, "pool", "Resource Pools to use for placement.")
108109
f.Var(&cmd.Type, "type", fmt.Sprintf("Placement type (%s)", strings.Join(allTypes, "|")))
110+
f.Var(&cmd.CandidateNetworks, "candidate-networks", "Candidate network names (repeat for multiple nics)")
109111
}
110112

111113
func (cmd *place) Usage() string {
@@ -116,7 +118,13 @@ func (cmd *place) Description() string {
116118
return `Get a placement recommendation for an existing VM
117119
118120
Examples:
119-
govc folder.place -rp $rp1Name -rp $rp2Name -rp $rp3Name-vm $vmName`
121+
govc folder.place -rp $rp1Name -rp $rp2Name -rp $rp3Name -vm $vmName -type relocate -candidate-networks "netA|netB" -candidate-networks "netC"
122+
Each use of the "-candidate-networks" flag corresponds to one NIC of the VM.
123+
Within the value of each flag, use "|" to specify multiple candidate networks for that NIC.
124+
For example:
125+
-candidate-networks "netA|netB" → NIC 0 can connect to either netA or netB.
126+
-candidate-networks "netC" → NIC 1 can connect only to netC.
127+
`
120128
}
121129

122130
func (cmd *place) Process(ctx context.Context) error {
@@ -136,13 +144,12 @@ func (cmd *place) Process(ctx context.Context) error {
136144
}
137145

138146
func (cmd *place) Run(ctx context.Context, f *flag.FlagSet) error {
139-
c, err := cmd.Client()
147+
client, err := cmd.Client()
140148
if err != nil {
141149
return err
142150
}
143-
144151
// Use latest version to pick up latest PlaceVmsXCluster API.
145-
err = c.UseServiceVersion()
152+
err = client.UseServiceVersion()
146153
if err != nil {
147154
return err
148155
}
@@ -175,9 +182,41 @@ func (cmd *place) Run(ctx context.Context, f *flag.FlagSet) error {
175182
default:
176183
return errors.New("please specify a valid type")
177184
}
185+
var candidateNetworks []types.PlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks
186+
if len(cmd.CandidateNetworks) > 0 {
187+
client, err := cmd.Client()
188+
if err != nil {
189+
return err
190+
}
191+
finder := find.NewFinder(client, false)
192+
193+
dc, err := cmd.Datacenter()
194+
if err != nil {
195+
return err
196+
}
197+
finder.SetDatacenter(dc)
198+
199+
for _, nic := range cmd.CandidateNetworks {
200+
// Each 'nic' string is like "netA|netB"
201+
netNames := strings.Split(nic, "|")
202+
var refs []types.ManagedObjectReference
203+
204+
for _, name := range netNames {
205+
fmt.Printf(">>> Looking up network: %q\n", name)
206+
netObj, err := finder.Network(ctx, name)
207+
if err != nil {
208+
return fmt.Errorf("network %q not found: %w", name, err)
209+
}
210+
refs = append(refs, netObj.Reference())
211+
}
212+
candidateNetworks = append(candidateNetworks, types.PlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks{
213+
Networks: refs,
214+
})
215+
}
216+
}
178217

179218
// PlaceVMsXCluster is only valid against the root folder.
180-
folder := object.NewRootFolder(c)
219+
folder := object.NewRootFolder(client)
181220

182221
refs := make([]types.ManagedObjectReference, 0, len(cmd.pool))
183222

@@ -191,9 +230,10 @@ func (cmd *place) Run(ctx context.Context, f *flag.FlagSet) error {
191230
}
192231

193232
vmPlacementSpecs := []types.PlaceVmsXClusterSpecVmPlacementSpec{{
194-
Vm: types.NewReference(vm.Reference()),
195-
ConfigSpec: types.VirtualMachineConfigSpec{},
196-
RelocateSpec: relocateSpec,
233+
Vm: types.NewReference(vm.Reference()),
234+
ConfigSpec: types.VirtualMachineConfigSpec{},
235+
RelocateSpec: relocateSpec,
236+
CandidateNetworks: candidateNetworks,
197237
}}
198238

199239
placementSpec := types.PlaceVmsXClusterSpec{

govc/USAGE.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ but appear via `govc $cmd -h`:
159159
- [firewall.ruleset.find](#firewallrulesetfind)
160160
- [folder.create](#foldercreate)
161161
- [folder.info](#folderinfo)
162+
- [folder.place](#folderplace)
162163
- [gpu.host.info](#gpuhostinfo)
163164
- [gpu.host.profile.ls](#gpuhostprofilels)
164165
- [gpu.vm.add](#gpuvmadd)
@@ -2754,6 +2755,29 @@ Usage: govc folder.info [OPTIONS] [PATH]...
27542755
Options:
27552756
```
27562757

2758+
## folder.place
2759+
2760+
```
2761+
Usage: govc folder.place [OPTIONS] PATH...
2762+
2763+
Get a placement recommendation for an existing VM
2764+
2765+
Examples:
2766+
govc folder.place -rp $rp1Name -rp $rp2Name -rp $rp3Name -vm $vmName -type relocate -candidate-networks "netA|netB" -candidate-networks "netC"
2767+
Each use of the "-candidate-networks" flag corresponds to one NIC of the VM.
2768+
Within the value of each flag, use "|" to specify multiple candidate networks for that NIC.
2769+
For example:
2770+
-candidate-networks "netA|netB" → NIC 0 can connect to either netA or netB.
2771+
-candidate-networks "netC" → NIC 1 can connect only to netC.
2772+
2773+
2774+
Options:
2775+
-candidate-networks=[] Candidate network names (repeat for multiple nics)
2776+
-pool=[] Resource Pools to use for placement.
2777+
-type= Placement type (createAndPowerOn|relocate|reconfigure)
2778+
-vm= Virtual machine [GOVC_VM]
2779+
```
2780+
27572781
## gpu.host.info
27582782

27592783
```

simulator/folder_test.go

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,68 @@ func TestPlaceVmsXClusterCreateAndPowerOn(t *testing.T) {
632632

633633
Test(func(ctx context.Context, c *vim25.Client) {
634634
finder := find.NewFinder(c, false)
635+
spec := types.PlaceVmsXClusterSpec{}
636+
637+
pools, err := finder.ResourcePoolList(ctx, "/DC0/host/DC0_C*/*")
638+
if err != nil {
639+
t.Fatal(err)
640+
}
641+
642+
for _, pool := range pools {
643+
spec.ResourcePools = append(spec.ResourcePools, pool.Reference())
644+
}
645+
646+
spec.VmPlacementSpecs = []types.PlaceVmsXClusterSpecVmPlacementSpec{{
647+
ConfigSpec: types.VirtualMachineConfigSpec{
648+
Name: "test-vm",
649+
},
650+
}}
651+
652+
folder := object.NewRootFolder(c)
653+
res, err := folder.PlaceVmsXCluster(ctx, spec)
654+
if err != nil {
655+
t.Fatal(err)
656+
}
657+
658+
if len(res.PlacementInfos) != len(spec.VmPlacementSpecs) {
659+
t.Errorf("%d PlacementInfos vs %d VmPlacementSpecs", len(res.PlacementInfos), len(spec.VmPlacementSpecs))
660+
}
661+
}, vpx)
662+
}
663+
664+
func TestPlaceVmsXClusterCreateAndPowerOnWithCandidateNetworks(t *testing.T) {
665+
vpx := VPX()
666+
vpx.Cluster = 3
635667

668+
Test(func(ctx context.Context, c *vim25.Client) {
669+
finder := find.NewFinder(c, false)
670+
datacenter, err := finder.DefaultDatacenter(ctx)
671+
if err != nil {
672+
t.Fatalf("failed to get default datacenter: %v", err)
673+
}
674+
finder.SetDatacenter(datacenter)
675+
676+
netA, err := finder.Network(ctx, "VM Network")
677+
if err != nil {
678+
t.Fatalf("unexpected error while getting network reference: %v", err)
679+
}
680+
netB, err := finder.Network(ctx, "DC0_DVPG0")
681+
if err != nil {
682+
t.Fatalf("unexpected error while getting network reference: %v", err)
683+
}
684+
685+
candidateNetworks := []types.PlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks{
686+
{
687+
Networks: []types.ManagedObjectReference{
688+
netA.Reference(), netB.Reference(),
689+
},
690+
},
691+
{
692+
Networks: []types.ManagedObjectReference{
693+
netA.Reference(),
694+
},
695+
},
696+
}
636697
spec := types.PlaceVmsXClusterSpec{}
637698

638699
pools, err := finder.ResourcePoolList(ctx, "/DC0/host/DC0_C*/*")
@@ -648,6 +709,7 @@ func TestPlaceVmsXClusterCreateAndPowerOn(t *testing.T) {
648709
ConfigSpec: types.VirtualMachineConfigSpec{
649710
Name: "test-vm",
650711
},
712+
CandidateNetworks: candidateNetworks,
651713
}}
652714

653715
folder := object.NewRootFolder(c)
@@ -686,6 +748,19 @@ func TestPlaceVmsXClusterRelocate(t *testing.T) {
686748

687749
vmMoRef := Map(ctx).Any("VirtualMachine").(*VirtualMachine).Reference()
688750

751+
netA, err := finder.Network(context.Background(), "VM Network")
752+
if err != nil {
753+
t.Fatalf("unexpected error while getting network reference: %v", err)
754+
}
755+
netB, err := finder.Network(context.Background(), "DC0_DVPG0")
756+
if err != nil {
757+
t.Fatalf("unexpected error while getting network reference: %v", err)
758+
}
759+
760+
candidateNetworks := []types.PlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks{
761+
{Networks: []types.ManagedObjectReference{netA.Reference(), netB.Reference()}}, // NIC 0
762+
{Networks: []types.ManagedObjectReference{netA.Reference()}}, // NIC 1
763+
}
689764
cfgSpec := types.VirtualMachineConfigSpec{}
690765

691766
tests := []struct {
@@ -754,9 +829,10 @@ func TestPlaceVmsXClusterRelocate(t *testing.T) {
754829
}
755830

756831
placeVmsXClusterSpec.VmPlacementSpecs = []types.PlaceVmsXClusterSpecVmPlacementSpec{{
757-
ConfigSpec: test.configSpec,
758-
Vm: test.vmMoRef,
759-
RelocateSpec: test.relocateSpec,
832+
ConfigSpec: test.configSpec,
833+
Vm: test.vmMoRef,
834+
RelocateSpec: test.relocateSpec,
835+
CandidateNetworks: candidateNetworks,
760836
}}
761837

762838
folder := object.NewRootFolder(c)

vim25/types/unreleased.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ func init() {
3030
t["ArrayOfPlaceVmsXClusterSpecVmPlacementSpec"] = reflect.TypeOf((*ArrayOfPlaceVmsXClusterSpecVmPlacementSpec)(nil)).Elem()
3131
}
3232

33+
type ArrayOfPlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks struct {
34+
PlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks []PlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks `xml:"PlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks,omitempty"`
35+
}
36+
37+
func init() {
38+
t["ArrayOfPlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks"] = reflect.TypeOf((*ArrayOfPlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks)(nil)).Elem()
39+
}
40+
3341
type PlaceVmsXCluster PlaceVmsXClusterRequestType
3442

3543
func init() {
@@ -102,15 +110,26 @@ func init() {
102110
type PlaceVmsXClusterSpecVmPlacementSpec struct {
103111
DynamicData
104112

105-
Vm *ManagedObjectReference `xml:"vm,omitempty"`
106-
ConfigSpec VirtualMachineConfigSpec `xml:"configSpec"`
107-
RelocateSpec *VirtualMachineRelocateSpec `xml:"relocateSpec,omitempty"`
113+
Vm *ManagedObjectReference `xml:"vm,omitempty"`
114+
ConfigSpec VirtualMachineConfigSpec `xml:"configSpec"`
115+
RelocateSpec *VirtualMachineRelocateSpec `xml:"relocateSpec,omitempty"`
116+
CandidateNetworks []PlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks `xml:"candidateNetworks,omitempty"`
108117
}
109118

110119
func init() {
111120
t["PlaceVmsXClusterSpecVmPlacementSpec"] = reflect.TypeOf((*PlaceVmsXClusterSpecVmPlacementSpec)(nil)).Elem()
112121
}
113122

123+
type PlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks struct {
124+
DynamicData
125+
126+
Networks []ManagedObjectReference `xml:"networks,omitempty"`
127+
}
128+
129+
func init() {
130+
t["PlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks"] = reflect.TypeOf((*PlaceVmsXClusterSpecVmPlacementSpecCandidateNetworks)(nil)).Elem()
131+
}
132+
114133
const RecommendationReasonCodeXClusterPlacement = RecommendationReasonCode("xClusterPlacement")
115134

116135
type ClusterClusterReconfigurePlacementAction struct {

0 commit comments

Comments
 (0)