sigs.k8s.io/cluster-api-provider-azure@v1.14.3/controllers/azurejson_machine_controller_test.go (about) 1 /* 2 Copyright 2020 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 17 package controllers 18 19 import ( 20 "context" 21 "testing" 22 23 "github.com/google/go-cmp/cmp" 24 corev1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/runtime" 27 "k8s.io/apimachinery/pkg/types" 28 clientgoscheme "k8s.io/client-go/kubernetes/scheme" 29 "k8s.io/client-go/tools/record" 30 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 31 infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta1" 32 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 33 expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" 34 ctrl "sigs.k8s.io/controller-runtime" 35 "sigs.k8s.io/controller-runtime/pkg/client/fake" 36 "sigs.k8s.io/controller-runtime/pkg/event" 37 ) 38 39 func TestUnclonedMachinesPredicate(t *testing.T) { 40 cases := map[string]struct { 41 expected bool 42 labels map[string]string 43 annotations map[string]string 44 }{ 45 "uncloned worker node should return true": { 46 expected: true, 47 labels: nil, 48 annotations: nil, 49 }, 50 "uncloned control plane node should return true": { 51 expected: true, 52 labels: map[string]string{ 53 clusterv1.MachineControlPlaneLabel: "", 54 }, 55 annotations: nil, 56 }, 57 "cloned node should return false": { 58 expected: false, 59 labels: nil, 60 annotations: map[string]string{ 61 clusterv1.TemplateClonedFromGroupKindAnnotation: infrav1.GroupVersion.WithKind("AzureMachineTemplate").GroupKind().String(), 62 }, 63 }, 64 } 65 66 for name, tc := range cases { 67 tc := tc 68 t.Run(name, func(t *testing.T) { 69 t.Parallel() 70 machine := &infrav1.AzureMachine{ 71 ObjectMeta: metav1.ObjectMeta{ 72 Labels: tc.labels, 73 Annotations: tc.annotations, 74 }, 75 } 76 e := event.GenericEvent{ 77 Object: machine, 78 } 79 filter := filterUnclonedMachinesPredicate{} 80 if filter.Generic(e) != tc.expected { 81 t.Errorf("expected: %t, got %t", tc.expected, filter.Generic(e)) 82 } 83 }) 84 } 85 } 86 87 func TestAzureJSONMachineReconciler(t *testing.T) { 88 scheme, err := newScheme() 89 if err != nil { 90 t.Error(err) 91 } 92 93 cluster := &clusterv1.Cluster{ 94 ObjectMeta: metav1.ObjectMeta{ 95 Name: "my-cluster", 96 }, 97 Spec: clusterv1.ClusterSpec{ 98 InfrastructureRef: &corev1.ObjectReference{ 99 APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", 100 Kind: infrav1.AzureClusterKind, 101 Name: "my-azure-cluster", 102 }, 103 }, 104 } 105 106 azureCluster := &infrav1.AzureCluster{ 107 ObjectMeta: metav1.ObjectMeta{ 108 Name: "my-azure-cluster", 109 OwnerReferences: []metav1.OwnerReference{ 110 { 111 APIVersion: "cluster.x-k8s.io/v1beta1", 112 Kind: "Cluster", 113 Name: "my-cluster", 114 }, 115 }, 116 }, 117 Spec: infrav1.AzureClusterSpec{ 118 AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ 119 SubscriptionID: "123", 120 IdentityRef: &corev1.ObjectReference{ 121 Name: "fake-identity", 122 Namespace: "default", 123 }, 124 }, 125 NetworkSpec: infrav1.NetworkSpec{ 126 Subnets: infrav1.Subnets{ 127 { 128 SubnetClassSpec: infrav1.SubnetClassSpec{ 129 Name: "node", 130 Role: infrav1.SubnetNode, 131 }, 132 }, 133 }, 134 }, 135 }, 136 } 137 138 azureMachine := &infrav1.AzureMachine{ 139 ObjectMeta: metav1.ObjectMeta{ 140 Name: "my-machine", 141 Labels: map[string]string{ 142 clusterv1.ClusterNameLabel: "my-cluster", 143 }, 144 OwnerReferences: []metav1.OwnerReference{ 145 { 146 APIVersion: "cluster.x-k8s.io/v1beta1", 147 Kind: "Cluster", 148 Name: "my-cluster", 149 }, 150 }, 151 }, 152 } 153 154 fakeIdentity := &infrav1.AzureClusterIdentity{ 155 ObjectMeta: metav1.ObjectMeta{ 156 Name: "fake-identity", 157 Namespace: "default", 158 }, 159 Spec: infrav1.AzureClusterIdentitySpec{ 160 Type: infrav1.ServicePrincipal, 161 TenantID: "fake-tenantid", 162 }, 163 } 164 fakeSecret := &corev1.Secret{Data: map[string][]byte{"clientSecret": []byte("fooSecret")}} 165 166 cases := map[string]struct { 167 objects []runtime.Object 168 fail bool 169 err string 170 }{ 171 "should reconcile normally": { 172 objects: []runtime.Object{ 173 cluster, 174 azureCluster, 175 azureMachine, 176 fakeIdentity, 177 fakeSecret, 178 }, 179 }, 180 "missing azure cluster should return error": { 181 objects: []runtime.Object{ 182 cluster, 183 azureMachine, 184 }, 185 fail: true, 186 err: "azureclusters.infrastructure.cluster.x-k8s.io \"my-azure-cluster\" not found", 187 }, 188 "infra ref is nil": { 189 objects: []runtime.Object{ 190 &clusterv1.Cluster{ 191 ObjectMeta: metav1.ObjectMeta{ 192 Name: "my-cluster", 193 }, 194 Spec: clusterv1.ClusterSpec{ 195 InfrastructureRef: nil, 196 }, 197 }, 198 azureCluster, 199 azureMachine, 200 fakeIdentity, 201 fakeSecret, 202 }, 203 fail: false, 204 }, 205 "infra ref is not an azure cluster": { 206 objects: []runtime.Object{ 207 &clusterv1.Cluster{ 208 ObjectMeta: metav1.ObjectMeta{ 209 Name: "my-cluster", 210 }, 211 Spec: clusterv1.ClusterSpec{ 212 InfrastructureRef: &corev1.ObjectReference{ 213 APIVersion: "infrastructure.cluster.x-k8s.io/v1beta1", 214 Kind: "FooCluster", 215 Name: "my-foo-cluster", 216 }, 217 }, 218 }, 219 azureCluster, 220 azureMachine, 221 fakeIdentity, 222 fakeSecret, 223 }, 224 fail: false, 225 }, 226 } 227 228 for name, tc := range cases { 229 t.Run(name, func(t *testing.T) { 230 client := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(tc.objects...).Build() 231 232 reconciler := &AzureJSONMachineReconciler{ 233 Client: client, 234 Recorder: record.NewFakeRecorder(128), 235 } 236 237 _, err := reconciler.Reconcile(context.Background(), ctrl.Request{ 238 NamespacedName: types.NamespacedName{ 239 Namespace: "", 240 Name: "my-machine", 241 }, 242 }) 243 if tc.fail { 244 if diff := cmp.Diff(tc.err, err.Error()); diff != "" { 245 t.Error(diff) 246 } 247 } else { 248 if err != nil { 249 t.Errorf("expected success, but got error: %s", err.Error()) 250 } 251 } 252 }) 253 } 254 } 255 256 func newScheme() (*runtime.Scheme, error) { 257 scheme := runtime.NewScheme() 258 schemeFn := []func(*runtime.Scheme) error{ 259 clientgoscheme.AddToScheme, 260 infrav1.AddToScheme, 261 clusterv1.AddToScheme, 262 infrav1exp.AddToScheme, 263 expv1.AddToScheme, 264 corev1.AddToScheme, 265 } 266 for _, fn := range schemeFn { 267 fn := fn 268 if err := fn(scheme); err != nil { 269 return nil, err 270 } 271 } 272 return scheme, nil 273 }