sigs.k8s.io/cluster-api-provider-azure@v1.17.0/azure/services/virtualmachines/client.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 virtualmachines 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 "k8s.io/utils/ptr" 27 "sigs.k8s.io/cluster-api-provider-azure/azure" 28 "sigs.k8s.io/cluster-api-provider-azure/azure/services/async" 29 "sigs.k8s.io/cluster-api-provider-azure/util/tele" 30 ) 31 32 type ( 33 // AzureClient contains the Azure go-sdk Client. 34 AzureClient struct { 35 virtualmachines *armcompute.VirtualMachinesClient 36 apiCallTimeout time.Duration 37 } 38 39 // Client provides operations on Azure virtual machine resources. 40 Client interface { 41 Get(context.Context, azure.ResourceSpecGetter) (interface{}, error) 42 CreateOrUpdateAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string, parameters interface{}) (result interface{}, poller *runtime.Poller[armcompute.VirtualMachinesClientCreateOrUpdateResponse], err error) 43 DeleteAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string) (poller *runtime.Poller[armcompute.VirtualMachinesClientDeleteResponse], err error) 44 } 45 ) 46 47 var _ Client = &AzureClient{} 48 49 // NewClient creates a VMs client from an authorizer. 50 func NewClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*AzureClient, error) { 51 opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) 52 if err != nil { 53 return nil, errors.Wrap(err, "failed to create virtualmachines client options") 54 } 55 factory, err := armcompute.NewClientFactory(auth.SubscriptionID(), auth.Token(), opts) 56 if err != nil { 57 return nil, errors.Wrap(err, "failed to create armcompute client factory") 58 } 59 return &AzureClient{factory.NewVirtualMachinesClient(), apiCallTimeout}, nil 60 } 61 62 // Get retrieves information about the model view or the instance view of a virtual machine. 63 func (ac *AzureClient) Get(ctx context.Context, spec azure.ResourceSpecGetter) (result interface{}, err error) { 64 ctx, _, done := tele.StartSpanWithLogger(ctx, "virtualmachines.AzureClient.Get") 65 defer done() 66 67 resp, err := ac.virtualmachines.Get(ctx, spec.ResourceGroupName(), spec.ResourceName(), nil) 68 if err != nil { 69 return nil, err 70 } 71 return resp.VirtualMachine, nil 72 } 73 74 // CreateOrUpdateAsync creates or updates a virtual machine asynchronously. 75 // 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 76 // progress of the operation. 77 func (ac *AzureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string, parameters interface{}) (result interface{}, poller *runtime.Poller[armcompute.VirtualMachinesClientCreateOrUpdateResponse], err error) { 78 ctx, _, done := tele.StartSpanWithLogger(ctx, "virtualmachines.AzureClient.CreateOrUpdate") 79 defer done() 80 81 vm, ok := parameters.(armcompute.VirtualMachine) 82 if !ok && parameters != nil { 83 return nil, nil, errors.Errorf("%T is not an armcompute.VirtualMachine", parameters) 84 } 85 86 opts := &armcompute.VirtualMachinesClientBeginCreateOrUpdateOptions{ResumeToken: resumeToken} 87 poller, err = ac.virtualmachines.BeginCreateOrUpdate(ctx, spec.ResourceGroupName(), spec.ResourceName(), vm, opts) 88 if err != nil { 89 return nil, nil, err 90 } 91 92 ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) 93 defer cancel() 94 95 pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} 96 resp, err := poller.PollUntilDone(ctx, pollOpts) 97 if err != nil { 98 // if an error occurs, return the poller. 99 // this means the long-running operation didn't finish in the specified timeout. 100 return nil, poller, err 101 } 102 103 // if the operation completed, return a nil poller 104 return resp.VirtualMachine, nil, err 105 } 106 107 // DeleteAsync deletes a virtual machine asynchronously. DeleteAsync sends a DELETE 108 // request to Azure and if accepted without error, the func will return a Poller which can be used to track the ongoing 109 // progress of the operation. 110 func (ac *AzureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string) (poller *runtime.Poller[armcompute.VirtualMachinesClientDeleteResponse], err error) { 111 ctx, _, done := tele.StartSpanWithLogger(ctx, "virtualmachines.AzureClient.Delete") 112 defer done() 113 114 forceDelete := ptr.To(true) 115 opts := &armcompute.VirtualMachinesClientBeginDeleteOptions{ResumeToken: resumeToken, ForceDeletion: forceDelete} 116 poller, err = ac.virtualmachines.BeginDelete(ctx, spec.ResourceGroupName(), spec.ResourceName(), opts) 117 if err != nil { 118 return nil, err 119 } 120 121 ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) 122 defer cancel() 123 124 pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} 125 _, err = poller.PollUntilDone(ctx, pollOpts) 126 if err != nil { 127 // if an error occurs, return the Poller. 128 // this means the long-running operation didn't finish in the specified timeout. 129 return poller, err 130 } 131 132 // if the operation completed, return a nil poller. 133 return nil, err 134 }