sigs.k8s.io/cluster-api-provider-azure@v1.14.3/controllers/azuremanagedcontrolplane_controller_test.go (about) 1 /* 2 Copyright 2023 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 asocontainerservicev1preview "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20230315preview" 24 asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001" 25 asonetworkv1 "github.com/Azure/azure-service-operator/v2/api/network/v1api20201101" 26 asoresourcesv1 "github.com/Azure/azure-service-operator/v2/api/resources/v1api20200601" 27 . "github.com/onsi/gomega" 28 "go.uber.org/mock/gomock" 29 corev1 "k8s.io/api/core/v1" 30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 31 "k8s.io/apimachinery/pkg/runtime" 32 "k8s.io/apimachinery/pkg/types" 33 "k8s.io/client-go/tools/record" 34 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 35 "sigs.k8s.io/cluster-api-provider-azure/azure" 36 "sigs.k8s.io/cluster-api-provider-azure/azure/mock_azure" 37 "sigs.k8s.io/cluster-api-provider-azure/azure/scope" 38 "sigs.k8s.io/cluster-api-provider-azure/internal/test" 39 "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" 40 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 41 "sigs.k8s.io/cluster-api/util/patch" 42 ctrl "sigs.k8s.io/controller-runtime" 43 "sigs.k8s.io/controller-runtime/pkg/client" 44 "sigs.k8s.io/controller-runtime/pkg/client/fake" 45 ) 46 47 func TestClusterToAzureManagedControlPlane(t *testing.T) { 48 tests := []struct { 49 name string 50 controlPlaneRef *corev1.ObjectReference 51 expected []ctrl.Request 52 }{ 53 { 54 name: "nil", 55 controlPlaneRef: nil, 56 expected: nil, 57 }, 58 { 59 name: "bad kind", 60 controlPlaneRef: &corev1.ObjectReference{ 61 Kind: "NotAzureManagedControlPlane", 62 }, 63 expected: nil, 64 }, 65 { 66 name: "ok", 67 controlPlaneRef: &corev1.ObjectReference{ 68 Kind: infrav1.AzureManagedControlPlaneKind, 69 Name: "name", 70 Namespace: "namespace", 71 }, 72 expected: []ctrl.Request{ 73 { 74 NamespacedName: types.NamespacedName{ 75 Name: "name", 76 Namespace: "namespace", 77 }, 78 }, 79 }, 80 }, 81 } 82 83 for _, test := range tests { 84 t.Run(test.name, func(t *testing.T) { 85 g := NewWithT(t) 86 actual := (&AzureManagedControlPlaneReconciler{}).ClusterToAzureManagedControlPlane(context.TODO(), &clusterv1.Cluster{ 87 Spec: clusterv1.ClusterSpec{ 88 ControlPlaneRef: test.controlPlaneRef, 89 }, 90 }) 91 if test.expected == nil { 92 g.Expect(actual).To(BeNil()) 93 } else { 94 g.Expect(actual).To(Equal(test.expected)) 95 } 96 }) 97 } 98 } 99 100 func TestAzureManagedControlPlaneReconcilePaused(t *testing.T) { 101 g := NewWithT(t) 102 103 ctx := context.Background() 104 105 sb := runtime.NewSchemeBuilder( 106 clusterv1.AddToScheme, 107 infrav1.AddToScheme, 108 asoresourcesv1.AddToScheme, 109 asocontainerservicev1.AddToScheme, 110 asonetworkv1.AddToScheme, 111 corev1.AddToScheme, 112 asocontainerservicev1preview.AddToScheme, 113 ) 114 s := runtime.NewScheme() 115 g.Expect(sb.AddToScheme(s)).To(Succeed()) 116 c := fake.NewClientBuilder(). 117 WithScheme(s). 118 Build() 119 120 recorder := record.NewFakeRecorder(1) 121 122 reconciler := &AzureManagedControlPlaneReconciler{ 123 Client: c, 124 Recorder: recorder, 125 Timeouts: reconciler.Timeouts{}, 126 WatchFilterValue: "", 127 getNewAzureManagedControlPlaneReconciler: newAzureManagedControlPlaneReconciler, 128 } 129 name := test.RandomName("paused", 10) 130 namespace := "default" 131 132 cluster := &clusterv1.Cluster{ 133 ObjectMeta: metav1.ObjectMeta{ 134 Name: name, 135 Namespace: namespace, 136 }, 137 Spec: clusterv1.ClusterSpec{ 138 Paused: true, 139 }, 140 } 141 g.Expect(c.Create(ctx, cluster)).To(Succeed()) 142 143 fakeIdentity := &infrav1.AzureClusterIdentity{ 144 ObjectMeta: metav1.ObjectMeta{ 145 Name: "fake-identity", 146 Namespace: "default", 147 }, 148 Spec: infrav1.AzureClusterIdentitySpec{ 149 Type: infrav1.ServicePrincipal, 150 ClientSecret: corev1.SecretReference{ 151 Name: "fooSecret", 152 Namespace: "default", 153 }, 154 TenantID: "fake-tenantid", 155 }, 156 } 157 fakeSecret := &corev1.Secret{ 158 ObjectMeta: metav1.ObjectMeta{ 159 Name: "fooSecret", 160 Namespace: "default", 161 }, 162 Data: map[string][]byte{ 163 "clientSecret": []byte("fooSecret"), 164 }, 165 } 166 g.Expect(c.Create(ctx, fakeIdentity)).To(Succeed()) 167 g.Expect(c.Create(ctx, fakeSecret)).To(Succeed()) 168 169 instance := &infrav1.AzureManagedControlPlane{ 170 ObjectMeta: metav1.ObjectMeta{ 171 Name: name, 172 Namespace: namespace, 173 OwnerReferences: []metav1.OwnerReference{ 174 { 175 Kind: "Cluster", 176 APIVersion: clusterv1.GroupVersion.String(), 177 Name: cluster.Name, 178 }, 179 }, 180 }, 181 Spec: infrav1.AzureManagedControlPlaneSpec{ 182 AzureManagedControlPlaneClassSpec: infrav1.AzureManagedControlPlaneClassSpec{ 183 SubscriptionID: "something", 184 VirtualNetwork: infrav1.ManagedControlPlaneVirtualNetwork{ 185 ManagedControlPlaneVirtualNetworkClassSpec: infrav1.ManagedControlPlaneVirtualNetworkClassSpec{ 186 Name: name, 187 Subnet: infrav1.ManagedControlPlaneSubnet{ 188 Name: "subnet", 189 }, 190 }, 191 }, 192 FleetsMember: &infrav1.FleetsMemberClassSpec{ 193 Group: "fleets", 194 ManagerName: "fleets-manager", 195 ManagerResourceGroup: "fleets-manager-rg", 196 }, 197 IdentityRef: &corev1.ObjectReference{ 198 Name: "fake-identity", 199 Namespace: "default", 200 Kind: "AzureClusterIdentity", 201 }, 202 }, 203 ResourceGroupName: name, 204 }, 205 } 206 g.Expect(c.Create(ctx, instance)).To(Succeed()) 207 208 rg := &asoresourcesv1.ResourceGroup{ 209 ObjectMeta: metav1.ObjectMeta{ 210 Name: name, 211 Namespace: namespace, 212 }, 213 } 214 g.Expect(c.Create(ctx, rg)).To(Succeed()) 215 216 mc := &asocontainerservicev1.ManagedCluster{ 217 ObjectMeta: metav1.ObjectMeta{ 218 Name: name, 219 Namespace: namespace, 220 }, 221 } 222 g.Expect(c.Create(ctx, mc)).To(Succeed()) 223 224 vnet := &asonetworkv1.VirtualNetwork{ 225 ObjectMeta: metav1.ObjectMeta{ 226 Name: name, 227 Namespace: namespace, 228 }, 229 } 230 g.Expect(c.Create(ctx, vnet)).To(Succeed()) 231 232 fleetsMember := &asocontainerservicev1preview.FleetsMember{ 233 ObjectMeta: metav1.ObjectMeta{ 234 Name: name, 235 Namespace: namespace, 236 }, 237 } 238 g.Expect(c.Create(ctx, fleetsMember)).To(Succeed()) 239 240 subnet := &asonetworkv1.VirtualNetworksSubnet{ 241 ObjectMeta: metav1.ObjectMeta{ 242 Name: name + "-subnet", 243 Namespace: namespace, 244 }, 245 } 246 g.Expect(c.Create(ctx, subnet)).To(Succeed()) 247 248 result, err := reconciler.Reconcile(context.Background(), ctrl.Request{ 249 NamespacedName: client.ObjectKey{ 250 Namespace: instance.Namespace, 251 Name: instance.Name, 252 }, 253 }) 254 255 g.Expect(err).NotTo(HaveOccurred()) 256 g.Expect(result.RequeueAfter).To(BeZero()) 257 } 258 259 func TestAzureManagedControlPlaneReconcileNormal(t *testing.T) { 260 g := NewWithT(t) 261 ctx := context.Background() 262 cp := &infrav1.AzureManagedControlPlane{ 263 ObjectMeta: metav1.ObjectMeta{ 264 Name: "fake-azmp", 265 Namespace: "fake-ns", 266 }, 267 Spec: infrav1.AzureManagedControlPlaneSpec{ 268 AzureManagedControlPlaneClassSpec: infrav1.AzureManagedControlPlaneClassSpec{ 269 Version: "0.0.1", 270 }, 271 }, 272 Status: infrav1.AzureManagedControlPlaneStatus{ 273 Ready: false, 274 Initialized: false, 275 }, 276 } 277 scheme, err := newScheme() 278 g.Expect(err).NotTo(HaveOccurred()) 279 280 client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(cp).WithStatusSubresource(cp).Build() 281 amcpr := &AzureManagedControlPlaneReconciler{ 282 Client: client, 283 } 284 285 helper, err := patch.NewHelper(cp, client) 286 g.Expect(err).NotTo(HaveOccurred()) 287 288 scopes := &scope.ManagedControlPlaneScope{ 289 Cluster: &clusterv1.Cluster{ 290 ObjectMeta: metav1.ObjectMeta{ 291 Name: "fake-cluster", 292 Namespace: "fake-ns", 293 }, 294 }, 295 Client: client, 296 PatchHelper: helper, 297 ControlPlane: cp, 298 } 299 scopes.SetAdminKubeconfigData(createFakeKubeConfig()) 300 scopes.SetUserKubeconfigData(createFakeKubeConfig()) 301 302 amcpr.getNewAzureManagedControlPlaneReconciler = func(scope *scope.ManagedControlPlaneScope) (*azureManagedControlPlaneService, error) { 303 ctrlr := gomock.NewController(t) 304 svcr := mock_azure.NewMockServiceReconciler(ctrlr) 305 svcr.EXPECT().Reconcile(gomock.Any()).Return(nil) 306 307 return &azureManagedControlPlaneService{ 308 kubeclient: scope.Client, 309 scope: scope, 310 services: []azure.ServiceReconciler{ 311 svcr, 312 }, 313 }, nil 314 } 315 316 _, err = amcpr.reconcileNormal(ctx, scopes) 317 g.Expect(err).To(HaveOccurred()) 318 } 319 320 func createFakeKubeConfig() []byte { 321 return []byte(` 322 apiVersion: v1 323 kind: Config 324 clusters: 325 - cluster: 326 certificate-authority-data: UEhPTlkK 327 server: https://1.1.1.1 328 name: production 329 contexts: 330 - context: 331 cluster: production 332 user: production 333 name: production 334 current-context: production`) 335 }