-
Notifications
You must be signed in to change notification settings - Fork 431
/
client.go
163 lines (134 loc) · 5.36 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package groups
import (
"context"
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2019-05-01/resources"
"github.com/Azure/go-autorest/autorest"
azureautorest "github.com/Azure/go-autorest/autorest/azure"
"github.com/pkg/errors"
"sigs.k8s.io/cluster-api-provider-azure/azure"
"sigs.k8s.io/cluster-api-provider-azure/util/reconciler"
"sigs.k8s.io/cluster-api-provider-azure/util/tele"
)
// client wraps go-sdk.
type client interface {
Get(context.Context, string) (resources.Group, error)
CreateOrUpdateAsync(context.Context, azure.ResourceSpecGetter) (azureautorest.FutureAPI, error)
DeleteAsync(context.Context, azure.ResourceSpecGetter) (azureautorest.FutureAPI, error)
IsDone(context.Context, azureautorest.FutureAPI) (bool, error)
}
// azureClient contains the Azure go-sdk Client.
type azureClient struct {
groups resources.GroupsClient
}
var _ client = (*azureClient)(nil)
// newClient creates a new VM client from subscription ID.
func newClient(auth azure.Authorizer) *azureClient {
c := newGroupsClient(auth.SubscriptionID(), auth.BaseURI(), auth.Authorizer())
return &azureClient{
groups: c,
}
}
// newGroupsClient creates a new groups client from subscription ID.
func newGroupsClient(subscriptionID string, baseURI string, authorizer autorest.Authorizer) resources.GroupsClient {
groupsClient := resources.NewGroupsClientWithBaseURI(baseURI, subscriptionID)
azure.SetAutoRestClientDefaults(&groupsClient.Client, authorizer)
return groupsClient
}
// Get gets a resource group.
func (ac *azureClient) Get(ctx context.Context, name string) (resources.Group, error) {
ctx, span := tele.Tracer().Start(ctx, "groups.AzureClient.Get")
defer span.End()
return ac.groups.Get(ctx, name)
}
// CreateOrUpdateAsync creates or updates a resource group.
// Creating a resource group is not a long running operation, so we don't ever return a future.
func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.ResourceSpecGetter) (azureautorest.FutureAPI, error) {
ctx, span := tele.Tracer().Start(ctx, "groups.AzureClient.CreateOrUpdate")
defer span.End()
group, err := ac.resourceGroupParams(ctx, spec)
if err != nil {
return nil, errors.Wrapf(err, "failed to get desired parameters for group %s", spec.ResourceName())
} else if group == nil {
// nothing to do here
return nil, nil
}
_, err = ac.groups.CreateOrUpdate(ctx, spec.ResourceName(), *group)
return nil, err
}
// DeleteAsync deletes a resource group asynchronously. DeleteAsync sends a DELETE
// request to Azure and if accepted without error, the func will return a Future which can be used to track the ongoing
// progress of the operation.
//
// NOTE: When you delete a resource group, all of its resources are also deleted.
func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecGetter) (azureautorest.FutureAPI, error) {
ctx, span := tele.Tracer().Start(ctx, "groups.AzureClient.DeleteAsync")
defer span.End()
future, err := ac.groups.Delete(ctx, spec.ResourceName())
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout)
defer cancel()
err = future.WaitForCompletionRef(ctx, ac.groups.Client)
if err != nil {
// if an error occurs, return the future.
// this means the long-running operation didn't finish in the specified timeout.
return &future, err
}
_, err = future.Result(ac.groups)
// if the operation completed, return a nil future.
return nil, err
}
// IsDone returns true if the long-running operation has completed.
func (ac *azureClient) IsDone(ctx context.Context, future azureautorest.FutureAPI) (bool, error) {
ctx, span := tele.Tracer().Start(ctx, "groups.AzureClient.IsDone")
defer span.End()
done, err := future.DoneWithContext(ctx, ac.groups)
if err != nil {
return false, errors.Wrap(err, "failed checking if the operation was complete")
}
return done, nil
}
// resourceGroupParams returns the desired resource group parameters from the given spec.
func (ac *azureClient) resourceGroupParams(ctx context.Context, spec azure.ResourceSpecGetter) (*resources.Group, error) {
ctx, span := tele.Tracer().Start(ctx, "groups.AzureClient.resourceGroupParams")
defer span.End()
var params interface{}
existingRG, err := ac.Get(ctx, spec.ResourceName())
if azure.ResourceNotFound(err) {
// rg doesn't exist, create it from scratch.
params, err = spec.Parameters(nil)
if err != nil {
return nil, err
}
} else if err != nil {
return nil, errors.Wrapf(err, "failed to get RG %s", spec.ResourceName())
} else {
// rg already exists
params, err = spec.Parameters(existingRG)
if err != nil {
return nil, err
}
}
rg, ok := params.(resources.Group)
if !ok {
if params == nil {
// nothing to do here.
return nil, nil
}
return nil, errors.Errorf("%T is not a resources.Group", params)
}
return &rg, nil
}