Skip to content

Commit 15b074b

Browse files
authored
Merge pull request #1219 from srm09/bug/fd-host-placement
Failure Domain: Fixes VM Placement on Hosts
2 parents 14477c0 + 91266f0 commit 15b074b

File tree

10 files changed

+123
-89
lines changed

10 files changed

+123
-89
lines changed

controllers/vspheredeploymentzone_controller_domain.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ func (r vsphereDeploymentZoneReconciler) createAndAttachMetadata(ctx *context.VS
176176
logger.V(4).Info("attaching tag to object")
177177
err := obj.AttachTag(ctx, failureDomain.Name)
178178
if err != nil {
179-
logger.V(4).Error(err, "failed to find object", obj)
179+
logger.V(4).Error(err, "failed to find object")
180180
errList = append(errList, errors.Wrapf(err, "failed to attach tag"))
181181
}
182182
}

controllers/vspheremachine_controller.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -335,11 +335,6 @@ func (r machineReconciler) reconcileNormal(ctx *context.MachineContext) (reconci
335335
return reconcile.Result{}, nil
336336
}
337337

338-
// Propagating the failure domain name to the VSphereMachine object
339-
if failureDomain := ctx.Machine.Spec.FailureDomain; failureDomain != nil {
340-
ctx.VSphereMachine.Spec.FailureDomain = failureDomain
341-
}
342-
343338
// TODO(akutz) Determine the version of vSphere.
344339
vm, err := r.reconcileNormalPre7(ctx, vsphereVM)
345340
if err != nil {
@@ -517,7 +512,7 @@ func (r machineReconciler) generateOverrideFunc(ctx *context.MachineContext) (fu
517512

518513
for index := range vsphereDeploymentZoneList.Items {
519514
zone := vsphereDeploymentZoneList.Items[index]
520-
if zone.Spec.FailureDomain == *ctx.Machine.Spec.FailureDomain {
515+
if zone.Spec.FailureDomain == *failureDomainName {
521516
overrideWithFailureDomainFunc = func(vm *infrav1.VSphereVM) {
522517
vm.Spec.Server = zone.Spec.Server
523518
vm.Spec.Datacenter = vsphereFailureDomain.Spec.Topology.Datacenter

controllers/vspherevm_controller_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
/*
2+
Copyright 2021 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
117
package controllers
218

319
import (

pkg/services/govmomi/cluster/cluster_suite_test.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
. "github.com/onsi/ginkgo"
2424
. "github.com/onsi/gomega"
2525

26-
"github.com/go-logr/logr"
2726
"github.com/vmware/govmomi/find"
2827
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/session"
2928
)
@@ -41,7 +40,3 @@ type testComputeClusterCtx struct {
4140
func (t testComputeClusterCtx) GetSession() *session.Session {
4241
return &session.Session{Finder: t.finder}
4342
}
44-
45-
func (t testComputeClusterCtx) GetLogger() logr.Logger {
46-
return logr.DiscardLogger{}
47-
}

pkg/services/govmomi/cluster/rule.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ func negate(input bool) bool {
5050
}
5151

5252
func VerifyAffinityRule(ctx computeClusterContext, clusterName, hostGroupName, vmGroupName string) (Rule, error) {
53-
logger := ctx.GetLogger().WithValues("compute cluster", clusterName, "VM Group", vmGroupName, "Host Group", hostGroupName)
54-
55-
logger.V(4).Info("listing affinity rules")
5653
rules, err := listRules(ctx, clusterName)
5754
if err != nil {
5855
return nil, errors.Wrapf(err, "unable to list rules for compute cluster %s", clusterName)
@@ -62,7 +59,6 @@ func VerifyAffinityRule(ctx computeClusterContext, clusterName, hostGroupName, v
6259
if vmHostRuleInfo, ok := rule.(*types.ClusterVmHostRuleInfo); ok {
6360
if vmHostRuleInfo.AffineHostGroupName == hostGroupName &&
6461
vmHostRuleInfo.VmGroupName == vmGroupName {
65-
logger.V(4).Info("found matching VM Host affinity rule")
6662
return vmHostAffinityRule{vmHostRuleInfo}, nil
6763
}
6864
}

pkg/services/govmomi/cluster/service.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package cluster
1919
import (
2020
"context"
2121

22-
"github.com/go-logr/logr"
2322
"github.com/vmware/govmomi/object"
2423
"github.com/vmware/govmomi/vim25/types"
2524

@@ -30,8 +29,6 @@ type computeClusterContext interface {
3029
context.Context
3130

3231
GetSession() *session.Session
33-
34-
GetLogger() logr.Logger
3532
}
3633

3734
func ListHostsFromGroup(ctx context.Context, ccr *object.ClusterComputeResource, hostGroup string) ([]object.Reference, error) {
@@ -53,17 +50,3 @@ func ListHostsFromGroup(ctx context.Context, ccr *object.ClusterComputeResource,
5350
}
5451
return refs, nil
5552
}
56-
57-
// TODO(srm09): Consider deferring the reconciliation of the task completion to a separate loop.
58-
func reconfigure(ctx context.Context, ccr *object.ClusterComputeResource, spec types.BaseComputeResourceConfigSpec) error {
59-
reconfigureTask, err := ccr.Reconfigure(ctx, spec, true)
60-
if err != nil {
61-
return err
62-
}
63-
64-
err = reconfigureTask.Wait(ctx)
65-
if err != nil {
66-
return err
67-
}
68-
return nil
69-
}

pkg/services/govmomi/cluster/vmgroup.go

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,59 +19,67 @@ package cluster
1919
import (
2020
"context"
2121

22+
"github.com/pkg/errors"
2223
"github.com/vmware/govmomi/object"
2324
"github.com/vmware/govmomi/vim25/types"
2425
)
2526

26-
func AddVMToGroup(ctx computeClusterContext, clusterName, vmGroupName, vm string) error {
27+
func FindVMGroup(ctx computeClusterContext, clusterName, vmGroupName string) (*VMGroup, error) {
2728
ccr, err := ctx.GetSession().Finder.ClusterComputeResource(ctx, clusterName)
2829
if err != nil {
29-
return err
30+
return nil, err
3031
}
3132

32-
vms, err := listVMs(ctx, ccr, vmGroupName)
33+
clusterConfigInfoEx, err := ccr.Configuration(ctx)
3334
if err != nil {
34-
return err
35+
return nil, err
3536
}
36-
37-
vmObj, err := ctx.GetSession().Finder.VirtualMachine(ctx, vm)
38-
if err != nil {
39-
return err
37+
for _, group := range clusterConfigInfoEx.Group {
38+
if clusterVMGroup, ok := group.(*types.ClusterVmGroup); ok {
39+
if clusterVMGroup.Name == vmGroupName {
40+
return &VMGroup{ccr, clusterVMGroup}, nil
41+
}
42+
}
4043
}
41-
vms = append(vms, vmObj.Reference())
44+
return nil, errors.Errorf("cannot find VM group %s", vmGroupName)
45+
}
46+
47+
// VMGroup represents a VSphere VM Group object
48+
type VMGroup struct {
49+
*object.ClusterComputeResource
50+
*types.ClusterVmGroup
51+
}
52+
53+
// Add a VSphere VM object to the VM Group
54+
func (vg VMGroup) Add(ctx context.Context, vmObj types.ManagedObjectReference) (*object.Task, error) {
55+
vms := vg.listVMs()
56+
vg.ClusterVmGroup.Vm = append(vms, vmObj) //nolint:gocritic
4257

43-
info := &types.ClusterVmGroup{
44-
ClusterGroupInfo: types.ClusterGroupInfo{
45-
Name: vmGroupName,
46-
},
47-
Vm: vms,
48-
}
4958
spec := &types.ClusterConfigSpecEx{
5059
GroupSpec: []types.ClusterGroupSpec{
5160
{
5261
ArrayUpdateSpec: types.ArrayUpdateSpec{
5362
Operation: types.ArrayUpdateOperationEdit,
5463
},
55-
Info: info,
64+
Info: vg.ClusterVmGroup,
5665
},
5766
},
5867
}
59-
return reconfigure(ctx, ccr, spec)
68+
return vg.ClusterComputeResource.Reconfigure(ctx, spec, true)
6069
}
6170

62-
func listVMs(ctx context.Context, ccr *object.ClusterComputeResource, vmGroupName string) ([]types.ManagedObjectReference, error) {
63-
clusterConfigInfoEx, err := ccr.Configuration(ctx)
64-
if err != nil {
65-
return nil, err
66-
}
71+
// HasVM returns whether a VSphere VM object is a member of the VM Group
72+
func (vg VMGroup) HasVM(vmObj types.ManagedObjectReference) (bool, error) {
73+
vms := vg.listVMs()
6774

68-
var refs []types.ManagedObjectReference
69-
for _, group := range clusterConfigInfoEx.Group {
70-
if clusterVMGroup, ok := group.(*types.ClusterVmGroup); ok {
71-
if clusterVMGroup.Name == vmGroupName {
72-
return clusterVMGroup.Vm, nil
73-
}
75+
for _, vm := range vms {
76+
if vm == vmObj {
77+
return true, nil
7478
}
7579
}
76-
return refs, nil
80+
return false, nil
81+
}
82+
83+
func (vg VMGroup) listVMs() []types.ManagedObjectReference {
84+
return vg.ClusterVmGroup.Vm
7785
}

pkg/services/govmomi/cluster/vmgroup_test.go

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,12 @@ import (
2828
"sigs.k8s.io/cluster-api-provider-vsphere/test/helpers"
2929
)
3030

31-
func TestAddVMToGroup(t *testing.T) {
31+
func Test_VMGroup(t *testing.T) {
3232
g := NewWithT(t)
3333
sim, err := helpers.VCSimBuilder().
34-
WithOperations("cluster.group.create -cluster DC0_C0 -name blah-vm-group -vm").
34+
WithOperations("cluster.group.create -cluster DC0_C0 -name blah-vm-group -vm DC0_C0_RP0_VM0 DC0_C0_RP0_VM1").
3535
Build()
36-
if err != nil {
37-
t.Fatalf("failed to create a VC simulator object %s", err)
38-
}
36+
g.Expect(err).NotTo(HaveOccurred())
3937
defer sim.Destroy()
4038

4139
ctx := context.Background()
@@ -50,14 +48,31 @@ func TestAddVMToGroup(t *testing.T) {
5048
finder: finder,
5149
}
5250

51+
computeClusterName := "DC0_C0"
5352
vmGroupName := "blah-vm-group"
54-
g.Expect(AddVMToGroup(computeClusterCtx, "DC0_C0", vmGroupName, "DC0_H0_VM0")).To(Succeed())
55-
g.Expect(AddVMToGroup(computeClusterCtx, "DC0_C0", vmGroupName, "DC0_H0_VM1")).To(Succeed())
5653

57-
ccr, err := finder.ClusterComputeResource(ctx, "DC0_C0")
54+
vmGrp, err := FindVMGroup(computeClusterCtx, computeClusterName, vmGroupName)
5855
g.Expect(err).NotTo(HaveOccurred())
56+
g.Expect(vmGrp.listVMs()).To(HaveLen(2))
5957

60-
refs, err := listVMs(ctx, ccr, "blah-vm-group")
58+
vmObjOne, err := finder.VirtualMachine(ctx, "DC0_H0_VM0")
6159
g.Expect(err).NotTo(HaveOccurred())
62-
g.Expect(refs).To(HaveLen(2))
60+
vmRef := vmObjOne.Reference()
61+
62+
hasVM, err := vmGrp.HasVM(vmRef)
63+
g.Expect(err).NotTo(HaveOccurred())
64+
g.Expect(hasVM).To(BeFalse())
65+
66+
task, err := vmGrp.Add(computeClusterCtx, vmRef)
67+
g.Expect(err).NotTo(HaveOccurred())
68+
g.Expect(task.Wait(ctx)).To(Succeed())
69+
g.Expect(vmGrp.listVMs()).To(HaveLen(3))
70+
71+
hasVM, err = vmGrp.HasVM(vmRef)
72+
g.Expect(err).NotTo(HaveOccurred())
73+
g.Expect(hasVM).To(BeTrue())
74+
75+
vmGroupName = "incorrect-vm-group"
76+
_, err = FindVMGroup(computeClusterCtx, computeClusterName, vmGroupName)
77+
g.Expect(err).To(HaveOccurred())
6378
}

pkg/services/govmomi/metadata/metadata.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,26 +47,36 @@ func getCategoryAssociableType(domainType infrav1.FailureDomainType) string {
4747
}
4848
}
4949

50+
// CreateCategory either creates a new vSphere category or updates the associable type for an existing category.
5051
func CreateCategory(ctx metadataContext, name string, failureDomainType infrav1.FailureDomainType) (string, error) {
5152
logger := ctx.GetLogger().WithValues("category", name)
5253
manager := ctx.GetSession().TagManager
5354
category, err := manager.GetCategory(ctx, name)
5455
if err != nil {
5556
logger.V(4).Info("failed to find existing category, creating a new category")
56-
id, err := manager.CreateCategory(ctx, &tags.Category{
57-
Name: name,
58-
Description: "CAPV generated category for Failure Domain support",
59-
AssociableTypes: []string{getCategoryAssociableType(failureDomainType)},
60-
Cardinality: "MULTIPLE",
61-
})
57+
id, err := manager.CreateCategory(ctx, getCategoryObject(name, failureDomainType))
6258
if err != nil {
6359
return "", err
6460
}
6561
return id, nil
6662
}
63+
category.Patch(getCategoryObject(name, failureDomainType))
64+
if err := manager.UpdateCategory(ctx, category); err != nil {
65+
logger.V(4).Error(err, "failed to update existing category")
66+
return "", err
67+
}
6768
return category.ID, nil
6869
}
6970

71+
func getCategoryObject(name string, failureDomainType infrav1.FailureDomainType) *tags.Category {
72+
return &tags.Category{
73+
Name: name,
74+
Description: "CAPV generated category for Failure Domain support",
75+
AssociableTypes: []string{getCategoryAssociableType(failureDomainType)},
76+
Cardinality: "MULTIPLE",
77+
}
78+
}
79+
7080
func CreateTag(ctx metadataContext, name, categoryID string) error {
7181
logger := ctx.GetLogger().WithValues("tag", name, "category", categoryID)
7282
manager := ctx.GetSession().TagManager

pkg/services/govmomi/service.go

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,11 @@ func (vms *VMService) ReconcileVM(ctx *context.VMContext) (vm infrav1.VirtualMac
132132
return vm, err
133133
}
134134

135-
if ok, err := vms.reconcilePowerState(vmCtx); err != nil || !ok {
135+
if ok, err := vms.reconcileVMGroupInfo(vmCtx); err != nil || !ok {
136136
return vm, err
137137
}
138138

139-
if err := vms.reconcileVMGroupInfo(ctx); err != nil {
139+
if ok, err := vms.reconcilePowerState(vmCtx); err != nil || !ok {
140140
return vm, err
141141
}
142142

@@ -490,15 +490,31 @@ func (vms *VMService) getBootstrapData(ctx *context.VMContext) ([]byte, error) {
490490
return value, nil
491491
}
492492

493-
func (vms *VMService) reconcileVMGroupInfo(ctx *context.VMContext) error {
494-
if ctx.VSphereFailureDomain != nil {
495-
topology := ctx.VSphereFailureDomain.Spec.Topology
496-
if topology.Hosts != nil {
497-
return cluster.AddVMToGroup(ctx,
498-
*topology.ComputeCluster,
499-
topology.Hosts.VMGroupName,
500-
ctx.VSphereVM.Name)
493+
func (vms *VMService) reconcileVMGroupInfo(ctx *virtualMachineContext) (bool, error) {
494+
if ctx.VSphereFailureDomain == nil || ctx.VSphereFailureDomain.Spec.Topology.Hosts == nil {
495+
ctx.Logger.Info("hosts topology in failure domain not defined. skipping reconcile VM group")
496+
return true, nil
497+
}
498+
499+
topology := ctx.VSphereFailureDomain.Spec.Topology
500+
vmGroup, err := cluster.FindVMGroup(ctx, *topology.ComputeCluster, topology.Hosts.VMGroupName)
501+
if err != nil {
502+
return false, errors.Wrapf(err, "unable to find VM Group %s", topology.Hosts.VMGroupName)
503+
}
504+
505+
hasVM, err := vmGroup.HasVM(ctx.Ref)
506+
if err != nil {
507+
return false, errors.Wrapf(err, "unable to find VM Group %s membership", topology.Hosts.VMGroupName)
508+
}
509+
510+
if !hasVM {
511+
task, err := vmGroup.Add(ctx, ctx.Ref)
512+
if err != nil {
513+
return false, errors.Wrapf(err, "failed to add VM %s to VM group", ctx.VSphereVM.Name)
501514
}
515+
ctx.VSphereVM.Status.TaskRef = task.Reference().Value
516+
ctx.Logger.Info("wait for VM to be added to group")
517+
return false, nil
502518
}
503-
return nil
519+
return true, nil
504520
}

0 commit comments

Comments
 (0)