Skip to content

Commit

Permalink
Refactor get machine util functions
Browse files Browse the repository at this point in the history
This patch refactors the VSphereMachine Service interface to expose a
new method to get the VSphereVM objects assoicated with a Cluster
object.
The idea is to reuse the VSphereMachine service without the need to
repeat similar code blocks in two places.
  • Loading branch information
srm09 committed Dec 27, 2023
1 parent 99f247e commit 6e80365
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 110 deletions.
2 changes: 2 additions & 0 deletions controllers/vspherecluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import (
"sigs.k8s.io/cluster-api-provider-vsphere/feature"
capvcontext "sigs.k8s.io/cluster-api-provider-vsphere/pkg/context"
inframanager "sigs.k8s.io/cluster-api-provider-vsphere/pkg/manager"
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/services"
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/services/vmoperator"
)

Expand Down Expand Up @@ -86,6 +87,7 @@ func AddClusterControllerToManager(ctx context.Context, controllerManagerCtx *ca
ControllerManagerContext: controllerManagerCtx,
Client: controllerManagerCtx.Client,
clusterModuleReconciler: NewReconciler(controllerManagerCtx),
vmService: services.VimMachineService{Client: controllerManagerCtx.Client},
}
clusterToInfraFn := clusterToInfrastructureMapFunc(ctx, controllerManagerCtx)
c, err := ctrl.NewControllerManagedBy(mgr).
Expand Down
4 changes: 3 additions & 1 deletion controllers/vspherecluster_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import (
"sigs.k8s.io/cluster-api-provider-vsphere/feature"
capvcontext "sigs.k8s.io/cluster-api-provider-vsphere/pkg/context"
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/identity"
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/services"
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/session"
infrautilv1 "sigs.k8s.io/cluster-api-provider-vsphere/pkg/util"
)
Expand All @@ -53,6 +54,7 @@ type clusterReconciler struct {
ControllerManagerContext *capvcontext.ControllerManagerContext
Client client.Client

vmService services.VimMachineService
clusterModuleReconciler Reconciler
}

