sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/availabilitysets/availabilitysets.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 availabilitysets
    18  
    19  import (
    20  	"context"
    21  
    22  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
    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/services/async"
    27  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/resourceskus"
    28  	"sigs.k8s.io/cluster-api-provider-azure/util/tele"
    29  )
    30  
    31  const serviceName = "availabilitysets"
    32  
    33  // AvailabilitySetScope defines the scope interface for a availability sets service.
    34  type AvailabilitySetScope interface {
    35  	azure.ClusterDescriber
    36  	azure.AsyncStatusUpdater
    37  	AvailabilitySetSpec() azure.ResourceSpecGetter
    38  }
    39  
    40  // Service provides operations on Azure resources.
    41  type Service struct {
    42  	Scope AvailabilitySetScope
    43  	async.Getter
    44  	async.Reconciler
    45  	resourceSKUCache *resourceskus.Cache
    46  }
    47  
    48  // New creates a new availability sets service.
    49  func New(scope AvailabilitySetScope, skuCache *resourceskus.Cache) (*Service, error) {
    50  	client, err := NewClient(scope)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	return &Service{
    55  		Scope:            scope,
    56  		Getter:           client,
    57  		resourceSKUCache: skuCache,
    58  		Reconciler: async.New[armcompute.AvailabilitySetsClientCreateOrUpdateResponse,
    59  			armcompute.AvailabilitySetsClientDeleteResponse](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 an availability set.
    69  func (s *Service) Reconcile(ctx context.Context) error {
    70  	ctx, log, done := tele.StartSpanWithLogger(ctx, "availabilitysets.Service.Reconcile")
    71  	defer done()
    72  
    73  	ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout())
    74  	defer cancel()
    75  
    76  	var err error
    77  	if setSpec := s.Scope.AvailabilitySetSpec(); setSpec != nil {
    78  		_, err = s.CreateOrUpdateResource(ctx, setSpec, serviceName)
    79  	} else {
    80  		log.V(2).Info("skip creation when no availability set spec is found")
    81  		return nil
    82  	}
    83  
    84  	s.Scope.UpdatePutStatus(infrav1.AvailabilitySetReadyCondition, serviceName, err)
    85  	return err
    86  }
    87  
    88  // Delete deletes availability sets.
    89  func (s *Service) Delete(ctx context.Context) error {
    90  	ctx, log, done := tele.StartSpanWithLogger(ctx, "availabilitysets.Service.Delete")
    91  	defer done()
    92  
    93  	ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout())
    94  	defer cancel()
    95  
    96  	var resultingErr error
    97  	setSpec := s.Scope.AvailabilitySetSpec()
    98  	if setSpec == nil {
    99  		log.V(2).Info("skip deletion when no availability set spec is found")
   100  		return nil
   101  	}
   102  
   103  	existingSet, err := s.Get(ctx, setSpec)
   104  	if err != nil {
   105  		if !azure.ResourceNotFound(err) {
   106  			resultingErr = errors.Wrapf(err, "failed to get availability set %s in resource group %s", setSpec.ResourceName(), setSpec.ResourceGroupName())
   107  		}
   108  	} else {
   109  		availabilitySet, ok := existingSet.(armcompute.AvailabilitySet)
   110  		if !ok {
   111  			resultingErr = errors.Errorf("%T is not an armcompute.AvailabilitySet", existingSet)
   112  		} else {
   113  			// only delete when the availability set does not have any vms
   114  			if availabilitySet.Properties != nil && len(availabilitySet.Properties.VirtualMachines) > 0 {
   115  				log.V(2).Info("skip deleting availability set with VMs", "availability set", setSpec.ResourceName())
   116  			} else {
   117  				resultingErr = s.DeleteResource(ctx, setSpec, serviceName)
   118  			}
   119  		}
   120  	}
   121  
   122  	s.Scope.UpdateDeleteStatus(infrav1.AvailabilitySetReadyCondition, serviceName, resultingErr)
   123  	return resultingErr
   124  }
   125  
   126  // IsManaged returns always returns true as CAPZ does not support BYO availability set.
   127  func (s *Service) IsManaged(ctx context.Context) (bool, error) {
   128  	return true, nil
   129  }