sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/privatedns/privatedns.go (about) 1 /* 2 Copyright 2019 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 22 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns" 23 "github.com/pkg/errors" 24 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 25 "sigs.k8s.io/cluster-api-provider-azure/azure" 26 "sigs.k8s.io/cluster-api-provider-azure/azure/converters" 27 "sigs.k8s.io/cluster-api-provider-azure/azure/services/async" 28 "sigs.k8s.io/cluster-api-provider-azure/azure/services/tags" 29 "sigs.k8s.io/cluster-api-provider-azure/util/tele" 30 ) 31 32 const serviceName = "privatedns" 33 34 // Scope defines the scope interface for a private dns service. 35 type Scope interface { 36 azure.ClusterDescriber 37 azure.Authorizer 38 azure.AsyncStatusUpdater 39 PrivateDNSSpec() (zoneSpec azure.ResourceSpecGetter, linksSpec, recordsSpec []azure.ResourceSpecGetter) 40 } 41 42 // Service provides operations on Azure resources. 43 type Service struct { 44 Scope Scope 45 TagsGetter async.TagsGetter 46 zoneReconciler async.Reconciler 47 vnetLinkReconciler async.Reconciler 48 recordReconciler async.Reconciler 49 } 50 51 // New creates a new private dns service. 52 func New(scope Scope) (*Service, error) { 53 zoneClient, err := newPrivateZonesClient(scope, scope.DefaultedAzureCallTimeout()) 54 if err != nil { 55 return nil, err 56 } 57 vnetLinkClient, err := newVirtualNetworkLinksClient(scope, scope.DefaultedAzureCallTimeout()) 58 if err != nil { 59 return nil, err 60 } 61 recordSetsClient, err := newRecordSetsClient(scope) 62 if err != nil { 63 return nil, err 64 } 65 tagsClient, err := tags.NewClient(scope) 66 if err != nil { 67 return nil, err 68 } 69 return &Service{ 70 Scope: scope, 71 TagsGetter: tagsClient, 72 zoneReconciler: async.New[armprivatedns.PrivateZonesClientCreateOrUpdateResponse, 73 armprivatedns.PrivateZonesClientDeleteResponse](scope, zoneClient, zoneClient), 74 vnetLinkReconciler: async.New[armprivatedns.VirtualNetworkLinksClientCreateOrUpdateResponse, 75 armprivatedns.VirtualNetworkLinksClientDeleteResponse](scope, vnetLinkClient, vnetLinkClient), 76 recordReconciler: async.New[armprivatedns.RecordSetsClientCreateOrUpdateResponse, 77 armprivatedns.RecordSetsClientDeleteResponse](scope, recordSetsClient, recordSetsClient), 78 }, nil 79 } 80 81 // Name returns the service name. 82 func (s *Service) Name() string { 83 return serviceName 84 } 85 86 // Reconcile creates or updates the private zone, links it to the vnet, and creates DNS records. 87 func (s *Service) Reconcile(ctx context.Context) error { 88 ctx, _, done := tele.StartSpanWithLogger(ctx, "privatedns.Service.Reconcile") 89 defer done() 90 91 ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) 92 defer cancel() 93 94 zoneSpec, links, records := s.Scope.PrivateDNSSpec() 95 if zoneSpec == nil { 96 return nil 97 } 98 99 managed, err := s.reconcileZone(ctx, zoneSpec) 100 if managed { 101 s.Scope.UpdatePutStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, err) 102 } 103 if err != nil { 104 return err 105 } 106 107 managed, err = s.reconcileLinks(ctx, links) 108 if managed { 109 s.Scope.UpdatePutStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, err) 110 } 111 if err != nil { 112 return err 113 } 114 115 err = s.reconcileRecords(ctx, records) 116 s.Scope.UpdatePutStatus(infrav1.PrivateDNSRecordReadyCondition, serviceName, err) 117 return err 118 } 119 120 // Delete deletes the private zone and vnet links. 121 func (s *Service) Delete(ctx context.Context) error { 122 ctx, _, done := tele.StartSpanWithLogger(ctx, "privatedns.Service.Delete") 123 defer done() 124 125 ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) 126 defer cancel() 127 128 zoneSpec, links, _ := s.Scope.PrivateDNSSpec() 129 if zoneSpec == nil { 130 return nil 131 } 132 133 managed, err := s.deleteLinks(ctx, links) 134 if managed { 135 s.Scope.UpdateDeleteStatus(infrav1.PrivateDNSLinkReadyCondition, serviceName, err) 136 } 137 if err != nil { 138 return err 139 } 140 141 managed, err = s.deleteZone(ctx, zoneSpec) 142 if managed { 143 s.Scope.UpdateDeleteStatus(infrav1.PrivateDNSZoneReadyCondition, serviceName, err) 144 s.Scope.UpdateDeleteStatus(infrav1.PrivateDNSRecordReadyCondition, serviceName, err) 145 } 146 147 return err 148 } 149 150 // isVnetLinkManaged returns true if the vnet link has an owned tag with the cluster name as value, 151 // meaning that the vnet link lifecycle is managed. 152 func (s *Service) isVnetLinkManaged(ctx context.Context, spec azure.ResourceSpecGetter) (bool, error) { 153 scope := azure.VirtualNetworkLinkID(s.Scope.SubscriptionID(), spec.ResourceGroupName(), spec.OwnerResourceName(), spec.ResourceName()) 154 result, err := s.TagsGetter.GetAtScope(ctx, scope) 155 if err != nil { 156 return false, err 157 } 158 159 tagsMap := make(map[string]*string) 160 if result.Properties != nil && result.Properties.Tags != nil { 161 tagsMap = result.Properties.Tags 162 } 163 164 tags := converters.MapToTags(tagsMap) 165 return tags.HasOwned(s.Scope.ClusterName()), nil 166 } 167 168 // IsManaged returns true if the private DNS has an owned tag with the cluster name as value, 169 // meaning that the DNS lifecycle is managed. 170 func (s *Service) IsManaged(ctx context.Context) (bool, error) { 171 zoneSpec, _, _ := s.Scope.PrivateDNSSpec() 172 if zoneSpec == nil { 173 return false, errors.Errorf("no private dns zone spec available") 174 } 175 176 scope := azure.PrivateDNSZoneID(s.Scope.SubscriptionID(), zoneSpec.ResourceGroupName(), zoneSpec.ResourceName()) 177 result, err := s.TagsGetter.GetAtScope(ctx, scope) 178 if err != nil { 179 return false, err 180 } 181 182 tagsMap := make(map[string]*string) 183 if result.Properties != nil && result.Properties.Tags != nil { 184 tagsMap = result.Properties.Tags 185 } 186 187 tags := converters.MapToTags(tagsMap) 188 return tags.HasOwned(s.Scope.ClusterName()), nil 189 }