Expand Down Expand Up @@ -126,7 +128,7 @@ func (r *clusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_
func (r *clusterReconciler) reconcileDelete(ctx context.Context, clusterCtx *capvcontext.ClusterContext) (reconcile.Result, error) {
log := ctrl.LoggerFrom(ctx)

vsphereMachines, err := infrautilv1.GetVSphereMachinesInCluster(ctx, r.Client, clusterCtx.Cluster.Namespace, clusterCtx.Cluster.Name)
vsphereMachines, err := r.vmService.GetMachinesInCluster(ctx, clusterCtx.Cluster.Namespace, clusterCtx.Cluster.Name)
if err != nil {
return reconcile.Result{}, pkgerrors.Wrapf(err,
"unable to list VSphereMachines part of VSphereCluster %s/%s", clusterCtx.VSphereCluster.Namespace, clusterCtx.VSphereCluster.Name)
Expand Down
60 changes: 22 additions & 38 deletions controllers/vspheremachine_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func AddMachineControllerToManager(ctx context.Context, controllerManagerContext
).
Watches(
&clusterv1.Cluster{},
handler.EnqueueRequestsFromMapFunc(r.clusterToVMwareMachines),
handler.EnqueueRequestsFromMapFunc(r.enqueueClusterToMachineRequests),
ctrlbldr.WithPredicates(
predicates.ClusterUnpausedAndInfrastructureReady(ctrl.LoggerFrom(ctx)),
),
Expand Down Expand Up @@ -161,7 +161,7 @@ func AddMachineControllerToManager(ctx context.Context, controllerManagerContext
).
Watches(
&clusterv1.Cluster{},
handler.EnqueueRequestsFromMapFunc(r.clusterToVSphereMachines),
handler.EnqueueRequestsFromMapFunc(r.enqueueClusterToMachineRequests),
ctrlbldr.WithPredicates(
predicates.ClusterUnpausedAndInfrastructureReady(ctrl.LoggerFrom(ctx)),
),
Expand Down Expand Up @@ -408,42 +408,6 @@ func (r *machineReconciler) patchMachineLabelsWithHostInfo(ctx context.Context,
return patchHelper.Patch(ctx, machine)
}

func (r *machineReconciler) clusterToVSphereMachines(ctx context.Context, a client.Object) []reconcile.Request {
requests := []reconcile.Request{}
machines, err := util.GetVSphereMachinesInCluster(ctx, r.Client, a.GetNamespace(), a.GetName())
if err != nil {
return requests
}
for _, m := range machines {
r := reconcile.Request{
NamespacedName: apitypes.NamespacedName{
Name: m.Name,
Namespace: m.Namespace,
},
}
requests = append(requests, r)
}
return requests
}

func (r *machineReconciler) clusterToVMwareMachines(ctx context.Context, a client.Object) []reconcile.Request {
requests := []reconcile.Request{}
machines, err := util.GetVMwareMachinesInCluster(ctx, r.Client, a.GetNamespace(), a.GetName())
if err != nil {
return requests
}
for _, m := range machines {
r := reconcile.Request{
NamespacedName: apitypes.NamespacedName{
Name: m.Name,
Namespace: m.Namespace,
},
}
requests = append(requests, r)
}
return requests
}

// Return hooks that will be invoked when a VirtualMachine is created.
func (r *machineReconciler) setVMModifiers(ctx context.Context, machineCtx capvcontext.MachineContext) error {
log := ctrl.LoggerFrom(ctx)
Expand All @@ -465,3 +429,23 @@ func (r *machineReconciler) setVMModifiers(ctx context.Context, machineCtx capvc
supervisorMachineCtx.VMModifiers = []vmware.VMModifier{networkModifier}
return nil
}

// enqueueClusterToMachineRequests returns a list of VSphereMachine reconcile requests
// belonging to the cluster.
func (r *machineReconciler) enqueueClusterToMachineRequests(ctx context.Context, a client.Object) []reconcile.Request {
requests := []reconcile.Request{}
machines, err := r.VMService.GetMachinesInCluster(ctx, a.GetNamespace(), a.GetName())
if err != nil {
return requests
}
for _, m := range machines {
r := reconcile.Request{

Check warning on line 442 in controllers/vspheremachine_controller.go

View check run for this annotation

Codecov / codecov/patch

controllers/vspheremachine_controller.go#L441-L442

Added lines #L441 - L442 were not covered by tests
NamespacedName: apitypes.NamespacedName{
Name: m.GetName(),
Namespace: m.GetNamespace(),
},
}
requests = append(requests, r)
}
return requests
}
2 changes: 2 additions & 0 deletions pkg/services/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

infrav1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/v1beta1"
Expand All @@ -32,6 +33,7 @@ import (

// VSphereMachineService is used for vsphere VM lifecycle and syncing with VSphereMachine types.
type VSphereMachineService interface {
GetMachinesInCluster(ctx context.Context, namespace, clusterName string) ([]client.Object, error)
FetchVSphereMachine(ctx context.Context, name types.NamespacedName) (capvcontext.MachineContext, error)
FetchVSphereCluster(ctx context.Context, cluster *clusterv1.Cluster, machineContext capvcontext.MachineContext) (capvcontext.MachineContext, error)
ReconcileDelete(ctx context.Context, machineCtx capvcontext.MachineContext) error
Expand Down
22 changes: 22 additions & 0 deletions pkg/services/vimmachine.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,28 @@ type VimMachineService struct {
Client client.Client
}

// GetMachinesInCluster returns a list of VSphereMachine objects belonging to the cluster.
func (v *VimMachineService) GetMachinesInCluster(
ctx context.Context,
namespace, clusterName string) ([]client.Object, error) {
labels := map[string]string{clusterv1.ClusterNameLabel: clusterName}
machineList := &infrav1.VSphereMachineList{}

if err := v.Client.List(
ctx, machineList,
client.InNamespace(namespace),
client.MatchingLabels(labels)); err != nil {
return nil, err
}

Check warning on line 62 in pkg/services/vimmachine.go

View check run for this annotation

Codecov / codecov/patch

pkg/services/vimmachine.go#L61-L62

Added lines #L61 - L62 were not covered by tests

objects := []client.Object{}
for _, machine := range machineList.Items {
m := machine
objects = append(objects, &m)
}
return objects, nil
}

// FetchVSphereMachine returns a new MachineContext containing the vsphereMachine.
func (v *VimMachineService) FetchVSphereMachine(ctx context.Context, name types.NamespacedName) (capvcontext.MachineContext, error) {
vsphereMachine := &infrav1.VSphereMachine{}
Expand Down
42 changes: 32 additions & 10 deletions pkg/services/vmoperator/vmopmachine.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
apitypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/util/conditions"
Expand All @@ -46,8 +46,30 @@ type VmopMachineService struct {
Client client.Client
}

// GetMachinesInCluster returns a list of VSphereMachine objects belonging to the cluster.
func (v *VmopMachineService) GetMachinesInCluster(
ctx context.Context,
namespace, clusterName string) ([]client.Object, error) {
labels := map[string]string{clusterv1.ClusterNameLabel: clusterName}
machineList := &vmwarev1.VSphereMachineList{}

if err := v.Client.List(
ctx, machineList,
client.InNamespace(namespace),
client.MatchingLabels(labels)); err != nil {
return nil, err
}

Check warning on line 61 in pkg/services/vmoperator/vmopmachine.go

View check run for this annotation

Codecov / codecov/patch

pkg/services/vmoperator/vmopmachine.go#L60-L61

Added lines #L60 - L61 were not covered by tests

objects := []client.Object{}
for _, machine := range machineList.Items {
m := machine
objects = append(objects, &m)
}
return objects, nil
}

// FetchVSphereMachine returns a MachineContext with a VSphereMachine for the passed NamespacedName.
func (v *VmopMachineService) FetchVSphereMachine(ctx context.Context, name types.NamespacedName) (capvcontext.MachineContext, error) {
func (v *VmopMachineService) FetchVSphereMachine(ctx context.Context, name apitypes.NamespacedName) (capvcontext.MachineContext, error) {
vsphereMachine := &vmwarev1.VSphereMachine{}
err := v.Client.Get(ctx, name, vsphereMachine)
return &vmware.SupervisorMachineContext{VSphereMachine: vsphereMachine}, err
Expand Down Expand Up @@ -82,17 +104,17 @@ func (v *VmopMachineService) ReconcileDelete(ctx context.Context, machineCtx cap

// If debug logging is enabled, report the number of vms in the cluster before and after the reconcile
if log.V(5).Enabled() {
vms, err := v.getVirtualMachinesInCluster(ctx, supervisorMachineCtx)
vms, err := v.GetVirtualMachinesInCluster(ctx, supervisorMachineCtx)
log.V(5).Info("Trace Destroy PRE: VirtualMachines", "vmcount", len(vms), "err", err)
defer func() {
vms, err := v.getVirtualMachinesInCluster(ctx, supervisorMachineCtx)
vms, err := v.GetVirtualMachinesInCluster(ctx, supervisorMachineCtx)
log.V(5).Info("Trace Destroy POST: VirtualMachines", "vmcount", len(vms), "err", err)
}()
}

// First, check to see if it's already deleted
vmopVM := vmoprv1.VirtualMachine{}
if err := v.Client.Get(ctx, types.NamespacedName{Namespace: supervisorMachineCtx.Machine.Namespace, Name: supervisorMachineCtx.Machine.Name}, &vmopVM); err != nil {
if err := v.Client.Get(ctx, apitypes.NamespacedName{Namespace: supervisorMachineCtx.Machine.Namespace, Name: supervisorMachineCtx.Machine.Name}, &vmopVM); err != nil {
// If debug logging is enabled, report the number of vms in the cluster before and after the reconcile
if apierrors.IsNotFound(err) {
supervisorMachineCtx.VSphereMachine.Status.VMStatus = vmwarev1.VirtualMachineStateNotFound
Expand Down Expand Up @@ -143,10 +165,10 @@ func (v *VmopMachineService) ReconcileNormal(ctx context.Context, machineCtx cap

// If debug logging is enabled, report the number of vms in the cluster before and after the reconcile
if log.V(5).Enabled() {
vms, err := v.getVirtualMachinesInCluster(ctx, supervisorMachineCtx)
vms, err := v.GetVirtualMachinesInCluster(ctx, supervisorMachineCtx)
log.V(5).Info("Trace ReconcileVM PRE: VirtualMachines", "vmcount", len(vms), "err", err)
defer func() {
vms, err = v.getVirtualMachinesInCluster(ctx, supervisorMachineCtx)
vms, err = v.GetVirtualMachinesInCluster(ctx, supervisorMachineCtx)
log.V(5).Info("Trace ReconcileVM POST: VirtualMachines", "vmcount", len(vms), "err", err)
}()
}
Expand Down Expand Up @@ -393,9 +415,9 @@ func (v *VmopMachineService) reconcileProviderID(ctx context.Context, supervisor
}
}

// getVirtualMachinesInCluster returns all VMOperator VirtualMachine objects in the current cluster.
// First filter by clusterSelectorKey. If the result is empty, they fall back to legacyClusterSelectorKey.
func (v *VmopMachineService) getVirtualMachinesInCluster(ctx context.Context, supervisorMachineCtx *vmware.SupervisorMachineContext) ([]*vmoprv1.VirtualMachine, error) {
// GetVirtualMachinesInCluster returns all VMOperator VirtualMachine objects in the current cluster.
// First filter by ClusterSelectorKey. If the result is empty, they fall back to LegacyClusterSelectorKey.
func (v *VmopMachineService) GetVirtualMachinesInCluster(ctx context.Context, supervisorMachineCtx *vmware.SupervisorMachineContext) ([]*vmoprv1.VirtualMachine, error) {
if supervisorMachineCtx.Cluster == nil {
return []*vmoprv1.VirtualMachine{}, errors.Errorf("No cluster is set for machine %s in namespace %s", supervisorMachineCtx.GetVSphereMachine().GetName(), supervisorMachineCtx.GetVSphereMachine().GetNamespace())
}
Expand Down
53 changes: 38 additions & 15 deletions pkg/services/vmoperator/vmopmachine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ import (
"k8s.io/apimachinery/pkg/types"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
"sigs.k8s.io/cluster-api/util/conditions"
"sigs.k8s.io/controller-runtime/pkg/client"

infrav1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/v1beta1"
vmwarev1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/vmware/v1beta1"
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/context/fake"
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/context/vmware"
"sigs.k8s.io/cluster-api-provider-vsphere/pkg/util"
)
Expand All @@ -57,20 +59,22 @@ func updateReconciledVMStatus(ctx context.Context, vmService VmopMachineService,
Expect(err).ShouldNot(HaveOccurred())
}

const (
machineName = "test-machine"
clusterName = "test-cluster"
controlPlaneLabelTrue = true
k8sVersion = "test-k8sVersion"
className = "test-className"
imageName = "test-imageName"
storageClass = "test-storageClass"
minHardwareVersion = int32(17)
vmIP = "127.0.0.1"
biosUUID = "test-biosUuid"
missingK8SVersionFailure = "missing kubernetes version"
)

var _ = Describe("VirtualMachine tests", func() {
const (
machineName = "test-machine"
clusterName = "test-cluster"
controlPlaneLabelTrue = true
k8sVersion = "test-k8sVersion"
className = "test-className"
imageName = "test-imageName"
storageClass = "test-storageClass"
minHardwareVersion = int32(17)
vmIP = "127.0.0.1"
biosUUID = "test-biosUuid"
missingK8SVersionFailure = "missing kubernetes version"
)

var (
bootstrapData = "test-bootstrap-data"

Expand All @@ -91,7 +95,6 @@ var _ = Describe("VirtualMachine tests", func() {
vsphereMachine *vmwarev1.VSphereMachine
supervisorMachineContext *vmware.SupervisorMachineContext

// vm vmwarev1.VirtualMachine
vmopVM *vmoprv1.VirtualMachine
vmService VmopMachineService
)
Expand Down Expand Up @@ -135,7 +138,7 @@ var _ = Describe("VirtualMachine tests", func() {
Expect(vmopVM != nil).Should(Equal(expectVMOpVM))

if vmopVM != nil {
vms, _ := vmService.getVirtualMachinesInCluster(ctx, machineContext)
vms, _ := vmService.GetVirtualMachinesInCluster(ctx, machineContext)
Expect(vms).Should(HaveLen(1))
Expect(vmopVM.Spec.ImageName).To(Equal(expectedImageName))
Expect(vmopVM.Spec.ClassName).To(Equal(className))
Expand Down Expand Up @@ -595,3 +598,23 @@ var _ = Describe("VirtualMachine tests", func() {
})
})
})

var _ = Describe("GetMachinesInCluster", func() {

initObjs := []client.Object{
util.CreateVSphereMachine(machineName, clusterName, className, imageName, storageClass, controlPlaneLabelTrue),
}

controllerManagerContext := fake.NewControllerManagerContext(initObjs...)
vmService := VmopMachineService{Client: controllerManagerContext.Client}

It("returns a list of VMs belonging to the cluster", func() {
objs, err := vmService.GetMachinesInCluster(context.TODO(),
corev1.NamespaceDefault,
clusterName)

Expect(err).ToNot(HaveOccurred())
Expect(objs).To(HaveLen(1))
Expect(objs[0].GetName()).To(Equal(machineName))
})
})
Loading

0 comments on commit 6e80365

Please sign in to comment.