sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/scalesets/client.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 scalesets
    18  
    19  import (
    20  	"context"
    21  	"time"
    22  
    23  	"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
    24  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
    25  	"github.com/pkg/errors"
    26  	"sigs.k8s.io/cluster-api-provider-azure/azure"
    27  	"sigs.k8s.io/cluster-api-provider-azure/azure/services/async"
    28  	"sigs.k8s.io/cluster-api-provider-azure/util/tele"
    29  )
    30  
    31  // Client wraps go-sdk.
    32  type Client interface {
    33  	Get(context.Context, azure.ResourceSpecGetter) (interface{}, error)
    34  	List(context.Context, string) ([]armcompute.VirtualMachineScaleSet, error)
    35  	ListInstances(context.Context, string, string) ([]armcompute.VirtualMachineScaleSetVM, error)
    36  
    37  	CreateOrUpdateAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string, parameters interface{}) (result interface{}, poller *runtime.Poller[armcompute.VirtualMachineScaleSetsClientCreateOrUpdateResponse], err error)
    38  	DeleteAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string) (poller *runtime.Poller[armcompute.VirtualMachineScaleSetsClientDeleteResponse], err error)
    39  }
    40  
    41  // AzureClient contains the Azure go-sdk Client.
    42  type AzureClient struct {
    43  	scalesetvms    *armcompute.VirtualMachineScaleSetVMsClient
    44  	scalesets      *armcompute.VirtualMachineScaleSetsClient
    45  	apiCallTimeout time.Duration
    46  }
    47  
    48  var _ Client = &AzureClient{}
    49  
    50  // NewClient creates a new VMSS client from an authorizer.
    51  func NewClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*AzureClient, error) {
    52  	scaleSetVMsClient, err := newVirtualMachineScaleSetVMsClient(auth)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	scaleSetsClient, err := newVirtualMachineScaleSetsClient(auth)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	return &AzureClient{
    61  		scalesetvms:    scaleSetVMsClient,
    62  		scalesets:      scaleSetsClient,
    63  		apiCallTimeout: apiCallTimeout,
    64  	}, nil
    65  }
    66  
    67  // newVirtualMachineScaleSetVMsClient creates a vmss VM client from an authorizer.
    68  func newVirtualMachineScaleSetVMsClient(auth azure.Authorizer) (*armcompute.VirtualMachineScaleSetVMsClient, error) {
    69  	opts, err := azure.ARMClientOptions(auth.CloudEnvironment())
    70  	if err != nil {
    71  		return nil, errors.Wrap(err, "failed to create scalesetvms client options")
    72  	}
    73  	factory, err := armcompute.NewClientFactory(auth.SubscriptionID(), auth.Token(), opts)
    74  	if err != nil {
    75  		return nil, errors.Wrap(err, "failed to create armcompute client factory")
    76  	}
    77  	return factory.NewVirtualMachineScaleSetVMsClient(), nil
    78  }
    79  
    80  // newVirtualMachineScaleSetsClient creates a vmss client from an authorizer.
    81  func newVirtualMachineScaleSetsClient(auth azure.Authorizer) (*armcompute.VirtualMachineScaleSetsClient, error) {
    82  	opts, err := azure.ARMClientOptions(auth.CloudEnvironment())
    83  	if err != nil {
    84  		return nil, errors.Wrap(err, "failed to create scalesets client options")
    85  	}
    86  	factory, err := armcompute.NewClientFactory(auth.SubscriptionID(), auth.Token(), opts)
    87  	if err != nil {
    88  		return nil, errors.Wrap(err, "failed to create armcompute client factory")
    89  	}
    90  	return factory.NewVirtualMachineScaleSetsClient(), nil
    91  }
    92  
    93  // ListInstances retrieves information about the model views of a virtual machine scale set.
    94  func (ac *AzureClient) ListInstances(ctx context.Context, resourceGroupName string, resourceName string) ([]armcompute.VirtualMachineScaleSetVM, error) {
    95  	ctx, _, done := tele.StartSpanWithLogger(ctx, "scalesets.AzureClient.ListInstances")
    96  	defer done()
    97  
    98  	var instances []armcompute.VirtualMachineScaleSetVM
    99  	pager := ac.scalesetvms.NewListPager(resourceGroupName, resourceName, nil)
   100  	for pager.More() {
   101  		nextResult, err := pager.NextPage(ctx)
   102  		if err != nil {
   103  			return nil, errors.Wrap(err, "could not iterate scalesetvms")
   104  		}
   105  		for _, scaleSetVM := range nextResult.Value {
   106  			instances = append(instances, *scaleSetVM)
   107  		}
   108  	}
   109  
   110  	return instances, nil
   111  }
   112  
   113  // List returns all scale sets in a resource group.
   114  func (ac *AzureClient) List(ctx context.Context, resourceGroupName string) ([]armcompute.VirtualMachineScaleSet, error) {
   115  	ctx, _, done := tele.StartSpanWithLogger(ctx, "scalesets.AzureClient.List")
   116  	defer done()
   117  
   118  	var scaleSets []armcompute.VirtualMachineScaleSet
   119  	pager := ac.scalesets.NewListPager(resourceGroupName, nil)
   120  	for pager.More() {
   121  		nextResult, err := pager.NextPage(ctx)
   122  		if err != nil {
   123  			return scaleSets, errors.Wrap(err, "could not iterate scalesets")
   124  		}
   125  		for _, scaleSet := range nextResult.Value {
   126  			scaleSets = append(scaleSets, *scaleSet)
   127  		}
   128  	}
   129  
   130  	return scaleSets, nil
   131  }
   132  
   133  // Get retrieves information about the model view of a virtual machine scale set.
   134  func (ac *AzureClient) Get(ctx context.Context, spec azure.ResourceSpecGetter) (interface{}, error) {
   135  	ctx, _, done := tele.StartSpanWithLogger(ctx, "scalesets.AzureClient.Get")
   136  	defer done()
   137  
   138  	resp, err := ac.scalesets.Get(ctx, spec.ResourceGroupName(), spec.ResourceName(), nil)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  	return resp.VirtualMachineScaleSet, nil
   143  }
   144  
   145  // CreateOrUpdateAsync creates or updates a virtual machine scale set asynchronously.
   146  // It sends a PUT request to Azure and if accepted without error, the func will return a poller which can be used to track the ongoing
   147  // progress of the operation.
   148  func (ac *AzureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string, parameters interface{}) (result interface{}, poller *runtime.Poller[armcompute.VirtualMachineScaleSetsClientCreateOrUpdateResponse], err error) {
   149  	ctx, _, done := tele.StartSpanWithLogger(ctx, "scalesets.AzureClient.CreateOrUpdateAsync")
   150  	defer done()
   151  
   152  	scaleset, ok := parameters.(armcompute.VirtualMachineScaleSet)
   153  	if !ok && parameters != nil {
   154  		return nil, nil, errors.Errorf("%T is not an armcompute.VirtualMachineScaleSet", parameters)
   155  	}
   156  
   157  	opts := &armcompute.VirtualMachineScaleSetsClientBeginCreateOrUpdateOptions{ResumeToken: resumeToken}
   158  	poller, err = ac.scalesets.BeginCreateOrUpdate(ctx, spec.ResourceGroupName(), spec.ResourceName(), scaleset, opts)
   159  	if err != nil {
   160  		return nil, nil, err
   161  	}
   162  
   163  	ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout)
   164  	defer cancel()
   165  
   166  	pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency}
   167  	resp, err := poller.PollUntilDone(ctx, pollOpts)
   168  	if err != nil {
   169  		// if an error occurs, return the poller.
   170  		// this means the long-running operation didn't finish in the specified timeout.
   171  		return nil, poller, err
   172  	}
   173  
   174  	// if the operation completed, return a nil poller
   175  	return resp.VirtualMachineScaleSet, nil, err
   176  }
   177  
   178  // DeleteAsync is the operation to delete a virtual machine scale set asynchronously. DeleteAsync sends a DELETE
   179  // request to Azure and if accepted without error, the func will return a poller which can be used to track the ongoing
   180  // progress of the operation.
   181  //
   182  // Parameters:
   183  //
   184  //	spec - The ResourceSpecGetter containing used for name and resource group of the virtual machine scale set.
   185  func (ac *AzureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string) (poller *runtime.Poller[armcompute.VirtualMachineScaleSetsClientDeleteResponse], err error) {
   186  	ctx, _, done := tele.StartSpanWithLogger(ctx, "scalesets.AzureClient.DeleteAsync")
   187  	defer done()
   188  
   189  	opts := &armcompute.VirtualMachineScaleSetsClientBeginDeleteOptions{ResumeToken: resumeToken}
   190  	poller, err = ac.scalesets.BeginDelete(ctx, spec.ResourceGroupName(), spec.ResourceName(), opts)
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  
   195  	ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout)
   196  	defer cancel()
   197  
   198  	pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency}
   199  	_, err = poller.PollUntilDone(ctx, pollOpts)
   200  	if err != nil {
   201  		// if an error occurs, return the Poller.
   202  		// this means the long-running operation didn't finish in the specified timeout.
   203  		return poller, err
   204  	}
   205  
   206  	// if the operation completed, return a nil poller.
   207  	return nil, err
   208  }