From b1c8248b39561f50aaefa6511dc1500a3e2c6258 Mon Sep 17 00:00:00 2001 From: Cecile Robert-Michon Date: Mon, 15 Mar 2021 15:36:31 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=B1=20Standardize=20machine=20filter?= =?UTF-8?q?=20functions=20and=20improve=20testing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controllers/cluster_controller.go | 27 +-- controllers/machine_controller.go | 29 +--- controllers/machine_controller_test.go | 160 +++++++----------- controllers/machine_helpers.go | 29 ---- controllers/machine_helpers_test.go | 104 ------------ .../kubeadm/controllers/controller.go | 4 +- .../kubeadm/controllers/fakes_test.go | 4 +- controlplane/kubeadm/controllers/scale.go | 2 +- .../kubeadm/controllers/scale_test.go | 4 + controlplane/kubeadm/controllers/status.go | 2 +- .../kubeadm/controllers/status_test.go | 30 +++- controlplane/kubeadm/internal/cluster.go | 17 +- controlplane/kubeadm/internal/cluster_test.go | 14 +- util/collections/helpers.go | 43 +++++ util/collections/machine_collection.go | 9 + util/collections/machine_filters.go | 17 +- util/collections/machine_filters_test.go | 97 +++++++++++ util/conversion/conversion.go | 4 +- util/deprecated.go | 76 +++++++++ util/util.go | 67 -------- 20 files changed, 361 insertions(+), 378 deletions(-) create mode 100644 util/collections/helpers.go create mode 100644 util/deprecated.go diff --git a/controllers/cluster_controller.go b/controllers/cluster_controller.go index 1479625cad35..3e21714ad19a 100644 --- a/controllers/cluster_controller.go +++ b/controllers/cluster_controller.go @@ -23,6 +23,8 @@ import ( "strings" "time" + "sigs.k8s.io/cluster-api/util/collections" + "github.com/pkg/errors" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -400,11 +402,13 @@ func (r *ClusterReconciler) listDescendants(ctx context.Context, cluster *cluste } // Split machines into control plane and worker machines so we make sure we delete control plane machines last - controlPlaneMachines, workerMachines := splitMachineList(&machines) - descendants.workerMachines = *workerMachines + machineCollection := collections.FromMachineList(&machines) + controlPlaneMachines := machineCollection.Filter(collections.ControlPlaneMachines(cluster.Name)) + workerMachines := machineCollection.Difference(controlPlaneMachines) + descendants.workerMachines = collections.ToMachineList(workerMachines) // Only count control plane machines as descendants if there is no control plane provider. if cluster.Spec.ControlPlaneRef == nil { - descendants.controlPlaneMachines = *controlPlaneMachines + descendants.controlPlaneMachines = collections.ToMachineList(controlPlaneMachines) } @@ -448,21 +452,6 @@ func (c clusterDescendants) filterOwnedDescendants(cluster *clusterv1.Cluster) ( return ownedDescendants, nil } -// splitMachineList separates the machines running the control plane from other worker nodes. -func splitMachineList(list *clusterv1.MachineList) (*clusterv1.MachineList, *clusterv1.MachineList) { - nodes := &clusterv1.MachineList{} - controlplanes := &clusterv1.MachineList{} - for i := range list.Items { - machine := &list.Items[i] - if util.IsControlPlaneMachine(machine) { - controlplanes.Items = append(controlplanes.Items, *machine) - } else { - nodes.Items = append(nodes.Items, *machine) - } - } - return controlplanes, nodes -} - func (r *ClusterReconciler) reconcileControlPlaneInitialized(ctx context.Context, cluster *clusterv1.Cluster) (ctrl.Result, error) { log := ctrl.LoggerFrom(ctx) @@ -480,7 +469,7 @@ func (r *ClusterReconciler) reconcileControlPlaneInitialized(ctx context.Context log.V(4).Info("Checking for control plane initialization") - machines, err := getActiveMachinesInCluster(ctx, r.Client, cluster.Namespace, cluster.Name) + machines, err := collections.GetFilteredMachinesForCluster(ctx, r.Client, cluster, collections.ActiveMachines) if err != nil { log.Error(err, "unable to determine ControlPlaneInitialized") return ctrl.Result{}, err diff --git a/controllers/machine_controller.go b/controllers/machine_controller.go index bfbfc04d5ea5..74d8dc606c7c 100644 --- a/controllers/machine_controller.go +++ b/controllers/machine_controller.go @@ -19,6 +19,7 @@ package controllers import ( "context" "fmt" + "sigs.k8s.io/cluster-api/util/collections" "time" "github.com/pkg/errors" @@ -126,21 +127,6 @@ func (r *MachineReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manag return nil } -func (r *MachineReconciler) clusterToActiveMachines(a client.Object) []reconcile.Request { - requests := []reconcile.Request{} - machines, err := getActiveMachinesInCluster(context.TODO(), r.Client, a.GetNamespace(), a.GetName()) - if err != nil { - return requests - } - for _, m := range machines { - r := reconcile.Request{ - NamespacedName: util.ObjectKey(m), - } - requests = append(requests, r) - } - return requests -} - func (r *MachineReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { log := ctrl.LoggerFrom(ctx) @@ -471,8 +457,8 @@ func (r *MachineReconciler) isDeleteNodeAllowed(ctx context.Context, cluster *cl } } - // Get all of the machines that belong to this cluster. - machines, err := getActiveMachinesInCluster(ctx, r.Client, machine.Namespace, machine.Labels[clusterv1.ClusterLabelName]) + // Get all of the active machines that belong to this cluster. + machines, err := collections.GetFilteredMachinesForCluster(ctx, r.Client, cluster, collections.ActiveMachines) if err != nil { return err } @@ -480,15 +466,14 @@ func (r *MachineReconciler) isDeleteNodeAllowed(ctx context.Context, cluster *cl // Whether or not it is okay to delete the NodeRef depends on the // number of remaining control plane members and whether or not this // machine is one of them. - switch numControlPlaneMachines := len(util.GetControlPlaneMachines(machines)); { - case numControlPlaneMachines == 0: + numControlPlaneMachines := len(machines.Filter(collections.ControlPlaneMachines(cluster.Name))) + if numControlPlaneMachines == 0 { // Do not delete the NodeRef if there are no remaining members of // the control plane. return errNoControlPlaneNodes - default: - // Otherwise it is okay to delete the NodeRef. - return nil } + // Otherwise it is okay to delete the NodeRef. + return nil } func (r *MachineReconciler) drainNode(ctx context.Context, cluster *clusterv1.Cluster, nodeName string) (ctrl.Result, error) { diff --git a/controllers/machine_controller_test.go b/controllers/machine_controller_test.go index 6d2198fcf1b9..0569f2eaba19 100644 --- a/controllers/machine_controller_test.go +++ b/controllers/machine_controller_test.go @@ -1139,88 +1139,6 @@ func TestRemoveMachineFinalizerAfterDeleteReconcile(t *testing.T) { g.Expect(actual.ObjectMeta.Finalizers).To(Equal([]string{"test"})) } -func Test_clusterToActiveMachines(t *testing.T) { - testCluster2Machines := &clusterv1.Cluster{ - TypeMeta: metav1.TypeMeta{Kind: "Cluster", APIVersion: clusterv1.GroupVersion.String()}, - ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "test-cluster-2"}, - } - testCluster0Machines := &clusterv1.Cluster{ - TypeMeta: metav1.TypeMeta{Kind: "Cluster", APIVersion: clusterv1.GroupVersion.String()}, - ObjectMeta: metav1.ObjectMeta{Namespace: "default", Name: "test-cluster-0"}, - } - - tests := []struct { - name string - cluster client.Object - want []reconcile.Request - }{ - { - name: "cluster with two machines", - cluster: testCluster2Machines, - want: []reconcile.Request{ - { - NamespacedName: client.ObjectKey{ - Name: "m1", - Namespace: "default", - }, - }, - { - NamespacedName: client.ObjectKey{ - Name: "m2", - Namespace: "default", - }, - }, - }, - }, - { - name: "cluster with zero machines", - cluster: testCluster0Machines, - want: []reconcile.Request{}, - }, - } - for _, tt := range tests { - g := NewWithT(t) - - var objs []client.Object - objs = append(objs, testCluster2Machines) - objs = append(objs, testCluster0Machines) - - m1 := &clusterv1.Machine{ - TypeMeta: metav1.TypeMeta{ - Kind: "Machine", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "m1", - Namespace: "default", - Labels: map[string]string{ - clusterv1.ClusterLabelName: "test-cluster-2", - }, - }, - } - objs = append(objs, m1) - m2 := &clusterv1.Machine{ - TypeMeta: metav1.TypeMeta{ - Kind: "Machine", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "m2", - Namespace: "default", - Labels: map[string]string{ - clusterv1.ClusterLabelName: "test-cluster-2", - }, - }, - } - objs = append(objs, m2) - - r := &MachineReconciler{ - Client: helpers.NewFakeClientWithScheme(scheme.Scheme, objs...), - } - - got := r.clusterToActiveMachines(tt.cluster) - g.Expect(got).To(Equal(tt.want)) - } -} - func TestIsNodeDrainedAllowed(t *testing.T) { testCluster := &clusterv1.Cluster{ TypeMeta: metav1.TypeMeta{Kind: "Cluster", APIVersion: clusterv1.GroupVersion.String()}, @@ -1356,12 +1274,20 @@ func TestIsDeleteNodeAllowed(t *testing.T) { expectedError error }{ { - name: "machine without nodeRef", - cluster: &clusterv1.Cluster{}, + name: "machine without nodeRef", + cluster: &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Namespace: "default", + }, + }, machine: &clusterv1.Machine{ ObjectMeta: metav1.ObjectMeta{ - Name: "created", - Namespace: "default", + Name: "created", + Namespace: "default", + Labels: map[string]string{ + clusterv1.ClusterLabelName: "test-cluster", + }, Finalizers: []string{clusterv1.MachineFinalizer}, }, Spec: clusterv1.MachineSpec{ @@ -1374,12 +1300,20 @@ func TestIsDeleteNodeAllowed(t *testing.T) { expectedError: errNilNodeRef, }, { - name: "no control plane members", - cluster: &clusterv1.Cluster{}, + name: "no control plane members", + cluster: &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Namespace: "default", + }, + }, machine: &clusterv1.Machine{ ObjectMeta: metav1.ObjectMeta{ - Name: "created", - Namespace: "default", + Name: "created", + Namespace: "default", + Labels: map[string]string{ + clusterv1.ClusterLabelName: "test-cluster", + }, Finalizers: []string{clusterv1.MachineFinalizer}, }, Spec: clusterv1.MachineSpec{ @@ -1396,14 +1330,19 @@ func TestIsDeleteNodeAllowed(t *testing.T) { expectedError: errNoControlPlaneNodes, }, { - name: "is last control plane member", - cluster: &clusterv1.Cluster{}, + name: "is last control plane member", + cluster: &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Namespace: "default", + }, + }, machine: &clusterv1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: "created", Namespace: "default", Labels: map[string]string{ - clusterv1.ClusterLabelName: "test", + clusterv1.ClusterLabelName: "test-cluster", clusterv1.MachineControlPlaneLabelName: "", }, Finalizers: []string{clusterv1.MachineFinalizer}, @@ -1423,14 +1362,19 @@ func TestIsDeleteNodeAllowed(t *testing.T) { expectedError: errNoControlPlaneNodes, }, { - name: "has nodeRef and control plane is healthy", - cluster: &clusterv1.Cluster{}, + name: "has nodeRef and control plane is healthy", + cluster: &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Namespace: "default", + }, + }, machine: &clusterv1.Machine{ ObjectMeta: metav1.ObjectMeta{ Name: "created", Namespace: "default", Labels: map[string]string{ - clusterv1.ClusterLabelName: "test", + clusterv1.ClusterLabelName: "test-cluster", }, Finalizers: []string{clusterv1.MachineFinalizer}, }, @@ -1451,6 +1395,8 @@ func TestIsDeleteNodeAllowed(t *testing.T) { name: "has nodeRef and cluster is being deleted", cluster: &clusterv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Namespace: "default", DeletionTimestamp: &deletionts, }, }, @@ -1460,6 +1406,10 @@ func TestIsDeleteNodeAllowed(t *testing.T) { { name: "has nodeRef and control plane is healthy and externally managed", cluster: &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Namespace: "default", + }, Spec: clusterv1.ClusterSpec{ ControlPlaneRef: &corev1.ObjectReference{ APIVersion: "controlplane.cluster.x-k8s.io/v1alpha4", @@ -1474,7 +1424,7 @@ func TestIsDeleteNodeAllowed(t *testing.T) { Name: "created", Namespace: "default", Labels: map[string]string{ - clusterv1.ClusterLabelName: "test", + clusterv1.ClusterLabelName: "test-cluster", }, Finalizers: []string{clusterv1.MachineFinalizer}, }, @@ -1494,6 +1444,10 @@ func TestIsDeleteNodeAllowed(t *testing.T) { { name: "has nodeRef, control plane is being deleted and not externally managed", cluster: &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Namespace: "default", + }, Spec: clusterv1.ClusterSpec{ ControlPlaneRef: &corev1.ObjectReference{ APIVersion: "controlplane.cluster.x-k8s.io/v1alpha4", @@ -1508,7 +1462,7 @@ func TestIsDeleteNodeAllowed(t *testing.T) { Name: "created", Namespace: "default", Labels: map[string]string{ - clusterv1.ClusterLabelName: "test", + clusterv1.ClusterLabelName: "test-cluster", }, Finalizers: []string{clusterv1.MachineFinalizer}, }, @@ -1528,6 +1482,10 @@ func TestIsDeleteNodeAllowed(t *testing.T) { { name: "has nodeRef, control plane is being deleted and is externally managed", cluster: &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Namespace: "default", + }, Spec: clusterv1.ClusterSpec{ ControlPlaneRef: &corev1.ObjectReference{ APIVersion: "controlplane.cluster.x-k8s.io/v1alpha4", @@ -1542,7 +1500,7 @@ func TestIsDeleteNodeAllowed(t *testing.T) { Name: "created", Namespace: "default", Labels: map[string]string{ - clusterv1.ClusterLabelName: "test", + clusterv1.ClusterLabelName: "test-cluster", }, Finalizers: []string{clusterv1.MachineFinalizer}, }, @@ -1604,7 +1562,7 @@ func TestIsDeleteNodeAllowed(t *testing.T) { Name: "cp1", Namespace: "default", Labels: map[string]string{ - clusterv1.ClusterLabelName: "test", + clusterv1.ClusterLabelName: "test-cluster", }, Finalizers: []string{clusterv1.MachineFinalizer}, }, @@ -1624,7 +1582,7 @@ func TestIsDeleteNodeAllowed(t *testing.T) { Name: "cp2", Namespace: "default", Labels: map[string]string{ - clusterv1.ClusterLabelName: "test", + clusterv1.ClusterLabelName: "test-cluster", }, Finalizers: []string{clusterv1.MachineFinalizer}, }, diff --git a/controllers/machine_helpers.go b/controllers/machine_helpers.go index a842fb1ec579..f02e1c6c9440 100644 --- a/controllers/machine_helpers.go +++ b/controllers/machine_helpers.go @@ -17,39 +17,10 @@ limitations under the License. package controllers import ( - "context" - - "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" - clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4" - "sigs.k8s.io/controller-runtime/pkg/client" ) -// getActiveMachinesInCluster returns all of the active Machine objects -// that belong to the cluster with given namespace/name -func getActiveMachinesInCluster(ctx context.Context, c client.Client, namespace, name string) ([]*clusterv1.Machine, error) { - if name == "" { - return nil, nil - } - - machineList := &clusterv1.MachineList{} - labels := map[string]string{clusterv1.ClusterLabelName: name} - - if err := c.List(ctx, machineList, client.InNamespace(namespace), client.MatchingLabels(labels)); err != nil { - return nil, errors.Wrap(err, "failed to list machines") - } - - machines := []*clusterv1.Machine{} - for i := range machineList.Items { - m := &machineList.Items[i] - if m.DeletionTimestamp.IsZero() { - machines = append(machines, m) - } - } - return machines, nil -} - // hasMatchingLabels verifies that the Label Selector matches the given Labels func hasMatchingLabels(matchSelector metav1.LabelSelector, matchLabels map[string]string) bool { // This should never fail, validating webhook should catch this first diff --git a/controllers/machine_helpers_test.go b/controllers/machine_helpers_test.go index 8bca123b57ec..ed6c50f0a096 100644 --- a/controllers/machine_helpers_test.go +++ b/controllers/machine_helpers_test.go @@ -22,112 +22,8 @@ import ( . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/scheme" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - - clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4" ) -func Test_getActiveMachinesInCluster(t *testing.T) { - ns1Cluster1 := clusterv1.Machine{ - TypeMeta: metav1.TypeMeta{ - Kind: "Machine", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "ns1cluster1", - Namespace: "test-ns-1", - Labels: map[string]string{ - clusterv1.ClusterLabelName: "test-cluster-1", - }, - }, - } - ns1Cluster2 := clusterv1.Machine{ - TypeMeta: metav1.TypeMeta{ - Kind: "Machine", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "ns1cluster2", - Namespace: "test-ns-1", - Labels: map[string]string{ - clusterv1.ClusterLabelName: "test-cluster-2", - }, - }, - } - time := metav1.Now() - ns1Cluster1Deleted := clusterv1.Machine{ - TypeMeta: metav1.TypeMeta{ - Kind: "Machine", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "ns1cluster1deleted", - Namespace: "test-ns-1", - Labels: map[string]string{ - clusterv1.ClusterLabelName: "test-cluster-2", - }, - DeletionTimestamp: &time, - }, - } - ns2Cluster2 := clusterv1.Machine{ - TypeMeta: metav1.TypeMeta{ - Kind: "Machine", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "ns2cluster2", - Namespace: "test-ns-2", - Labels: map[string]string{ - clusterv1.ClusterLabelName: "test-cluster-2", - }, - }, - } - - type args struct { - namespace string - name string - } - tests := []struct { - name string - args args - want []*clusterv1.Machine - wantErr bool - }{ - { - name: "ns1 cluster1", - args: args{ - namespace: "test-ns-1", - name: "test-cluster-1", - }, - want: []*clusterv1.Machine{&ns1Cluster1}, - wantErr: false, - }, - { - name: "ns2 cluster2", - args: args{ - namespace: "test-ns-2", - name: "test-cluster-2", - }, - want: []*clusterv1.Machine{&ns2Cluster2}, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - g := NewWithT(t) - - g.Expect(clusterv1.AddToScheme(scheme.Scheme)).To(Succeed()) - - c := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(&ns1Cluster1, &ns1Cluster2, &ns1Cluster1Deleted, &ns2Cluster2).Build() - got, err := getActiveMachinesInCluster(ctx, c, tt.args.namespace, tt.args.name) - if tt.wantErr { - g.Expect(err).To(HaveOccurred()) - } else { - g.Expect(err).NotTo(HaveOccurred()) - } - - g.Expect(got).To(Equal(tt.want)) - }) - } -} - func TestMachineHealthCheckHasMatchingLabels(t *testing.T) { testCases := []struct { name string diff --git a/controlplane/kubeadm/controllers/controller.go b/controlplane/kubeadm/controllers/controller.go index bb9609cff38c..3f3c9d07d51e 100644 --- a/controlplane/kubeadm/controllers/controller.go +++ b/controlplane/kubeadm/controllers/controller.go @@ -270,7 +270,7 @@ func (r *KubeadmControlPlaneReconciler) reconcile(ctx context.Context, cluster * return result, err } - controlPlaneMachines, err := r.managementClusterUncached.GetMachinesForCluster(ctx, util.ObjectKey(cluster), collections.ControlPlaneMachines(cluster.Name)) + controlPlaneMachines, err := r.managementClusterUncached.GetMachinesForCluster(ctx, cluster, collections.ControlPlaneMachines(cluster.Name)) if err != nil { log.Error(err, "failed to retrieve control plane machines for cluster") return ctrl.Result{}, err @@ -390,7 +390,7 @@ func (r *KubeadmControlPlaneReconciler) reconcileDelete(ctx context.Context, clu log.Info("Reconcile KubeadmControlPlane deletion") // Gets all machines, not just control plane machines. - allMachines, err := r.managementCluster.GetMachinesForCluster(ctx, util.ObjectKey(cluster)) + allMachines, err := r.managementCluster.GetMachinesForCluster(ctx, cluster) if err != nil { return ctrl.Result{}, err } diff --git a/controlplane/kubeadm/controllers/fakes_test.go b/controlplane/kubeadm/controllers/fakes_test.go index 74592865f513..dec2018cc3a6 100644 --- a/controlplane/kubeadm/controllers/fakes_test.go +++ b/controlplane/kubeadm/controllers/fakes_test.go @@ -45,9 +45,9 @@ func (f *fakeManagementCluster) GetWorkloadCluster(_ context.Context, _ client.O return f.Workload, nil } -func (f *fakeManagementCluster) GetMachinesForCluster(c context.Context, n client.ObjectKey, filters ...collections.Func) (collections.Machines, error) { +func (f *fakeManagementCluster) GetMachinesForCluster(c context.Context, cluster *clusterv1.Cluster, filters ...collections.Func) (collections.Machines, error) { if f.Management != nil { - return f.Management.GetMachinesForCluster(c, n, filters...) + return f.Management.GetMachinesForCluster(c, cluster, filters...) } return f.Machines, nil } diff --git a/controlplane/kubeadm/controllers/scale.go b/controlplane/kubeadm/controllers/scale.go index 890002654f0a..c4b3597903a2 100644 --- a/controlplane/kubeadm/controllers/scale.go +++ b/controlplane/kubeadm/controllers/scale.go @@ -38,7 +38,7 @@ func (r *KubeadmControlPlaneReconciler) initializeControlPlane(ctx context.Conte // Perform an uncached read of all the owned machines. This check is in place to make sure // that the controller cache is not misbehaving and we end up initializing the cluster more than once. - ownedMachines, err := r.managementClusterUncached.GetMachinesForCluster(ctx, util.ObjectKey(cluster), collections.OwnedMachines(kcp)) + ownedMachines, err := r.managementClusterUncached.GetMachinesForCluster(ctx, cluster, collections.OwnedMachines(kcp)) if err != nil { logger.Error(err, "failed to perform an uncached read of control plane machines for cluster") return ctrl.Result{}, err diff --git a/controlplane/kubeadm/controllers/scale_test.go b/controlplane/kubeadm/controllers/scale_test.go index c3bb34b2d973..aa7dfc55d45d 100644 --- a/controlplane/kubeadm/controllers/scale_test.go +++ b/controlplane/kubeadm/controllers/scale_test.go @@ -66,6 +66,10 @@ func TestKubeadmControlPlaneReconciler_initializeControlPlane(t *testing.T) { g.Expect(fakeClient.List(ctx, machineList, client.InNamespace(cluster.Namespace))).To(Succeed()) g.Expect(machineList.Items).To(HaveLen(1)) + res, err := collections.GetFilteredMachinesForCluster(ctx, fakeClient, cluster, collections.OwnedMachines(kcp)) + g.Expect(res).To(HaveLen(1)) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(machineList.Items[0].Namespace).To(Equal(cluster.Namespace)) g.Expect(machineList.Items[0].Name).To(HavePrefix(kcp.Name)) diff --git a/controlplane/kubeadm/controllers/status.go b/controlplane/kubeadm/controllers/status.go index 6945226ed19d..9c26d525807c 100644 --- a/controlplane/kubeadm/controllers/status.go +++ b/controlplane/kubeadm/controllers/status.go @@ -39,7 +39,7 @@ func (r *KubeadmControlPlaneReconciler) updateStatus(ctx context.Context, kcp *c // This is necessary for CRDs including scale subresources. kcp.Status.Selector = selector.String() - ownedMachines, err := r.managementCluster.GetMachinesForCluster(ctx, util.ObjectKey(cluster), collections.OwnedMachines(kcp)) + ownedMachines, err := r.managementCluster.GetMachinesForCluster(ctx, cluster, collections.OwnedMachines(kcp)) if err != nil { return errors.Wrap(err, "failed to get list of owned machines") } diff --git a/controlplane/kubeadm/controllers/status_test.go b/controlplane/kubeadm/controllers/status_test.go index 8e515eb5923f..a6ec08c25270 100644 --- a/controlplane/kubeadm/controllers/status_test.go +++ b/controlplane/kubeadm/controllers/status_test.go @@ -46,6 +46,10 @@ func TestKubeadmControlPlaneReconciler_updateStatusNoMachines(t *testing.T) { } kcp := &controlplanev1.KubeadmControlPlane{ + TypeMeta: metav1.TypeMeta{ + Kind: "KubeadmControlPlane", + APIVersion: controlplanev1.GroupVersion.String(), + }, ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, Name: "foo", @@ -91,6 +95,10 @@ func TestKubeadmControlPlaneReconciler_updateStatusAllMachinesNotReady(t *testin } kcp := &controlplanev1.KubeadmControlPlane{ + TypeMeta: metav1.TypeMeta{ + Kind: "KubeadmControlPlane", + APIVersion: controlplanev1.GroupVersion.String(), + }, ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, Name: "foo", @@ -107,7 +115,7 @@ func TestKubeadmControlPlaneReconciler_updateStatusAllMachinesNotReady(t *testin for i := 0; i < 3; i++ { name := fmt.Sprintf("test-%d", i) m, n := createMachineNodePair(name, cluster, kcp, false) - objs = append(objs, n) + objs = append(objs, n, m) machines[m.Name] = m } @@ -145,6 +153,10 @@ func TestKubeadmControlPlaneReconciler_updateStatusAllMachinesReady(t *testing.T } kcp := &controlplanev1.KubeadmControlPlane{ + TypeMeta: metav1.TypeMeta{ + Kind: "KubeadmControlPlane", + APIVersion: controlplanev1.GroupVersion.String(), + }, ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, Name: "foo", @@ -161,7 +173,7 @@ func TestKubeadmControlPlaneReconciler_updateStatusAllMachinesReady(t *testing.T for i := 0; i < 3; i++ { name := fmt.Sprintf("test-%d", i) m, n := createMachineNodePair(name, cluster, kcp, true) - objs = append(objs, n) + objs = append(objs, n, m) machines[m.Name] = m } @@ -207,6 +219,10 @@ func TestKubeadmControlPlaneReconciler_updateStatusMachinesReadyMixed(t *testing } kcp := &controlplanev1.KubeadmControlPlane{ + TypeMeta: metav1.TypeMeta{ + Kind: "KubeadmControlPlane", + APIVersion: controlplanev1.GroupVersion.String(), + }, ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, Name: "foo", @@ -223,10 +239,10 @@ func TestKubeadmControlPlaneReconciler_updateStatusMachinesReadyMixed(t *testing name := fmt.Sprintf("test-%d", i) m, n := createMachineNodePair(name, cluster, kcp, false) machines[m.Name] = m - objs = append(objs, n) + objs = append(objs, n, m) } m, n := createMachineNodePair("testReady", cluster, kcp, true) - objs = append(objs, n, kubeadmConfigMap()) + objs = append(objs, n, m, kubeadmConfigMap()) machines[m.Name] = m fakeClient := newFakeClient(g, objs...) log.SetLogger(klogr.New()) @@ -268,6 +284,10 @@ func TestKubeadmControlPlaneReconciler_machinesCreatedIsIsTrueEvenWhenTheNodesAr } kcp := &controlplanev1.KubeadmControlPlane{ + TypeMeta: metav1.TypeMeta{ + Kind: "KubeadmControlPlane", + APIVersion: controlplanev1.GroupVersion.String(), + }, ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, Name: "foo", @@ -286,7 +306,7 @@ func TestKubeadmControlPlaneReconciler_machinesCreatedIsIsTrueEvenWhenTheNodesAr name := fmt.Sprintf("test-%d", i) m, n := createMachineNodePair(name, cluster, kcp, false) machines[m.Name] = m - objs = append(objs, n) + objs = append(objs, n, m) } fakeClient := newFakeClient(g, objs...) diff --git a/controlplane/kubeadm/internal/cluster.go b/controlplane/kubeadm/internal/cluster.go index b34fd128e421..a2a314fc2918 100644 --- a/controlplane/kubeadm/internal/cluster.go +++ b/controlplane/kubeadm/internal/cluster.go @@ -21,12 +21,12 @@ import ( "crypto/tls" "crypto/x509" "fmt" + clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4" "sigs.k8s.io/cluster-api/util/collections" "time" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" - clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4" "sigs.k8s.io/cluster-api/controllers/remote" "sigs.k8s.io/cluster-api/util/secret" "sigs.k8s.io/controller-runtime/pkg/client" @@ -42,7 +42,7 @@ const ( type ManagementCluster interface { ctrlclient.Reader - GetMachinesForCluster(ctx context.Context, cluster client.ObjectKey, filters ...collections.Func) (collections.Machines, error) + GetMachinesForCluster(ctx context.Context, cluster *clusterv1.Cluster, filters ...collections.Func) (collections.Machines, error) GetWorkloadCluster(ctx context.Context, clusterKey client.ObjectKey) (WorkloadCluster, error) } @@ -73,17 +73,8 @@ func (m *Management) List(ctx context.Context, list client.ObjectList, opts ...c // GetMachinesForCluster returns a list of machines that can be filtered or not. // If no filter is supplied then all machines associated with the target cluster are returned. -func (m *Management) GetMachinesForCluster(ctx context.Context, cluster client.ObjectKey, filters ...collections.Func) (collections.Machines, error) { - selector := map[string]string{ - clusterv1.ClusterLabelName: cluster.Name, - } - ml := &clusterv1.MachineList{} - if err := m.Client.List(ctx, ml, client.InNamespace(cluster.Namespace), client.MatchingLabels(selector)); err != nil { - return nil, errors.Wrap(err, "failed to list machines") - } - - machines := collections.FromMachineList(ml) - return machines.Filter(filters...), nil +func (m *Management) GetMachinesForCluster(ctx context.Context, cluster *clusterv1.Cluster, filters ...collections.Func) (collections.Machines, error) { + return collections.GetFilteredMachinesForCluster(ctx, m.Client, cluster, filters...) } // GetWorkloadCluster builds a cluster object. diff --git a/controlplane/kubeadm/internal/cluster_test.go b/controlplane/kubeadm/internal/cluster_test.go index 16ef5b0da44f..2307a644d2eb 100644 --- a/controlplane/kubeadm/internal/cluster_test.go +++ b/controlplane/kubeadm/internal/cluster_test.go @@ -51,16 +51,18 @@ func TestGetMachinesForCluster(t *testing.T) { m := Management{Client: &fakeClient{ list: machineListForTestGetMachinesForCluster(), }} - clusterKey := client.ObjectKey{ - Namespace: "my-namespace", - Name: "my-cluster", + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "my-namespace", + Name: "my-cluster", + }, } - machines, err := m.GetMachinesForCluster(ctx, clusterKey) + machines, err := m.GetMachinesForCluster(ctx, cluster) g.Expect(err).NotTo(HaveOccurred()) g.Expect(machines).To(HaveLen(3)) // Test the ControlPlaneMachines works - machines, err = m.GetMachinesForCluster(ctx, clusterKey, collections.ControlPlaneMachines("my-cluster")) + machines, err = m.GetMachinesForCluster(ctx, cluster, collections.ControlPlaneMachines("my-cluster")) g.Expect(err).NotTo(HaveOccurred()) g.Expect(machines).To(HaveLen(1)) @@ -68,7 +70,7 @@ func TestGetMachinesForCluster(t *testing.T) { nameFilter := func(cluster *clusterv1.Machine) bool { return cluster.Name == "first-machine" } - machines, err = m.GetMachinesForCluster(ctx, clusterKey, collections.ControlPlaneMachines("my-cluster"), nameFilter) + machines, err = m.GetMachinesForCluster(ctx, cluster, collections.ControlPlaneMachines("my-cluster"), nameFilter) g.Expect(err).NotTo(HaveOccurred()) g.Expect(machines).To(HaveLen(1)) } diff --git a/util/collections/helpers.go b/util/collections/helpers.go new file mode 100644 index 000000000000..bb0cc56d64f7 --- /dev/null +++ b/util/collections/helpers.go @@ -0,0 +1,43 @@ +/* +Copyright 2021 The Kubernetes Authors. + +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. +*/ + +package collections + +import ( + "context" + "github.com/pkg/errors" + clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// GetFilteredMachinesForCluster returns a list of machines that can be filtered or not. +// If no filter is supplied then all machines associated with the target cluster are returned. +func GetFilteredMachinesForCluster(ctx context.Context, c client.Reader, cluster *clusterv1.Cluster, filters ...Func) (Machines, error) { + ml := &clusterv1.MachineList{} + if err := c.List( + ctx, + ml, + client.InNamespace(cluster.Namespace), + client.MatchingLabels{ + clusterv1.ClusterLabelName: cluster.Name, + }, + ); err != nil { + return nil, errors.Wrap(err, "failed to list machines") + } + + machines := FromMachineList(ml) + return machines.Filter(filters...), nil +} diff --git a/util/collections/machine_collection.go b/util/collections/machine_collection.go index 1c5f5e0c02ae..047426085c65 100644 --- a/util/collections/machine_collection.go +++ b/util/collections/machine_collection.go @@ -59,6 +59,15 @@ func FromMachineList(machineList *clusterv1.MachineList) Machines { return ss } +// ToMachineList creates a MachineList from the given Machines. +func ToMachineList(machines Machines) clusterv1.MachineList { + ml := clusterv1.MachineList{} + for _, m := range machines { + ml.Items = append(ml.Items, *m) + } + return ml +} + // Insert adds items to the set. func (s Machines) Insert(machines ...*clusterv1.Machine) { for i := range machines { diff --git a/util/collections/machine_filters.go b/util/collections/machine_filters.go index 6c42152a53f1..6b1888da52b8 100644 --- a/util/collections/machine_filters.go +++ b/util/collections/machine_filters.go @@ -93,8 +93,8 @@ func InFailureDomains(failureDomains ...*string) Func { } } -// OwnedMachines returns a filter to find all owned control plane machines. -// Usage: managementCluster.GetMachinesForCluster(ctx, cluster, machinefilters.OwnedMachines(controlPlane)) +// OwnedMachines returns a filter to find all machines owned by specified owner. +// Usage: GetFilteredMachinesForCluster(ctx, client, cluster, OwnedMachines(controlPlane)) func OwnedMachines(owner client.Object) func(machine *clusterv1.Machine) bool { return func(machine *clusterv1.Machine) bool { if machine == nil { @@ -105,7 +105,7 @@ func OwnedMachines(owner client.Object) func(machine *clusterv1.Machine) bool { } // ControlPlaneMachines returns a filter to find all control plane machines for a cluster, regardless of ownership. -// Usage: managementCluster.GetMachinesForCluster(ctx, cluster, machinefilters.ControlPlaneMachines(cluster.Name)) +// Usage: GetFilteredMachinesForCluster(ctx, client, cluster, ControlPlaneMachines(cluster.Name)) func ControlPlaneMachines(clusterName string) func(machine *clusterv1.Machine) bool { selector := ControlPlaneSelectorForCluster(clusterName) return func(machine *clusterv1.Machine) bool { @@ -117,7 +117,7 @@ func ControlPlaneMachines(clusterName string) func(machine *clusterv1.Machine) b } // AdoptableControlPlaneMachines returns a filter to find all un-controlled control plane machines. -// Usage: managementCluster.GetMachinesForCluster(ctx, cluster, AdoptableControlPlaneMachines(cluster.Name, controlPlane)) +// Usage: GetFilteredMachinesForCluster(ctx, client, cluster, AdoptableControlPlaneMachines(cluster.Name, controlPlane)) func AdoptableControlPlaneMachines(clusterName string) func(machine *clusterv1.Machine) bool { return And( ControlPlaneMachines(clusterName), @@ -125,6 +125,15 @@ func AdoptableControlPlaneMachines(clusterName string) func(machine *clusterv1.M ) } +// ActiveMachines returns a filter to find all active machines. +// Usage: GetFilteredMachinesForCluster(ctx, client, cluster, ActiveMachines) +func ActiveMachines(machine *clusterv1.Machine) bool { + if machine == nil { + return false + } + return machine.DeletionTimestamp.IsZero() +} + // HasDeletionTimestamp returns a filter to find all machines that have a deletion timestamp. func HasDeletionTimestamp(machine *clusterv1.Machine) bool { if machine == nil { diff --git a/util/collections/machine_filters_test.go b/util/collections/machine_filters_test.go index 623752d99462..4a5fc2ed49d4 100644 --- a/util/collections/machine_filters_test.go +++ b/util/collections/machine_filters_test.go @@ -17,7 +17,10 @@ limitations under the License. package collections_test import ( + "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/cluster-api/util/collections" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" "testing" "time" @@ -29,6 +32,10 @@ import ( clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4" ) +var ( + ctx = ctrl.SetupSignalHandler() +) + func falseFilter(_ *clusterv1.Machine) bool { return false } @@ -220,6 +227,28 @@ func TestInFailureDomain(t *testing.T) { }) } +func TestActiveMachinesInCluster(t *testing.T) { + t.Run("machine with deletion timestamp returns false", func(t *testing.T) { + g := NewWithT(t) + m := &clusterv1.Machine{} + now := metav1.Now() + m.SetDeletionTimestamp(&now) + g.Expect(collections.ActiveMachines(m)).To(BeFalse()) + }) + t.Run("machine with nil deletion timestamp returns true", func(t *testing.T) { + g := NewWithT(t) + m := &clusterv1.Machine{} + g.Expect(collections.ActiveMachines(m)).To(BeTrue()) + }) + t.Run("machine with zero deletion timestamp returns true", func(t *testing.T) { + g := NewWithT(t) + m := &clusterv1.Machine{} + zero := metav1.NewTime(time.Time{}) + m.SetDeletionTimestamp(&zero) + g.Expect(collections.ActiveMachines(m)).To(BeTrue()) + }) +} + func TestMatchesKubernetesVersion(t *testing.T) { t.Run("nil machine returns false", func(t *testing.T) { g := NewWithT(t) @@ -258,3 +287,71 @@ func TestMatchesKubernetesVersion(t *testing.T) { g.Expect(collections.MatchesKubernetesVersion("some_ver")(machine)).To(BeFalse()) }) } + +func TestGetFilteredMachinesForCluster(t *testing.T) { + g := NewWithT(t) + + scheme := runtime.NewScheme() + g.Expect(clusterv1.AddToScheme(scheme)).To(Succeed()) + + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "my-namespace", + Name: "my-cluster", + }, + } + + c := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(cluster, + testControlPlaneMachine("first-machine"), + testMachine("second-machine"), + testMachine("third-machine")). + Build() + + machines, err := collections.GetFilteredMachinesForCluster(ctx, c, cluster) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(machines).To(HaveLen(3)) + + // Test the ControlPlaneMachines works + machines, err = collections.GetFilteredMachinesForCluster(ctx, c, cluster, collections.ControlPlaneMachines("my-cluster")) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(machines).To(HaveLen(1)) + + // Test that the filters use AND logic instead of OR logic + nameFilter := func(cluster *clusterv1.Machine) bool { + return cluster.Name == "first-machine" + } + machines, err = collections.GetFilteredMachinesForCluster(ctx, c, cluster, collections.ControlPlaneMachines("my-cluster"), nameFilter) + g.Expect(err).NotTo(HaveOccurred()) + g.Expect(machines).To(HaveLen(1)) +} + +func testControlPlaneMachine(name string) *clusterv1.Machine { + owned := true + ownedRef := []metav1.OwnerReference{ + { + Kind: "KubeadmControlPlane", + Name: "my-control-plane", + Controller: &owned, + }, + } + controlPlaneMachine := testMachine(name) + controlPlaneMachine.ObjectMeta.Labels[clusterv1.MachineControlPlaneLabelName] = "" + controlPlaneMachine.OwnerReferences = ownedRef + + return controlPlaneMachine +} + +func testMachine(name string) *clusterv1.Machine { + return &clusterv1.Machine{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: "my-namespace", + Labels: map[string]string{ + clusterv1.ClusterLabelName: "my-cluster", + }, + }, + } +} diff --git a/util/conversion/conversion.go b/util/conversion/conversion.go index 152eb9624de4..d4869006bda1 100644 --- a/util/conversion/conversion.go +++ b/util/conversion/conversion.go @@ -139,10 +139,10 @@ func GetFuzzer(scheme *runtime.Scheme, funcs ...fuzzer.FuzzerFuncs) *fuzz.Fuzzer type FuzzTestFuncInput struct { Scheme *runtime.Scheme - Hub conversion.Hub + Hub conversion.Hub HubAfterMutation func(conversion.Hub) - Spoke conversion.Convertible + Spoke conversion.Convertible SpokeAfterMutation func(convertible conversion.Convertible) FuzzerFuncs []fuzzer.FuzzerFuncs diff --git a/util/deprecated.go b/util/deprecated.go new file mode 100644 index 000000000000..9855b585d1b5 --- /dev/null +++ b/util/deprecated.go @@ -0,0 +1,76 @@ +/* +Copyright 2021 The Kubernetes Authors. + +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. +*/ + +package util + +import ( + "context" + "github.com/blang/semver" + clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4" + "sigs.k8s.io/cluster-api/util/version" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// ParseMajorMinorPatch returns a semver.Version from the string provided +// by looking only at major.minor.patch and stripping everything else out. +// Deprecated: Please use the function in util/version +// Deprecated in v1alpha4 +func ParseMajorMinorPatch(v string) (semver.Version, error) { + return version.ParseMajorMinorPatchTolerant(v) +} + +// GetMachinesForCluster returns a list of machines associated with the cluster. +// Deprecated: Please use util/collection GetFilteredMachinesForCluster(ctx, client, cluster) +// Deprecated in v1alpha4 +func GetMachinesForCluster(ctx context.Context, c client.Client, cluster *clusterv1.Cluster) (*clusterv1.MachineList, error) { + var machines clusterv1.MachineList + if err := c.List( + ctx, + &machines, + client.InNamespace(cluster.Namespace), + client.MatchingLabels{ + clusterv1.ClusterLabelName: cluster.Name, + }, + ); err != nil { + return nil, err + } + return &machines, nil +} + +// GetControlPlaneMachines returns a slice containing control plane machines. +// Deprecated: Please use util/collection FromMachines(machine).Filter(collections.ControlPlaneMachines(cluster.Name)) +// Deprecated in v1alpha4 +func GetControlPlaneMachines(machines []*clusterv1.Machine) (res []*clusterv1.Machine) { + for _, machine := range machines { + if IsControlPlaneMachine(machine) { + res = append(res, machine) + } + } + return +} + +// GetControlPlaneMachinesFromList returns a slice containing control plane machines. +// Deprecated: Please use util/collection FromMachineList(machineList).Filter(collections.ControlPlaneMachines(cluster.Name)) +// Deprecated in v1alpha4 +func GetControlPlaneMachinesFromList(machineList *clusterv1.MachineList) (res []*clusterv1.Machine) { + for i := 0; i < len(machineList.Items); i++ { + machine := machineList.Items[i] + if IsControlPlaneMachine(&machine) { + res = append(res, &machine) + } + } + return +} diff --git a/util/util.go b/util/util.go index 3c3d93f6e95c..f218d7892fb3 100644 --- a/util/util.go +++ b/util/util.go @@ -40,8 +40,6 @@ import ( "k8s.io/client-go/metadata" "k8s.io/client-go/rest" clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4" - "sigs.k8s.io/cluster-api/util/container" - "sigs.k8s.io/cluster-api/util/version" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/apiutil" @@ -52,9 +50,6 @@ import ( const ( // CharSet defines the alphanumeric set for random string generation CharSet = "0123456789abcdefghijklmnopqrstuvwxyz" - // MachineListFormatDeprecationMessage notifies the user that the old - // MachineList format is no longer supported - MachineListFormatDeprecationMessage = "Your MachineList items must include Kind and APIVersion" ) var ( @@ -95,68 +90,6 @@ func Ordinalize(n int) string { return fmt.Sprintf("%d%s", n, m[an%10]) } -// ParseMajorMinorPatch returns a semver.Version from the string provided -// by looking only at major.minor.patch and stripping everything else out. -// Deprecated: Please use the function in util/version -func ParseMajorMinorPatch(v string) (semver.Version, error) { - return version.ParseMajorMinorPatchTolerant(v) -} - -// ModifyImageRepository takes an imageName (e.g., repository/image:tag), and returns an image name with updated repository -// Deprecated: Please use the functions in util/container -func ModifyImageRepository(imageName, repositoryName string) (string, error) { - return container.ModifyImageRepository(imageName, repositoryName) -} - -// ModifyImageTag takes an imageName (e.g., repository/image:tag), and returns an image name with updated tag -// Deprecated: Please use the functions in util/container -func ModifyImageTag(imageName, tagName string) (string, error) { - return container.ModifyImageTag(imageName, tagName) -} - -// ImageTagIsValid ensures that a given image tag is compliant with the OCI spec -// Deprecated: Please use the functions in util/container -func ImageTagIsValid(tagName string) bool { - return container.ImageTagIsValid(tagName) -} - -// GetMachinesForCluster returns a list of machines associated with the cluster. -func GetMachinesForCluster(ctx context.Context, c client.Client, cluster *clusterv1.Cluster) (*clusterv1.MachineList, error) { - var machines clusterv1.MachineList - if err := c.List( - ctx, - &machines, - client.InNamespace(cluster.Namespace), - client.MatchingLabels{ - clusterv1.ClusterLabelName: cluster.Name, - }, - ); err != nil { - return nil, err - } - return &machines, nil -} - -// GetControlPlaneMachines returns a slice containing control plane machines. -func GetControlPlaneMachines(machines []*clusterv1.Machine) (res []*clusterv1.Machine) { - for _, machine := range machines { - if IsControlPlaneMachine(machine) { - res = append(res, machine) - } - } - return -} - -// GetControlPlaneMachinesFromList returns a slice containing control plane machines. -func GetControlPlaneMachinesFromList(machineList *clusterv1.MachineList) (res []*clusterv1.Machine) { - for i := 0; i < len(machineList.Items); i++ { - machine := machineList.Items[i] - if IsControlPlaneMachine(&machine) { - res = append(res, &machine) - } - } - return -} - // IsExternalManagedControlPlane returns a bool indicating whether the control plane referenced // in the passed Unstructured resource is an externally managed control plane such as AKS, EKS, GKE, etc. func IsExternalManagedControlPlane(controlPlane *unstructured.Unstructured) bool {