sigs.k8s.io/cluster-api-provider-azure@v1.17.0/azure/services/loadbalancers/loadbalancers.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 loadbalancers 18 19 import ( 20 "context" 21 22 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4" 23 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 24 "sigs.k8s.io/cluster-api-provider-azure/azure" 25 "sigs.k8s.io/cluster-api-provider-azure/azure/services/async" 26 "sigs.k8s.io/cluster-api-provider-azure/util/tele" 27 ) 28 29 const ( 30 serviceName = "loadbalancers" 31 httpsProbe = "HTTPSProbe" 32 httpsProbeRequestPath = "/readyz" 33 lbRuleHTTPS = "LBRuleHTTPS" 34 outboundNAT = "OutboundNATAllProtocols" 35 ) 36 37 // LBScope defines the scope interface for a load balancer service. 38 type LBScope interface { 39 azure.ClusterScoper 40 azure.AsyncStatusUpdater 41 LBSpecs() []azure.ResourceSpecGetter 42 } 43 44 // Service provides operations on Azure resources. 45 type Service struct { 46 Scope LBScope 47 async.Reconciler 48 } 49 50 // New creates a new service. 51 func New(scope LBScope) (*Service, error) { 52 client, err := newClient(scope, scope.DefaultedAzureCallTimeout()) 53 if err != nil { 54 return nil, err 55 } 56 return &Service{ 57 Scope: scope, 58 Reconciler: async.New[armnetwork.LoadBalancersClientCreateOrUpdateResponse, 59 armnetwork.LoadBalancersClientDeleteResponse](scope, client, client), 60 }, nil 61 } 62 63 // Name returns the service name. 64 func (s *Service) Name() string { 65 return serviceName 66 } 67 68 // Reconcile idempotently creates or updates a load balancer. 69 func (s *Service) Reconcile(ctx context.Context) error { 70 ctx, _, done := tele.StartSpanWithLogger(ctx, "loadbalancers.Service.Reconcile") 71 defer done() 72 73 ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) 74 defer cancel() 75 76 specs := s.Scope.LBSpecs() 77 if len(specs) == 0 { 78 return nil 79 } 80 81 // We go through the list of LBSpecs to reconcile each one, independently of the result of the previous one. 82 // If multiple errors occur, we return the most pressing one. 83 // Order of precedence (highest -> lowest) is: error that is not an operationNotDoneError (i.e. error creating) -> operationNotDoneError (i.e. creating in progress) -> no error (i.e. created) 84 var result error 85 for _, lbSpec := range specs { 86 if _, err := s.CreateOrUpdateResource(ctx, lbSpec, serviceName); err != nil { 87 if !azure.IsOperationNotDoneError(err) || result == nil { 88 result = err 89 } 90 } 91 } 92 93 s.Scope.UpdatePutStatus(infrav1.LoadBalancersReadyCondition, serviceName, result) 94 return result 95 } 96 97 // Delete deletes the public load balancer with the provided name. 98 func (s *Service) Delete(ctx context.Context) error { 99 ctx, _, done := tele.StartSpanWithLogger(ctx, "loadbalancers.Service.Delete") 100 defer done() 101 102 ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) 103 defer cancel() 104 105 specs := s.Scope.LBSpecs() 106 if len(specs) == 0 { 107 return nil 108 } 109 110 // We go through the list of LBSpecs to delete each one, independently of the result of the previous one. 111 // If multiple errors occur, we return the most pressing one. 112 // Order of precedence (highest -> lowest) is: error that is not an operationNotDoneError (i.e. error deleting) -> operationNotDoneError (i.e. deleting in progress) -> no error (i.e. deleted) 113 var result error 114 for _, lbSpec := range specs { 115 if err := s.DeleteResource(ctx, lbSpec, serviceName); err != nil { 116 if !azure.IsOperationNotDoneError(err) || result == nil { 117 result = err 118 } 119 } 120 } 121 122 s.Scope.UpdateDeleteStatus(infrav1.LoadBalancersReadyCondition, serviceName, result) 123 return result 124 } 125 126 // IsManaged returns always returns true as CAPZ does not support BYO load balancers. 127 func (s *Service) IsManaged(ctx context.Context) (bool, error) { 128 return true, nil 129 }