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 }