sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/privatedns/privatedns_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 privatedns 18 19 import ( 20 "context" 21 "net/http" 22 "testing" 23 24 "github.com/Azure/azure-sdk-for-go/sdk/azcore" 25 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources" 26 . "github.com/onsi/gomega" 27 "github.com/pkg/errors" 28 "go.uber.org/mock/gomock" 29 "k8s.io/utils/ptr" 30 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 31 "sigs.k8s.io/cluster-api-provider-azure/azure" 32 "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" 33 "sigs.k8s.io/cluster-api-provider-azure/azure/services/privatedns/mock_privatedns" 34 gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" 35 "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" 36 ) 37 38 const ( 39 zoneName = "my-zone" 40 resourceGroup = "my-rg" 41 vnetName = "my-vnet" 42 vnetResourceGroup = "my-vnet-rg" 43 linkName1 = "my-link-1" 44 linkName2 = "my-link-2" 45 clusterName = "my-cluster" 46 subscriptionID = "my-subscription-id" 47 ) 48 49 var ( 50 fakeZone = ZoneSpec{ 51 Name: zoneName, 52 ResourceGroup: resourceGroup, 53 ClusterName: clusterName, 54 AdditionalTags: nil, 55 } 56 57 fakeLink1 = LinkSpec{ 58 Name: linkName1, 59 ZoneName: zoneName, 60 SubscriptionID: subscriptionID, 61 VNetResourceGroup: vnetResourceGroup, 62 VNetName: vnetName, 63 ResourceGroup: resourceGroup, 64 ClusterName: clusterName, 65 AdditionalTags: nil, 66 } 67 68 fakeLink2 = LinkSpec{ 69 Name: linkName2, 70 ZoneName: zoneName, 71 SubscriptionID: subscriptionID, 72 VNetResourceGroup: vnetResourceGroup, 73 VNetName: vnetName, 74 ResourceGroup: resourceGroup, 75 ClusterName: clusterName, 76 AdditionalTags: nil, 77 } 78 79 fakeRecord1 = RecordSpec{ 80 Record: infrav1.AddressRecord{Hostname: "my-host", IP: "10.0.0.8"}, 81 ZoneName: zoneName, 82 ResourceGroup: resourceGroup, 83 } 84 85 managedTags = armresources.TagsResource{ 86 Properties: &armresources.Tags{ 87 Tags: map[string]*string{ 88 "foo": ptr.To("bar"), 89 "sigs.k8s.io_cluster-api-provider-azure_cluster_" + clusterName: ptr.To("owned"), 90 }, 91 }, 92 } 93 94 notDoneError = azure.NewOperationNotDoneError(&infrav1.Future{Type: "resourceType", ResourceGroup: resourceGroup, Name: "resourceName"}) 95 errFake = errors.New("this is an error") 96 notFoundError = &azcore.ResponseError{StatusCode: http.StatusNotFound} 97 ) 98 99 func TestReconcilePrivateDNS(t *testing.T) { 100 testcases := []struct { 101 name string 102 expectedError string 103 expect func(s *mock_privatedns.MockScopeMockRecorder, zoneReconiler, linksReconciler, recordsReconciler *mock_async.MockReconcilerMockRecorder, 104 tagsGetter *mock_async.MockTagsGetterMockRecorder) 105 }{ 106 { 107 name: "no private dns", 108 expectedError: "", 109 expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 110 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 111 s.PrivateDNSSpec().Return(nil, nil, nil) 112 }, 113 }, 114 { 115 name: "create private dns with multiple links successfully", 116 expectedError: "", 117 expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 118 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 119 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 120 121 s.SubscriptionID().Return("123") 122 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 123 124 s.SubscriptionID().Return("123") 125 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 126 127 s.SubscriptionID().Return("123") 128 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 129 130 z.CreateOrUpdateResource(gomockinternal.AContext(), fakeZone, serviceName).Return(nil, nil) 131 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink1, serviceName).Return(nil, nil) 132 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(nil, nil) 133 r.CreateOrUpdateResource(gomockinternal.AContext(), fakeRecord1, serviceName).Return(nil, nil) 134 s.UpdatePutStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, nil) 135 s.UpdatePutStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, nil) 136 s.UpdatePutStatus(infrav1.PrivateDNSRecordReadyCondition, serviceName, nil) 137 }, 138 }, 139 { 140 name: "zone creation in progress", 141 expectedError: "operation type resourceType on Azure resource my-rg/resourceName is not done", 142 expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 143 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 144 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 145 146 s.SubscriptionID().Return("123") 147 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 148 149 z.CreateOrUpdateResource(gomockinternal.AContext(), fakeZone, serviceName).Return(nil, notDoneError) 150 s.UpdatePutStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, notDoneError) 151 }, 152 }, 153 { 154 name: "zone creation fails", 155 expectedError: "this is an error", 156 expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 157 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 158 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 159 160 s.SubscriptionID().Return("123") 161 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 162 163 z.CreateOrUpdateResource(gomockinternal.AContext(), fakeZone, serviceName).Return(nil, errFake) 164 s.UpdatePutStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, errFake) 165 }, 166 }, 167 { 168 name: "unmanaged zone does not update ready condition", 169 expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 170 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 171 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 172 173 s.SubscriptionID().Return("123") 174 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(armresources.TagsResource{}, nil) 175 s.ClusterName().Return(clusterName) 176 177 s.SubscriptionID().Return("123") 178 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 179 180 s.SubscriptionID().Return("123") 181 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 182 183 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink1, serviceName).Return(nil, nil) 184 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(nil, nil) 185 r.CreateOrUpdateResource(gomockinternal.AContext(), fakeRecord1, serviceName).Return(nil, nil) 186 s.UpdatePutStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, nil) 187 s.UpdatePutStatus(infrav1.PrivateDNSRecordReadyCondition, serviceName, nil) 188 }, 189 }, 190 { 191 name: "link 1 creation fails but still proceeds to link 2, and returns the error", 192 expectedError: "this is an error", 193 expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 194 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 195 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 196 197 s.SubscriptionID().Return("123") 198 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 199 200 s.SubscriptionID().Return("123") 201 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 202 203 s.SubscriptionID().Return("123") 204 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 205 206 z.CreateOrUpdateResource(gomockinternal.AContext(), fakeZone, serviceName).Return(nil, nil) 207 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink1, serviceName).Return(nil, errFake) 208 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(nil, nil) 209 s.UpdatePutStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, nil) 210 s.UpdatePutStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, errFake) 211 }, 212 }, 213 { 214 name: "link 2 creation fails", 215 expectedError: "this is an error", 216 expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 217 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 218 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 219 220 s.SubscriptionID().Return("123") 221 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 222 223 s.SubscriptionID().Return("123") 224 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 225 226 s.SubscriptionID().Return("123") 227 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 228 229 z.CreateOrUpdateResource(gomockinternal.AContext(), fakeZone, serviceName).Return(nil, nil) 230 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink1, serviceName).Return(nil, nil) 231 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(nil, errFake) 232 s.UpdatePutStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, nil) 233 s.UpdatePutStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, errFake) 234 }, 235 }, 236 { 237 name: "link 1 is long running, link 2 fails, it returns the failure of link2", 238 expectedError: "this is an error", 239 expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 240 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 241 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 242 243 s.SubscriptionID().Return("123") 244 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 245 246 s.SubscriptionID().Return("123") 247 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 248 249 s.SubscriptionID().Return("123") 250 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 251 252 z.CreateOrUpdateResource(gomockinternal.AContext(), fakeZone, serviceName).Return(nil, nil) 253 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink1, serviceName).Return(nil, notDoneError) 254 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(nil, errFake) 255 s.UpdatePutStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, nil) 256 s.UpdatePutStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, errFake) 257 }, 258 }, 259 { 260 name: "unmanaged link does not update ready condition", 261 expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 262 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 263 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 264 265 s.SubscriptionID().Return("123") 266 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 267 268 s.SubscriptionID().Return("123") 269 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(armresources.TagsResource{}, nil) 270 s.ClusterName().Return(clusterName) 271 272 s.SubscriptionID().Return("123") 273 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(armresources.TagsResource{}, nil) 274 s.ClusterName().Return(clusterName) 275 276 z.CreateOrUpdateResource(gomockinternal.AContext(), fakeZone, serviceName).Return(nil, nil) 277 r.CreateOrUpdateResource(gomockinternal.AContext(), fakeRecord1, serviceName).Return(nil, nil) 278 s.UpdatePutStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, nil) 279 s.UpdatePutStatus(infrav1.PrivateDNSRecordReadyCondition, serviceName, nil) 280 }, 281 }, 282 { 283 name: "vnet link is considered managed if at least one of the links is managed", 284 expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 285 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 286 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 287 288 s.SubscriptionID().Return("123") 289 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 290 291 s.SubscriptionID().Return("123") 292 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(armresources.TagsResource{}, nil) 293 s.ClusterName().Return(clusterName) 294 295 s.SubscriptionID().Return("123") 296 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 297 298 z.CreateOrUpdateResource(gomockinternal.AContext(), fakeZone, serviceName).Return(nil, nil) 299 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(nil, nil) 300 r.CreateOrUpdateResource(gomockinternal.AContext(), fakeRecord1, serviceName).Return(nil, nil) 301 s.UpdatePutStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, nil) 302 s.UpdatePutStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, nil) 303 s.UpdatePutStatus(infrav1.PrivateDNSRecordReadyCondition, serviceName, nil) 304 }, 305 }, 306 { 307 name: "record creation fails", 308 expectedError: "this is an error", 309 expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 310 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 311 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 312 313 s.SubscriptionID().Return("123") 314 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 315 316 s.SubscriptionID().Return("123") 317 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 318 319 s.SubscriptionID().Return("123") 320 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(armresources.TagsResource{}, notFoundError) 321 322 z.CreateOrUpdateResource(gomockinternal.AContext(), fakeZone, serviceName).Return(nil, nil) 323 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink1, serviceName).Return(nil, nil) 324 l.CreateOrUpdateResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(nil, nil) 325 r.CreateOrUpdateResource(gomockinternal.AContext(), fakeRecord1, serviceName).Return(nil, errFake) 326 s.UpdatePutStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, nil) 327 s.UpdatePutStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, nil) 328 s.UpdatePutStatus(infrav1.PrivateDNSRecordReadyCondition, serviceName, errFake) 329 }, 330 }, 331 } 332 333 for _, tc := range testcases { 334 tc := tc 335 t.Run(tc.name, func(t *testing.T) { 336 g := NewWithT(t) 337 338 t.Parallel() 339 mockCtrl := gomock.NewController(t) 340 defer mockCtrl.Finish() 341 scopeMock := mock_privatedns.NewMockScope(mockCtrl) 342 zoneReconcilerMock := mock_async.NewMockReconciler(mockCtrl) 343 vnetLinkReconcilerMock := mock_async.NewMockReconciler(mockCtrl) 344 recordReconcilerMock := mock_async.NewMockReconciler(mockCtrl) 345 tagsGetterMock := mock_async.NewMockTagsGetter(mockCtrl) 346 347 tc.expect(scopeMock.EXPECT(), zoneReconcilerMock.EXPECT(), vnetLinkReconcilerMock.EXPECT(), recordReconcilerMock.EXPECT(), tagsGetterMock.EXPECT()) 348 349 s := &Service{ 350 Scope: scopeMock, 351 zoneReconciler: zoneReconcilerMock, 352 vnetLinkReconciler: vnetLinkReconcilerMock, 353 recordReconciler: recordReconcilerMock, 354 TagsGetter: tagsGetterMock, 355 } 356 357 err := s.Reconcile(context.TODO()) 358 if tc.expectedError != "" { 359 g.Expect(err).To(HaveOccurred()) 360 g.Expect(err).To(MatchError(tc.expectedError)) 361 } else { 362 g.Expect(err).NotTo(HaveOccurred()) 363 } 364 }) 365 } 366 } 367 368 func TestDeletePrivateDNS(t *testing.T) { 369 testcases := []struct { 370 name string 371 expectedError string 372 expect func(s *mock_privatedns.MockScopeMockRecorder, linkReconciler, zoneReconciler *mock_async.MockReconcilerMockRecorder, tagsGetter *mock_async.MockTagsGetterMockRecorder) 373 }{ 374 { 375 name: "no private dns", 376 expectedError: "", 377 expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 378 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 379 s.PrivateDNSSpec().Return(nil, nil, nil) 380 }, 381 }, 382 { 383 name: "dns and links deletion succeeds", 384 expectedError: "", 385 expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 386 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 387 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 388 389 s.SubscriptionID().Return("123") 390 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(managedTags, nil) 391 s.ClusterName().Return(clusterName) 392 393 lr.DeleteResource(gomockinternal.AContext(), fakeLink1, serviceName).Return(nil) 394 395 s.SubscriptionID().Return("123") 396 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(managedTags, nil) 397 s.ClusterName().Return(clusterName) 398 399 lr.DeleteResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(nil) 400 401 s.SubscriptionID().Return("123") 402 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(managedTags, nil) 403 s.ClusterName().Return(clusterName) 404 405 zr.DeleteResource(gomockinternal.AContext(), fakeZone, serviceName).Return(nil) 406 s.UpdateDeleteStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, nil) 407 s.UpdateDeleteStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, nil) 408 s.UpdateDeleteStatus(infrav1.PrivateDNSRecordReadyCondition, serviceName, nil) 409 }, 410 }, 411 { 412 name: "skips if zone and links are unmanaged", 413 expectedError: "", 414 expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 415 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 416 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 417 418 s.SubscriptionID().Return("123") 419 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(armresources.TagsResource{}, nil) 420 s.ClusterName().Return(clusterName) 421 422 s.SubscriptionID().Return("123") 423 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(armresources.TagsResource{}, nil) 424 s.ClusterName().Return(clusterName) 425 426 s.SubscriptionID().Return("123") 427 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(armresources.TagsResource{}, nil) 428 s.ClusterName().Return(clusterName) 429 }, 430 }, 431 { 432 name: "skips if unmanaged, but deletes the next resource if it is managed", 433 expectedError: "", 434 expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 435 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 436 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 437 438 s.SubscriptionID().Return("123") 439 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(armresources.TagsResource{}, nil) 440 s.ClusterName().Return(clusterName) 441 442 s.SubscriptionID().Return("123") 443 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(managedTags, nil) 444 s.ClusterName().Return(clusterName) 445 lr.DeleteResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(nil) 446 447 s.SubscriptionID().Return("123") 448 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(managedTags, nil) 449 s.ClusterName().Return(clusterName) 450 451 zr.DeleteResource(gomockinternal.AContext(), fakeZone, serviceName).Return(nil) 452 s.UpdateDeleteStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, nil) 453 s.UpdateDeleteStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, nil) 454 s.UpdateDeleteStatus(infrav1.PrivateDNSRecordReadyCondition, serviceName, nil) 455 }, 456 }, 457 { 458 name: "link1 is deleted, link2 is long running. It returns not done error", 459 expectedError: "operation type resourceType on Azure resource my-rg/resourceName is not done", 460 expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 461 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 462 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}) 463 464 s.SubscriptionID().Return("123") 465 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(managedTags, nil) 466 s.ClusterName().Return(clusterName) 467 468 lr.DeleteResource(gomockinternal.AContext(), fakeLink1, serviceName).Return(notDoneError) 469 470 s.SubscriptionID().Return("123") 471 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(managedTags, nil) 472 s.ClusterName().Return(clusterName) 473 474 lr.DeleteResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(nil) 475 s.UpdateDeleteStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, notDoneError) 476 }, 477 }, 478 { 479 name: "link1 deletion fails and link2 is long running, returns the more pressing error", 480 expectedError: "this is an error", 481 expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 482 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 483 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}) 484 485 s.SubscriptionID().Return("123") 486 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(managedTags, nil) 487 s.ClusterName().Return(clusterName) 488 489 lr.DeleteResource(gomockinternal.AContext(), fakeLink1, serviceName).Return(errFake) 490 491 s.SubscriptionID().Return("123") 492 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(managedTags, nil) 493 s.ClusterName().Return(clusterName) 494 495 lr.DeleteResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(notDoneError) 496 s.UpdateDeleteStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, errFake) 497 }, 498 }, 499 { 500 name: "links are deleted, zone is long running", 501 expectedError: "operation type resourceType on Azure resource my-rg/resourceName is not done", 502 expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 503 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 504 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 505 506 s.SubscriptionID().Return("123") 507 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(managedTags, nil) 508 s.ClusterName().Return(clusterName) 509 510 lr.DeleteResource(gomockinternal.AContext(), fakeLink1, serviceName).Return(nil) 511 512 s.SubscriptionID().Return("123") 513 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(managedTags, nil) 514 s.ClusterName().Return(clusterName) 515 516 lr.DeleteResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(nil) 517 518 s.SubscriptionID().Return("123") 519 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(managedTags, nil) 520 s.ClusterName().Return(clusterName) 521 522 zr.DeleteResource(gomockinternal.AContext(), fakeZone, serviceName).Return(notDoneError) 523 524 s.UpdateDeleteStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, nil) 525 s.UpdateDeleteStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, notDoneError) 526 s.UpdateDeleteStatus(infrav1.PrivateDNSRecordReadyCondition, serviceName, notDoneError) 527 }, 528 }, 529 { 530 name: "links are deleted, zone deletion fails with error", 531 expectedError: "this is an error", 532 expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { 533 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 534 s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) 535 536 s.SubscriptionID().Return("123") 537 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink1.ResourceGroupName(), fakeLink1.OwnerResourceName(), fakeLink1.ResourceName())).Return(managedTags, nil) 538 s.ClusterName().Return(clusterName) 539 540 lr.DeleteResource(gomockinternal.AContext(), fakeLink1, serviceName).Return(nil) 541 542 s.SubscriptionID().Return("123") 543 tg.GetAtScope(gomockinternal.AContext(), azure.VirtualNetworkLinkID("123", fakeLink2.ResourceGroupName(), fakeLink2.OwnerResourceName(), fakeLink2.ResourceName())).Return(managedTags, nil) 544 s.ClusterName().Return(clusterName) 545 546 lr.DeleteResource(gomockinternal.AContext(), fakeLink2, serviceName).Return(nil) 547 548 s.SubscriptionID().Return("123") 549 tg.GetAtScope(gomockinternal.AContext(), azure.PrivateDNSZoneID("123", fakeZone.ResourceGroupName(), fakeZone.ResourceName())).Return(managedTags, nil) 550 s.ClusterName().Return(clusterName) 551 552 zr.DeleteResource(gomockinternal.AContext(), fakeZone, serviceName).Return(errFake) 553 554 s.UpdateDeleteStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, nil) 555 s.UpdateDeleteStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, errFake) 556 s.UpdateDeleteStatus(infrav1.PrivateDNSRecordReadyCondition, serviceName, errFake) 557 }, 558 }, 559 } 560 561 for _, tc := range testcases { 562 tc := tc 563 t.Run(tc.name, func(t *testing.T) { 564 g := NewWithT(t) 565 566 t.Parallel() 567 mockCtrl := gomock.NewController(t) 568 defer mockCtrl.Finish() 569 scopeMock := mock_privatedns.NewMockScope(mockCtrl) 570 vnetLinkReconcilerMock := mock_async.NewMockReconciler(mockCtrl) 571 zoneReconcilerMock := mock_async.NewMockReconciler(mockCtrl) 572 tagsGetterMock := mock_async.NewMockTagsGetter(mockCtrl) 573 574 tc.expect(scopeMock.EXPECT(), vnetLinkReconcilerMock.EXPECT(), zoneReconcilerMock.EXPECT(), tagsGetterMock.EXPECT()) 575 576 s := &Service{ 577 Scope: scopeMock, 578 zoneReconciler: zoneReconcilerMock, 579 vnetLinkReconciler: vnetLinkReconcilerMock, 580 TagsGetter: tagsGetterMock, 581 } 582 583 err := s.Delete(context.TODO()) 584 if tc.expectedError != "" { 585 g.Expect(err).To(HaveOccurred()) 586 g.Expect(err).To(MatchError(tc.expectedError)) 587 } else { 588 g.Expect(err).NotTo(HaveOccurred()) 589 } 590 }) 591 } 592 }