2019-09-27 21:51:53 +00:00
// +build !providerless
/ *
Copyright 2016 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 azure
import (
"fmt"
"strings"
2020-03-26 21:07:15 +00:00
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage"
2020-12-01 01:06:26 +00:00
"github.com/Azure/go-autorest/autorest/to"
2019-09-27 21:51:53 +00:00
2020-08-10 17:43:49 +00:00
"k8s.io/klog/v2"
2019-09-27 21:51:53 +00:00
)
2020-08-10 17:43:49 +00:00
// AccountOptions contains the fields which are used to create storage account.
type AccountOptions struct {
Name , Type , Kind , ResourceGroup , Location string
EnableHTTPSTrafficOnly bool
Tags map [ string ] string
2020-12-01 01:06:26 +00:00
VirtualNetworkResourceIDs [ ] string
2020-08-10 17:43:49 +00:00
}
2019-09-27 21:51:53 +00:00
type accountWithLocation struct {
Name , StorageType , Location string
}
2020-12-01 01:06:26 +00:00
// getStorageAccounts get matching storage accounts
func ( az * Cloud ) getStorageAccounts ( accountOptions * AccountOptions ) ( [ ] accountWithLocation , error ) {
2019-09-27 21:51:53 +00:00
ctx , cancel := getContextWithCancel ( )
defer cancel ( )
2020-12-01 01:06:26 +00:00
result , rerr := az . StorageAccountClient . ListByResourceGroup ( ctx , accountOptions . ResourceGroup )
2020-03-26 21:07:15 +00:00
if rerr != nil {
return nil , rerr . Error ( )
2019-09-27 21:51:53 +00:00
}
accounts := [ ] accountWithLocation { }
2020-03-26 21:07:15 +00:00
for _ , acct := range result {
2019-09-27 21:51:53 +00:00
if acct . Name != nil && acct . Location != nil && acct . Sku != nil {
storageType := string ( ( * acct . Sku ) . Name )
2020-12-01 01:06:26 +00:00
if accountOptions . Type != "" && ! strings . EqualFold ( accountOptions . Type , storageType ) {
2019-09-27 21:51:53 +00:00
continue
}
2020-12-01 01:06:26 +00:00
if accountOptions . Kind != "" && ! strings . EqualFold ( accountOptions . Kind , string ( acct . Kind ) ) {
2019-09-27 21:51:53 +00:00
continue
}
location := * acct . Location
2020-12-01 01:06:26 +00:00
if accountOptions . Location != "" && ! strings . EqualFold ( accountOptions . Location , location ) {
2019-09-27 21:51:53 +00:00
continue
}
2020-12-01 01:06:26 +00:00
if len ( accountOptions . VirtualNetworkResourceIDs ) > 0 {
if acct . AccountProperties == nil || acct . AccountProperties . NetworkRuleSet == nil ||
acct . AccountProperties . NetworkRuleSet . VirtualNetworkRules == nil {
continue
}
found := false
for _ , subnetID := range accountOptions . VirtualNetworkResourceIDs {
for _ , rule := range * acct . AccountProperties . NetworkRuleSet . VirtualNetworkRules {
if strings . EqualFold ( to . String ( rule . VirtualNetworkResourceID ) , subnetID ) && rule . Action == storage . Allow {
found = true
break
}
}
}
if ! found {
continue
}
}
2019-09-27 21:51:53 +00:00
accounts = append ( accounts , accountWithLocation { Name : * acct . Name , StorageType : storageType , Location : location } )
}
}
return accounts , nil
}
// GetStorageAccesskey gets the storage account access key
func ( az * Cloud ) GetStorageAccesskey ( account , resourceGroup string ) ( string , error ) {
ctx , cancel := getContextWithCancel ( )
defer cancel ( )
2020-03-26 21:07:15 +00:00
result , rerr := az . StorageAccountClient . ListKeys ( ctx , resourceGroup , account )
if rerr != nil {
return "" , rerr . Error ( )
2019-09-27 21:51:53 +00:00
}
if result . Keys == nil {
return "" , fmt . Errorf ( "empty keys" )
}
for _ , k := range * result . Keys {
if k . Value != nil && * k . Value != "" {
v := * k . Value
if ind := strings . LastIndex ( v , " " ) ; ind >= 0 {
v = v [ ( ind + 1 ) : ]
}
return v , nil
}
}
return "" , fmt . Errorf ( "no valid keys" )
}
// EnsureStorageAccount search storage account, create one storage account(with genAccountNamePrefix) if not found, return accountName, accountKey
2020-08-10 17:43:49 +00:00
func ( az * Cloud ) EnsureStorageAccount ( accountOptions * AccountOptions , genAccountNamePrefix string ) ( string , string , error ) {
if accountOptions == nil {
return "" , "" , fmt . Errorf ( "account options is nil" )
}
accountName := accountOptions . Name
accountType := accountOptions . Type
accountKind := accountOptions . Kind
resourceGroup := accountOptions . ResourceGroup
location := accountOptions . Location
enableHTTPSTrafficOnly := accountOptions . EnableHTTPSTrafficOnly
2020-12-01 01:06:26 +00:00
2019-09-27 21:51:53 +00:00
if len ( accountName ) == 0 {
// find a storage account that matches accountType
2020-12-01 01:06:26 +00:00
accounts , err := az . getStorageAccounts ( accountOptions )
2019-09-27 21:51:53 +00:00
if err != nil {
return "" , "" , fmt . Errorf ( "could not list storage accounts for account type %s: %v" , accountType , err )
}
if len ( accounts ) > 0 {
accountName = accounts [ 0 ] . Name
klog . V ( 4 ) . Infof ( "found a matching account %s type %s location %s" , accounts [ 0 ] . Name , accounts [ 0 ] . StorageType , accounts [ 0 ] . Location )
}
if len ( accountName ) == 0 {
2020-12-01 01:06:26 +00:00
// set network rules for storage account
var networkRuleSet * storage . NetworkRuleSet
virtualNetworkRules := [ ] storage . VirtualNetworkRule { }
for _ , subnetID := range accountOptions . VirtualNetworkResourceIDs {
vnetRule := storage . VirtualNetworkRule {
VirtualNetworkResourceID : & subnetID ,
Action : storage . Allow ,
}
virtualNetworkRules = append ( virtualNetworkRules , vnetRule )
klog . V ( 4 ) . Infof ( "subnetID(%s) has been set" , subnetID )
}
if len ( virtualNetworkRules ) > 0 {
networkRuleSet = & storage . NetworkRuleSet {
VirtualNetworkRules : & virtualNetworkRules ,
DefaultAction : storage . DefaultActionDeny ,
}
}
2019-09-27 21:51:53 +00:00
// not found a matching account, now create a new account in current resource group
accountName = generateStorageAccountName ( genAccountNamePrefix )
if location == "" {
location = az . Location
}
if accountType == "" {
accountType = defaultStorageAccountType
}
// use StorageV2 by default per https://docs.microsoft.com/en-us/azure/storage/common/storage-account-options
kind := defaultStorageAccountKind
if accountKind != "" {
kind = storage . Kind ( accountKind )
}
2020-08-10 17:43:49 +00:00
if len ( accountOptions . Tags ) == 0 {
accountOptions . Tags = make ( map [ string ] string )
}
accountOptions . Tags [ "created-by" ] = "azure"
2020-12-01 01:06:26 +00:00
tags := convertMapToMapPointer ( accountOptions . Tags )
2020-08-10 17:43:49 +00:00
klog . V ( 2 ) . Infof ( "azure - no matching account found, begin to create a new account %s in resource group %s, location: %s, accountType: %s, accountKind: %s, tags: %+v" ,
accountName , resourceGroup , location , accountType , kind , accountOptions . Tags )
2019-09-27 21:51:53 +00:00
cp := storage . AccountCreateParameters {
2020-12-01 01:06:26 +00:00
Sku : & storage . Sku { Name : storage . SkuName ( accountType ) } ,
Kind : kind ,
AccountPropertiesCreateParameters : & storage . AccountPropertiesCreateParameters {
EnableHTTPSTrafficOnly : & enableHTTPSTrafficOnly ,
NetworkRuleSet : networkRuleSet ,
} ,
Tags : tags ,
Location : & location }
2019-09-27 21:51:53 +00:00
ctx , cancel := getContextWithCancel ( )
defer cancel ( )
2020-03-26 21:07:15 +00:00
rerr := az . StorageAccountClient . Create ( ctx , resourceGroup , accountName , cp )
if rerr != nil {
return "" , "" , fmt . Errorf ( fmt . Sprintf ( "Failed to create storage account %s, error: %v" , accountName , rerr ) )
2019-09-27 21:51:53 +00:00
}
}
}
// find the access key with this account
accountKey , err := az . GetStorageAccesskey ( accountName , resourceGroup )
if err != nil {
return "" , "" , fmt . Errorf ( "could not get storage key for storage account %s: %v" , accountName , err )
}
return accountName , accountKey , nil
}