diff --git a/azure/services/privatedns/client.go b/azure/services/privatedns/client.go index 8df5ea8b710..f7bb9b3767f 100644 --- a/azure/services/privatedns/client.go +++ b/azure/services/privatedns/client.go @@ -31,6 +31,7 @@ type client interface { GetZone(context.Context, string, string) (privatedns.PrivateZone, error) CreateOrUpdateZone(context.Context, string, string, privatedns.PrivateZone) error DeleteZone(context.Context, string, string) error + GetLink(context.Context, string, string, string) (privatedns.VirtualNetworkLink, error) CreateOrUpdateLink(context.Context, string, string, string, privatedns.VirtualNetworkLink) error DeleteLink(context.Context, string, string, string) error CreateOrUpdateRecordSet(context.Context, string, string, privatedns.RecordType, string, privatedns.RecordSet) error @@ -119,6 +120,17 @@ func (ac *azureClient) DeleteZone(ctx context.Context, resourceGroupName, name s return err } +// GetLink returns a vnet link. +func (ac *azureClient) GetLink(ctx context.Context, resourceGroupName, zoneName, vnetLinkName string) (privatedns.VirtualNetworkLink, error) { + ctx, _, done := tele.StartSpanWithLogger(ctx, "privatedns.AzureClient.GetZone") + defer done() + gotVnetLink, err := ac.vnetlinks.Get(ctx, resourceGroupName, zoneName, vnetLinkName) + if err != nil { + return privatedns.VirtualNetworkLink{}, err + } + return gotVnetLink, nil +} + // CreateOrUpdateLink creates or updates a virtual network link to the specified Private DNS zone. func (ac *azureClient) CreateOrUpdateLink(ctx context.Context, resourceGroupName, privateZoneName, name string, link privatedns.VirtualNetworkLink) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "privatedns.AzureClient.CreateOrUpdateLink") diff --git a/azure/services/privatedns/mock_privatedns/client_mock.go b/azure/services/privatedns/mock_privatedns/client_mock.go index fbf8f62b2c7..cf9d71ec70c 100644 --- a/azure/services/privatedns/mock_privatedns/client_mock.go +++ b/azure/services/privatedns/mock_privatedns/client_mock.go @@ -135,6 +135,21 @@ func (mr *MockclientMockRecorder) DeleteZone(arg0, arg1, arg2 interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteZone", reflect.TypeOf((*Mockclient)(nil).DeleteZone), arg0, arg1, arg2) } +// GetLink mocks base method. +func (m *Mockclient) GetLink(arg0 context.Context, arg1, arg2, arg3 string) (privatedns.VirtualNetworkLink, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLink", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(privatedns.VirtualNetworkLink) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLink indicates an expected call of GetLink. +func (mr *MockclientMockRecorder) GetLink(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLink", reflect.TypeOf((*Mockclient)(nil).GetLink), arg0, arg1, arg2, arg3) +} + // GetZone mocks base method. func (m *Mockclient) GetZone(arg0 context.Context, arg1, arg2 string) (privatedns.PrivateZone, error) { m.ctrl.T.Helper() diff --git a/azure/services/privatedns/privatedns.go b/azure/services/privatedns/privatedns.go index c8dfc4e9ee5..f1a43141fc9 100644 --- a/azure/services/privatedns/privatedns.go +++ b/azure/services/privatedns/privatedns.go @@ -59,6 +59,20 @@ func (s *Service) Reconcile(ctx context.Context) error { zoneSpec := s.Scope.PrivateDNSSpec() if zoneSpec != nil { + // Skip the reconciliation of private DNS zone which is not managed by capz. + isManaged, err := s.isPrivateDNSManaged(ctx, s.Scope.ResourceGroup(), zoneSpec.ZoneName) + if err != nil && !azure.ResourceNotFound(err) { + return errors.Wrapf(err, "could not get private DNS zone state of %s in resource group %s", zoneSpec.ZoneName, s.Scope.ResourceGroup()) + } + // If resource is not found, it means it should be created and hence setting isVnetLinkManaged to true + // will allow the reconciliation to continue + if err != nil && azure.ResourceNotFound(err) { + isManaged = true + } + if !isManaged { + s.Scope.V(2).Info("Skipping reconciliation of unmanaged private DNS zone", "private DNS", zoneSpec.ZoneName) + return nil + } // Create the private DNS zone. s.Scope.V(2).Info("creating private DNS zone", "private dns zone", zoneSpec.ZoneName) pDNS := privatedns.PrivateZone{ @@ -69,13 +83,27 @@ func (s *Service) Reconcile(ctx context.Context) error { Additional: s.Scope.AdditionalTags(), })), } - err := s.client.CreateOrUpdateZone(ctx, s.Scope.ResourceGroup(), zoneSpec.ZoneName, pDNS) + err = s.client.CreateOrUpdateZone(ctx, s.Scope.ResourceGroup(), zoneSpec.ZoneName, pDNS) if err != nil { return errors.Wrapf(err, "failed to create private DNS zone %s", zoneSpec.ZoneName) } s.Scope.V(2).Info("successfully created private DNS zone", "private dns zone", zoneSpec.ZoneName) for _, linkSpec := range zoneSpec.Links { + // If the virtual network link is not managed by capz, skip its reconciliation + isVnetLinkManaged, err := s.isVnetLinkManaged(ctx, s.Scope.ResourceGroup(), zoneSpec.ZoneName, linkSpec.LinkName) + if err != nil && !azure.ResourceNotFound(err) { + return errors.Wrapf(err, "could not get vnet link state of %s in resource group %s", zoneSpec.ZoneName, s.Scope.ResourceGroup()) + } + // If resource is not found, it means it should be created and hence setting isVnetLinkManaged to true + // will allow the reconciliation to continue + if err != nil && azure.ResourceNotFound(err) { + isVnetLinkManaged = true + } + if !isVnetLinkManaged { + s.Scope.V(2).Info("Skipping vnet link reconciliation for unmanaged vnet link", "vnet link", linkSpec.LinkName, "private dns zone", zoneSpec.ZoneName) + continue + } // Link each virtual network. s.Scope.V(2).Info("creating a virtual network link", "virtual network", linkSpec.VNetName, "private dns zone", zoneSpec.ZoneName) link := privatedns.VirtualNetworkLink{ @@ -86,6 +114,11 @@ func (s *Service) Reconcile(ctx context.Context) error { RegistrationEnabled: to.BoolPtr(false), }, Location: to.StringPtr(azure.Global), + Tags: converters.TagsToMap(infrav1.Build(infrav1.BuildParams{ + ClusterName: s.Scope.ClusterName(), + Lifecycle: infrav1.ResourceLifecycleOwned, + Additional: s.Scope.AdditionalTags(), + })), } err = s.client.CreateOrUpdateLink(ctx, s.Scope.ResourceGroup(), zoneSpec.ZoneName, linkSpec.LinkName, link) if err != nil { @@ -122,33 +155,42 @@ func (s *Service) Reconcile(ctx context.Context) error { return nil } -// Delete deletes the private zone. +// Delete deletes the private zone and vnet links. func (s *Service) Delete(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "privatedns.Service.Delete") defer done() zoneSpec := s.Scope.PrivateDNSSpec() if zoneSpec != nil { - isManaged, err := s.isPrivateDNSManaged(ctx, s.Scope.ResourceGroup(), zoneSpec.ZoneName) - if err != nil && !azure.ResourceNotFound(err) { - return errors.Wrapf(err, "could not get private DNS zone state of %s in resource group %s", zoneSpec.ZoneName, s.Scope.ResourceGroup()) - } - - if !isManaged { - s.Scope.V(2).Info("Skipping private DNS zone deletion for unmanaged private DNS zone", "private DNS", zoneSpec.ZoneName) - return nil - } - for _, linkSpec := range zoneSpec.Links { // Remove each virtual network link. + // If the virtual network link is not managed by capz, skip its removal + isVnetLinkManaged, err := s.isVnetLinkManaged(ctx, s.Scope.ResourceGroup(), zoneSpec.ZoneName, linkSpec.LinkName) + if err != nil && !azure.ResourceNotFound(err) { + return errors.Wrapf(err, "could not get vnet link state of %s in resource group %s", zoneSpec.ZoneName, s.Scope.ResourceGroup()) + } + if !isVnetLinkManaged { + s.Scope.V(2).Info("Skipping vnet link deletion for unmanaged vnet link", "vnet link", linkSpec.LinkName, "private dns zone", zoneSpec.ZoneName) + continue + } s.Scope.V(2).Info("removing virtual network link", "virtual network", linkSpec.VNetName, "private dns zone", zoneSpec.ZoneName) - err := s.client.DeleteLink(ctx, s.Scope.ResourceGroup(), zoneSpec.ZoneName, linkSpec.LinkName) + err = s.client.DeleteLink(ctx, s.Scope.ResourceGroup(), zoneSpec.ZoneName, linkSpec.LinkName) if err != nil && !azure.ResourceNotFound(err) { return errors.Wrapf(err, "failed to delete virtual network link %s with zone %s in resource group %s", linkSpec.VNetName, zoneSpec.ZoneName, s.Scope.ResourceGroup()) } } // Delete the private DNS zone, which also deletes all records. + // Skip the deletion of private DNS zone which is not managed by capz. + isManaged, err := s.isPrivateDNSManaged(ctx, s.Scope.ResourceGroup(), zoneSpec.ZoneName) + if err != nil && !azure.ResourceNotFound(err) { + return errors.Wrapf(err, "could not get private DNS zone state of %s in resource group %s", zoneSpec.ZoneName, s.Scope.ResourceGroup()) + } + + if !isManaged { + s.Scope.V(2).Info("Skipping private DNS zone deletion for unmanaged private DNS zone", "private DNS", zoneSpec.ZoneName) + return nil + } s.Scope.V(2).Info("deleting private dns zone", "private dns zone", zoneSpec.ZoneName) err = s.client.DeleteZone(ctx, s.Scope.ResourceGroup(), zoneSpec.ZoneName) if err != nil && azure.ResourceNotFound(err) { @@ -173,3 +215,14 @@ func (s *Service) isPrivateDNSManaged(ctx context.Context, resourceGroup, zoneNa tags := converters.MapToTags(gotZone.Tags) return tags.HasOwned(s.Scope.ClusterName()), nil } + +// isVnetLinkManaged returns true if the vnet link has an owned tag with the cluster name as value, +// meaning that the vnet link lifecycle is managed. +func (s *Service) isVnetLinkManaged(ctx context.Context, resourceGroupName, zoneName, vnetLinkName string) (bool, error) { + gotZone, err := s.client.GetLink(ctx, resourceGroupName, zoneName, vnetLinkName) + if err != nil { + return false, err + } + tags := converters.MapToTags(gotZone.Tags) + return tags.HasOwned(s.Scope.ClusterName()), nil +} diff --git a/azure/services/privatedns/privatedns_test.go b/azure/services/privatedns/privatedns_test.go index 81131f22f99..35ac56bc7e6 100644 --- a/azure/services/privatedns/privatedns_test.go +++ b/azure/services/privatedns/privatedns_test.go @@ -73,12 +73,16 @@ func TestReconcilePrivateDNS(t *testing.T) { s.ClusterName().AnyTimes().Return("my-cluster") s.AdditionalTags().AnyTimes().Return(infrav1.Tags{}) s.SubscriptionID().Return("123") + m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone"). + Return(privatedns.PrivateZone{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateZone(gomockinternal.AContext(), "my-rg", "my-dns-zone", privatedns.PrivateZone{ Location: to.StringPtr(azure.Global), Tags: map[string]*string{ "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), }, }) + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link"). + Return(privatedns.VirtualNetworkLink{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link", privatedns.VirtualNetworkLink{ VirtualNetworkLinkProperties: &privatedns.VirtualNetworkLinkProperties{ VirtualNetwork: &privatedns.SubResource{ @@ -87,6 +91,9 @@ func TestReconcilePrivateDNS(t *testing.T) { RegistrationEnabled: to.BoolPtr(false), }, Location: to.StringPtr(azure.Global), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + }, }) m.CreateOrUpdateRecordSet(gomockinternal.AContext(), "my-rg", "my-dns-zone", privatedns.A, "hostname-1", privatedns.RecordSet{ RecordSetProperties: &privatedns.RecordSetProperties{ @@ -130,12 +137,16 @@ func TestReconcilePrivateDNS(t *testing.T) { s.ClusterName().AnyTimes().Return("my-cluster") s.AdditionalTags().AnyTimes().Return(infrav1.Tags{}) s.SubscriptionID().AnyTimes().Return("123") + m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone"). + Return(privatedns.PrivateZone{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateZone(gomockinternal.AContext(), "my-rg", "my-dns-zone", privatedns.PrivateZone{ Location: to.StringPtr(azure.Global), Tags: map[string]*string{ "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), }, }) + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1"). + Return(privatedns.VirtualNetworkLink{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1", privatedns.VirtualNetworkLink{ VirtualNetworkLinkProperties: &privatedns.VirtualNetworkLinkProperties{ VirtualNetwork: &privatedns.SubResource{ @@ -144,7 +155,12 @@ func TestReconcilePrivateDNS(t *testing.T) { RegistrationEnabled: to.BoolPtr(false), }, Location: to.StringPtr(azure.Global), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + }, }) + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2"). + Return(privatedns.VirtualNetworkLink{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2", privatedns.VirtualNetworkLink{ VirtualNetworkLinkProperties: &privatedns.VirtualNetworkLinkProperties{ VirtualNetwork: &privatedns.SubResource{ @@ -153,6 +169,9 @@ func TestReconcilePrivateDNS(t *testing.T) { RegistrationEnabled: to.BoolPtr(false), }, Location: to.StringPtr(azure.Global), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + }, }) m.CreateOrUpdateRecordSet(gomockinternal.AContext(), "my-rg", "my-dns-zone", privatedns.A, "hostname-1", privatedns.RecordSet{ RecordSetProperties: &privatedns.RecordSetProperties{ @@ -191,12 +210,16 @@ func TestReconcilePrivateDNS(t *testing.T) { s.ClusterName().AnyTimes().Return("my-cluster") s.AdditionalTags().AnyTimes().Return(infrav1.Tags{}) s.SubscriptionID().AnyTimes().Return("123") + m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone"). + Return(privatedns.PrivateZone{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateZone(gomockinternal.AContext(), "my-rg", "my-dns-zone", privatedns.PrivateZone{ Location: to.StringPtr(azure.Global), Tags: map[string]*string{ "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), }, }) + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link"). + Return(privatedns.VirtualNetworkLink{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link", privatedns.VirtualNetworkLink{ VirtualNetworkLinkProperties: &privatedns.VirtualNetworkLinkProperties{ VirtualNetwork: &privatedns.SubResource{ @@ -205,6 +228,9 @@ func TestReconcilePrivateDNS(t *testing.T) { RegistrationEnabled: to.BoolPtr(false), }, Location: to.StringPtr(azure.Global), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + }, }) m.CreateOrUpdateRecordSet(gomockinternal.AContext(), "my-rg", "my-dns-zone", privatedns.AAAA, "hostname-2", privatedns.RecordSet{ RecordSetProperties: &privatedns.RecordSetProperties{ @@ -248,12 +274,16 @@ func TestReconcilePrivateDNS(t *testing.T) { s.ClusterName().AnyTimes().Return("my-cluster") s.AdditionalTags().AnyTimes().Return(infrav1.Tags{}) s.SubscriptionID().AnyTimes().Return("123") + m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone"). + Return(privatedns.PrivateZone{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateZone(gomockinternal.AContext(), "my-rg", "my-dns-zone", privatedns.PrivateZone{ Location: to.StringPtr(azure.Global), Tags: map[string]*string{ "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), }, }) + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1"). + Return(privatedns.VirtualNetworkLink{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1", privatedns.VirtualNetworkLink{ VirtualNetworkLinkProperties: &privatedns.VirtualNetworkLinkProperties{ VirtualNetwork: &privatedns.SubResource{ @@ -262,7 +292,12 @@ func TestReconcilePrivateDNS(t *testing.T) { RegistrationEnabled: to.BoolPtr(false), }, Location: to.StringPtr(azure.Global), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + }, }) + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2"). + Return(privatedns.VirtualNetworkLink{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2", privatedns.VirtualNetworkLink{ VirtualNetworkLinkProperties: &privatedns.VirtualNetworkLinkProperties{ VirtualNetwork: &privatedns.SubResource{ @@ -271,6 +306,9 @@ func TestReconcilePrivateDNS(t *testing.T) { RegistrationEnabled: to.BoolPtr(false), }, Location: to.StringPtr(azure.Global), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + }, }) m.CreateOrUpdateRecordSet(gomockinternal.AContext(), "my-rg", "my-dns-zone", privatedns.AAAA, "hostname-2", privatedns.RecordSet{ RecordSetProperties: &privatedns.RecordSetProperties{ @@ -309,12 +347,16 @@ func TestReconcilePrivateDNS(t *testing.T) { s.ClusterName().AnyTimes().Return("my-cluster") s.AdditionalTags().AnyTimes().Return(infrav1.Tags{}) s.SubscriptionID().AnyTimes().Return("123") + m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone"). + Return(privatedns.PrivateZone{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateZone(gomockinternal.AContext(), "my-rg", "my-dns-zone", privatedns.PrivateZone{ Location: to.StringPtr(azure.Global), Tags: map[string]*string{ "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), }, }) + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link"). + Return(privatedns.VirtualNetworkLink{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link", privatedns.VirtualNetworkLink{ VirtualNetworkLinkProperties: &privatedns.VirtualNetworkLinkProperties{ VirtualNetwork: &privatedns.SubResource{ @@ -323,6 +365,9 @@ func TestReconcilePrivateDNS(t *testing.T) { RegistrationEnabled: to.BoolPtr(false), }, Location: to.StringPtr(azure.Global), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + }, }).Return(autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 500}, "Internal Server Error")) }, }, @@ -361,12 +406,16 @@ func TestReconcilePrivateDNS(t *testing.T) { s.ClusterName().AnyTimes().Return("my-cluster") s.AdditionalTags().AnyTimes().Return(infrav1.Tags{}) s.SubscriptionID().AnyTimes().Return("123") + m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone"). + Return(privatedns.PrivateZone{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateZone(gomockinternal.AContext(), "my-rg", "my-dns-zone", privatedns.PrivateZone{ Location: to.StringPtr(azure.Global), Tags: map[string]*string{ "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), }, }) + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1"). + Return(privatedns.VirtualNetworkLink{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1", privatedns.VirtualNetworkLink{ VirtualNetworkLinkProperties: &privatedns.VirtualNetworkLinkProperties{ VirtualNetwork: &privatedns.SubResource{ @@ -375,7 +424,12 @@ func TestReconcilePrivateDNS(t *testing.T) { RegistrationEnabled: to.BoolPtr(false), }, Location: to.StringPtr(azure.Global), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + }, }) + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2"). + Return(privatedns.VirtualNetworkLink{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.CreateOrUpdateLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2", privatedns.VirtualNetworkLink{ VirtualNetworkLinkProperties: &privatedns.VirtualNetworkLinkProperties{ VirtualNetwork: &privatedns.SubResource{ @@ -384,6 +438,9 @@ func TestReconcilePrivateDNS(t *testing.T) { RegistrationEnabled: to.BoolPtr(false), }, Location: to.StringPtr(azure.Global), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + }, }).Return(autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 500}, "Internal Server Error")) }, }, @@ -433,7 +490,7 @@ func TestDeletePrivateDNS(t *testing.T) { }, }, { - name: "delete the dns zone managed by capz", + name: "delete the dns zone and vnet links managed by capz", expectedError: "", expect: func(s *mock_privatedns.MockScopeMockRecorder, m *mock_privatedns.MockclientMockRecorder) { s.V(gomock.AssignableToTypeOf(2)).AnyTimes().Return(klogr.New()) @@ -455,6 +512,14 @@ func TestDeletePrivateDNS(t *testing.T) { }) s.ResourceGroup().AnyTimes().Return("my-rg") s.ClusterName().AnyTimes().Return("my-cluster") + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-link"), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + "foo": to.StringPtr("bar"), + }, + }, nil) + m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link") m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone").Return(privatedns.PrivateZone{ Name: to.StringPtr("my-dns-zone"), Tags: map[string]*string{ @@ -462,12 +527,11 @@ func TestDeletePrivateDNS(t *testing.T) { "foo": to.StringPtr("bar"), }, }, nil) - m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link") m.DeleteZone(gomockinternal.AContext(), "my-rg", "my-dns-zone") }, }, { - name: "skip unmanaged private dns zone deletion", + name: "skip unmanaged private dns zone and vnet link deletion", expectedError: "", expect: func(s *mock_privatedns.MockScopeMockRecorder, m *mock_privatedns.MockclientMockRecorder) { s.V(gomock.AssignableToTypeOf(2)).AnyTimes().Return(klogr.New()) @@ -489,6 +553,7 @@ func TestDeletePrivateDNS(t *testing.T) { }) s.ResourceGroup().AnyTimes().Return("my-rg") s.ClusterName().AnyTimes().Return("my-cluster") + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link") m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone") }, }, @@ -525,16 +590,37 @@ func TestDeletePrivateDNS(t *testing.T) { }) s.ResourceGroup().AnyTimes().Return("my-rg") s.ClusterName().AnyTimes().Return("my-cluster") - m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone").Return(privatedns.PrivateZone{ - Name: to.StringPtr("my-dns-zone"), + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-vnet"), Tags: map[string]*string{ "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), "foo": to.StringPtr("bar"), }, }, nil) m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1") + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-vnet"), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + "foo": to.StringPtr("bar"), + }, + }, nil) m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2") + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-3").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-vnet"), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + "foo": to.StringPtr("bar"), + }, + }, nil) m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-3") + m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone").Return(privatedns.PrivateZone{ + Name: to.StringPtr("my-dns-zone"), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + "foo": to.StringPtr("bar"), + }, + }, nil) m.DeleteZone(gomockinternal.AContext(), "my-rg", "my-dns-zone") }, }, @@ -561,6 +647,8 @@ func TestDeletePrivateDNS(t *testing.T) { }) s.ResourceGroup().AnyTimes().Return("my-rg") s.ClusterName().AnyTimes().Return("my-cluster") + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link"). + Return(privatedns.VirtualNetworkLink{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone").Return(privatedns.PrivateZone{ Name: to.StringPtr("my-dns-zone"), Tags: map[string]*string{ @@ -568,8 +656,6 @@ func TestDeletePrivateDNS(t *testing.T) { "foo": to.StringPtr("bar"), }, }, nil) - m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link"). - Return(autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) m.DeleteZone(gomockinternal.AContext(), "my-rg", "my-dns-zone") }, }, @@ -606,22 +692,36 @@ func TestDeletePrivateDNS(t *testing.T) { }) s.ResourceGroup().AnyTimes().Return("my-rg") s.ClusterName().AnyTimes().Return("my-cluster") - m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone").Return(privatedns.PrivateZone{ - Name: to.StringPtr("my-dns-zone"), + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-vnet"), Tags: map[string]*string{ "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), "foo": to.StringPtr("bar"), }, }, nil) m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1") - m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2"). - Return(autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2"). + Return(privatedns.VirtualNetworkLink{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-3").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-vnet"), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + "foo": to.StringPtr("bar"), + }, + }, nil) m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-3") + m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone").Return(privatedns.PrivateZone{ + Name: to.StringPtr("my-dns-zone"), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + "foo": to.StringPtr("bar"), + }, + }, nil) m.DeleteZone(gomockinternal.AContext(), "my-rg", "my-dns-zone") }, }, { - name: "zone already deleted", + name: "zone and all vnet links already deleted", expectedError: "", expect: func(s *mock_privatedns.MockScopeMockRecorder, m *mock_privatedns.MockclientMockRecorder) { s.V(gomock.AssignableToTypeOf(2)).AnyTimes().Return(klogr.New()) @@ -643,17 +743,10 @@ func TestDeletePrivateDNS(t *testing.T) { }) s.ResourceGroup().AnyTimes().Return("my-rg") s.ClusterName().AnyTimes().Return("my-cluster") - m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone").Return(privatedns.PrivateZone{ - Name: to.StringPtr("my-dns-zone"), - Tags: map[string]*string{ - "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), - "foo": to.StringPtr("bar"), - }, - }, nil) - m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link"). - Return(autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) - m.DeleteZone(gomockinternal.AContext(), "my-rg", "my-dns-zone"). - Return(autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link"). + Return(privatedns.VirtualNetworkLink{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) + m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone"). + Return(privatedns.PrivateZone{}, autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 404}, "Not found")) }, }, { @@ -679,8 +772,8 @@ func TestDeletePrivateDNS(t *testing.T) { }) s.ResourceGroup().AnyTimes().Return("my-rg") s.ClusterName().AnyTimes().Return("my-cluster") - m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone").Return(privatedns.PrivateZone{ - Name: to.StringPtr("my-dns-zone"), + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-vnet"), Tags: map[string]*string{ "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), "foo": to.StringPtr("bar"), @@ -723,14 +816,21 @@ func TestDeletePrivateDNS(t *testing.T) { }) s.ResourceGroup().AnyTimes().Return("my-rg") s.ClusterName().AnyTimes().Return("my-cluster") - m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone").Return(privatedns.PrivateZone{ - Name: to.StringPtr("my-dns-zone"), + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-vnet"), Tags: map[string]*string{ "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), "foo": to.StringPtr("bar"), }, }, nil) m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1") + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-vnet"), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + "foo": to.StringPtr("bar"), + }, + }, nil) m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2"). Return(autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 500}, "Internal Server Error")) }, @@ -758,6 +858,14 @@ func TestDeletePrivateDNS(t *testing.T) { }) s.ResourceGroup().AnyTimes().Return("my-rg") s.ClusterName().AnyTimes().Return("my-cluster") + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-vnet"), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + "foo": to.StringPtr("bar"), + }, + }, nil) + m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link") m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone").Return(privatedns.PrivateZone{ Name: to.StringPtr("my-dns-zone"), Tags: map[string]*string{ @@ -765,7 +873,6 @@ func TestDeletePrivateDNS(t *testing.T) { "foo": to.StringPtr("bar"), }, }, nil) - m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link") m.DeleteZone(gomockinternal.AContext(), "my-rg", "my-dns-zone"). Return(autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 500}, "Internal Server Error")) }, @@ -803,16 +910,37 @@ func TestDeletePrivateDNS(t *testing.T) { }) s.ResourceGroup().AnyTimes().Return("my-rg") s.ClusterName().AnyTimes().Return("my-cluster") - m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone").Return(privatedns.PrivateZone{ - Name: to.StringPtr("my-dns-zone"), + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-vnet"), Tags: map[string]*string{ "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), "foo": to.StringPtr("bar"), }, }, nil) m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-1") + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-vnet"), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + "foo": to.StringPtr("bar"), + }, + }, nil) m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-2") + m.GetLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-3").Return(privatedns.VirtualNetworkLink{ + Name: to.StringPtr("my-vnet"), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + "foo": to.StringPtr("bar"), + }, + }, nil) m.DeleteLink(gomockinternal.AContext(), "my-rg", "my-dns-zone", "my-link-3") + m.GetZone(gomockinternal.AContext(), "my-rg", "my-dns-zone").Return(privatedns.PrivateZone{ + Name: to.StringPtr("my-dns-zone"), + Tags: map[string]*string{ + "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": to.StringPtr("owned"), + "foo": to.StringPtr("bar"), + }, + }, nil) m.DeleteZone(gomockinternal.AContext(), "my-rg", "my-dns-zone"). Return(autorest.NewErrorWithResponse("", "", &http.Response{StatusCode: 500}, "Internal Server Error")) },