-
Notifications
You must be signed in to change notification settings - Fork 101
/
azure_utils.go
194 lines (165 loc) · 7.33 KB
/
azure_utils.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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package system
import (
"fmt"
"log"
"net/http"
"net/url"
"time"
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage"
"github.com/Azure/azure-storage-blob-go/azblob"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/to"
"github.com/noobaa/noobaa-operator/v5/pkg/util"
)
func (r *Reconciler) getStorageAccountsClient() storage.AccountsClient {
storageAccountsClient := storage.NewAccountsClient(r.AzureContainerCreds.StringData["azure_subscription_id"])
auth, _ := r.GetResourceManagementAuthorizer()
storageAccountsClient.Authorizer = auth
// Inject the global refreshing CA pool into the one used by the Azure client
var httpClient = &http.Client{
Transport: util.GlobalCARefreshingTransport,
Timeout: 10 * time.Second,
}
underlyingHTTPClient, ok := storageAccountsClient.Sender.(*http.Client)
if !ok {
log.Fatalf("failed to cast underlyingHTTPClient to *http.Client")
}
underlyingHTTPClient.Transport = httpClient.Transport
underlyingTransport, ok := underlyingHTTPClient.Transport.(*http.Transport)
if !ok {
log.Fatalf("failed to cast underlyingTransport to *http.Transport")
}
underlyingTransport.TLSClientConfig.RootCAs = util.GlobalCARefreshingTransport.TLSClientConfig.RootCAs
err := storageAccountsClient.AddToUserAgent("Go-http-client/1.1")
if err != nil {
log.Fatalf("got error on storageAccountsClient.AddToUserAgent %v", err)
}
return storageAccountsClient
}
func (r *Reconciler) getAccountPrimaryKey(accountName, accountGroupName string) string {
response, err := r.GetAccountKeys(accountName, accountGroupName)
if err != nil {
log.Fatalf("failed to list keys: %v", err)
}
return *(((*response.Keys)[0]).Value)
}
// CreateStorageAccount starts creation of a new storage account and waits for
// the account to be created.
func (r *Reconciler) CreateStorageAccount(accountName, accountGroupName string) (storage.Account, error) {
var s storage.Account
storageAccountsClient := r.getStorageAccountsClient()
// we used to call storage.AccountCheckNameAvailabilityParameters here to make sure the name is available
// removed it because when using a newer API version (2019-06-01), this call produced some irrelevant errors sometimes
// if the name is not available, CreateStorageAccount will return an error, and a different name will be used next time
enableHTTPSTrafficOnly := true
allowBlobPublicAccess := false
future, err := storageAccountsClient.Create(
r.Ctx,
accountGroupName,
accountName,
storage.AccountCreateParameters{
Sku: &storage.Sku{
Name: storage.StandardLRS},
Kind: storage.Storage,
Location: to.StringPtr(r.AzureContainerCreds.StringData["azure_region"]),
AccountPropertiesCreateParameters: &storage.AccountPropertiesCreateParameters{
EnableHTTPSTrafficOnly: &enableHTTPSTrafficOnly,
AllowBlobPublicAccess: &allowBlobPublicAccess,
MinimumTLSVersion: storage.TLS12,
},
})
if err != nil {
return s, fmt.Errorf("failed to start creating storage account: %+v", err)
}
err = future.WaitForCompletionRef(r.Ctx, storageAccountsClient.Client)
if err != nil {
return s, fmt.Errorf("failed to finish creating storage account: %+v", err)
}
return future.Result(storageAccountsClient)
}
// GetStorageAccount gets details on the specified storage account
func (r *Reconciler) GetStorageAccount(accountName, accountGroupName string) (storage.Account, error) {
storageAccountsClient := r.getStorageAccountsClient()
return storageAccountsClient.GetProperties(r.Ctx, accountGroupName, accountName, storage.AccountExpandBlobRestoreStatus)
}
// DeleteStorageAccount deletes an existing storate account
func (r *Reconciler) DeleteStorageAccount(accountName, accountGroupName string) (autorest.Response, error) {
storageAccountsClient := r.getStorageAccountsClient()
return storageAccountsClient.Delete(r.Ctx, accountGroupName, accountName)
}
// CheckAccountNameAvailability checks if the storage account name is available.
// Storage account names must be unique across Azure and meet other requirements.
func (r *Reconciler) CheckAccountNameAvailability(accountName string) (storage.CheckNameAvailabilityResult, error) {
storageAccountsClient := r.getStorageAccountsClient()
result, err := storageAccountsClient.CheckNameAvailability(
r.Ctx,
storage.AccountCheckNameAvailabilityParameters{
Name: to.StringPtr(accountName),
Type: to.StringPtr("Microsoft.Storage/storageAccounts"),
})
return result, err
}
// GetAccountKeys gets the storage account keys
func (r *Reconciler) GetAccountKeys(accountName, accountGroupName string) (storage.AccountListKeysResult, error) {
accountsClient := r.getStorageAccountsClient()
return accountsClient.ListKeys(r.Ctx, accountGroupName, accountName, storage.Kerb)
}
func (r *Reconciler) getContainerURL(accountName, accountGroupName, containerName string) azblob.ContainerURL {
key := r.getAccountPrimaryKey(accountName, accountGroupName)
c, _ := azblob.NewSharedKeyCredential(accountName, key)
p := azblob.NewPipeline(c, azblob.PipelineOptions{
Telemetry: azblob.TelemetryOptions{Value: "Go-http-client/1.1"},
})
u, _ := url.Parse(fmt.Sprintf(`https://%s.blob.core.windows.net`, accountName))
service := azblob.NewServiceURL(*u, p)
container := service.NewContainerURL(containerName)
return container
}
// CreateContainer creates a new container with the specified name in the specified account
func (r *Reconciler) CreateContainer(accountName, accountGroupName, containerName string) (azblob.ContainerURL, error) {
c := r.getContainerURL(accountName, accountGroupName, containerName)
_, err := c.Create(
r.Ctx,
azblob.Metadata{},
azblob.PublicAccessNone)
return c, err
}
// GetContainer gets info about an existing container.
func (r *Reconciler) GetContainer(accountName, accountGroupName, containerName string) (azblob.ContainerURL, error) {
c := r.getContainerURL(accountName, accountGroupName, containerName)
_, err := c.GetProperties(r.Ctx, azblob.LeaseAccessConditions{})
return c, err
}
// DeleteContainer deletes the named container.
func (r *Reconciler) DeleteContainer(accountName, accountGroupName, containerName string) error {
c := r.getContainerURL(accountName, accountGroupName, containerName)
_, err := c.Delete(r.Ctx, azblob.ContainerAccessConditions{})
return err
}
// Environment returns an `azure.Environment{...}` for the current cloud.
func (r *Reconciler) Environment() *azure.Environment {
env, _ := azure.EnvironmentFromName("AzurePublicCloud")
return &env
}
// GetResourceManagementAuthorizer gets an OAuthTokenAuthorizer for Azure Resource Manager
func (r *Reconciler) GetResourceManagementAuthorizer() (autorest.Authorizer, error) {
return r.getAuthorizerForResource(r.Environment().ResourceManagerEndpoint)
}
func (r *Reconciler) getAuthorizerForResource(resource string) (autorest.Authorizer, error) {
var a autorest.Authorizer
var err error
oauthConfig, err := adal.NewOAuthConfig(
r.Environment().ActiveDirectoryEndpoint, r.AzureContainerCreds.StringData["azure_tenant_id"])
if err != nil {
return nil, err
}
token, err := adal.NewServicePrincipalToken(
*oauthConfig, r.AzureContainerCreds.StringData["azure_client_id"], r.AzureContainerCreds.StringData["azure_client_secret"], resource)
if err != nil {
return nil, err
}
a = autorest.NewBearerAuthorizer(token)
return a, err
}