Skip to content

Commit 4df5f93

Browse files
authored
Merge pull request #234 from andyzhangx/bring-key
feat: bring your own account key for dynamic provisioning
2 parents da42c89 + 8236ba2 commit 4df5f93

File tree

4 files changed

+182
-18
lines changed

4 files changed

+182
-18
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
apiVersion: storage.k8s.io/v1
3+
kind: StorageClass
4+
metadata:
5+
name: blob
6+
provisioner: blob.csi.azure.com
7+
parameters:
8+
csi.storage.k8s.io/provisioner-secret-name: azure-secret
9+
csi.storage.k8s.io/provisioner-secret-namespace: default
10+
csi.storage.k8s.io/node-stage-secret-name: azure-secret
11+
csi.storage.k8s.io/node-stage-secret-namespace: default

pkg/blob/blob.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,3 +433,34 @@ func isSupportedProtocol(protocol string) bool {
433433
}
434434
return false
435435
}
436+
437+
// get storage account from secrets map
438+
func getStorageAccount(secrets map[string]string) (string, string, error) {
439+
if secrets == nil {
440+
return "", "", fmt.Errorf("unexpected: getStorageAccount secrets is nil")
441+
}
442+
443+
var accountName, accountKey string
444+
for k, v := range secrets {
445+
switch strings.ToLower(k) {
446+
case "accountname":
447+
accountName = v
448+
case "azurestorageaccountname": // for compatibility with built-in azurefile plugin
449+
accountName = v
450+
case "accountkey":
451+
accountKey = v
452+
case "azurestorageaccountkey": // for compatibility with built-in azurefile plugin
453+
accountKey = v
454+
}
455+
}
456+
457+
if accountName == "" {
458+
return "", "", fmt.Errorf("could not find accountname or azurestorageaccountname field secrets(%v)", secrets)
459+
}
460+
if accountKey == "" {
461+
return "", "", fmt.Errorf("could not find accountkey or azurestorageaccountkey field in secrets(%v)", secrets)
462+
}
463+
464+
klog.V(4).Infof("got storage account(%s) from secret", accountName)
465+
return accountName, accountKey, nil
466+
}

pkg/blob/blob_test.go

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@ import (
2121
"errors"
2222
"fmt"
2323
"io/ioutil"
24-
"k8s.io/legacy-cloud-providers/azure/retry"
2524
"os"
2625
"reflect"
2726
"testing"
2827

28+
"k8s.io/legacy-cloud-providers/azure/retry"
29+
2930
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage"
3031
"github.com/golang/mock/gomock"
3132
"github.com/stretchr/testify/assert"
@@ -600,3 +601,102 @@ func TestGetStorageAccountAndContainer(t *testing.T) {
600601
t.Run(tc.name, tc.testFunc)
601602
}
602603
}
604+
605+
func TestGetStorageAccount(t *testing.T) {
606+
emptyAccountKeyMap := map[string]string{
607+
"accountname": "testaccount",
608+
"accountkey": "",
609+
}
610+
611+
emptyAccountNameMap := map[string]string{
612+
"azurestorageaccountname": "",
613+
"azurestorageaccountkey": "testkey",
614+
}
615+
616+
emptyAzureAccountKeyMap := map[string]string{
617+
"azurestorageaccountname": "testaccount",
618+
"azurestorageaccountkey": "",
619+
}
620+
621+
emptyAzureAccountNameMap := map[string]string{
622+
"azurestorageaccountname": "",
623+
"azurestorageaccountkey": "testkey",
624+
}
625+
626+
tests := []struct {
627+
options map[string]string
628+
expected1 string
629+
expected2 string
630+
expected3 error
631+
}{
632+
{
633+
options: map[string]string{
634+
"accountname": "testaccount",
635+
"accountkey": "testkey",
636+
},
637+
expected1: "testaccount",
638+
expected2: "testkey",
639+
expected3: nil,
640+
},
641+
{
642+
options: map[string]string{
643+
"azurestorageaccountname": "testaccount",
644+
"azurestorageaccountkey": "testkey",
645+
},
646+
expected1: "testaccount",
647+
expected2: "testkey",
648+
expected3: nil,
649+
},
650+
{
651+
options: map[string]string{
652+
"accountname": "",
653+
"accountkey": "",
654+
},
655+
expected1: "",
656+
expected2: "",
657+
expected3: fmt.Errorf("could not find accountname or azurestorageaccountname field secrets(map[accountname: accountkey:])"),
658+
},
659+
{
660+
options: emptyAccountKeyMap,
661+
expected1: "",
662+
expected2: "",
663+
expected3: fmt.Errorf("could not find accountkey or azurestorageaccountkey field in secrets(%v)", emptyAccountKeyMap),
664+
},
665+
{
666+
options: emptyAccountNameMap,
667+
expected1: "",
668+
expected2: "",
669+
expected3: fmt.Errorf("could not find accountname or azurestorageaccountname field secrets(%v)", emptyAccountNameMap),
670+
},
671+
{
672+
options: emptyAzureAccountKeyMap,
673+
expected1: "",
674+
expected2: "",
675+
expected3: fmt.Errorf("could not find accountkey or azurestorageaccountkey field in secrets(%v)", emptyAzureAccountKeyMap),
676+
},
677+
{
678+
options: emptyAzureAccountNameMap,
679+
expected1: "",
680+
expected2: "",
681+
expected3: fmt.Errorf("could not find accountname or azurestorageaccountname field secrets(%v)", emptyAzureAccountNameMap),
682+
},
683+
{
684+
options: nil,
685+
expected1: "",
686+
expected2: "",
687+
expected3: fmt.Errorf("unexpected: getStorageAccount secrets is nil"),
688+
},
689+
}
690+
691+
for _, test := range tests {
692+
result1, result2, result3 := getStorageAccount(test.options)
693+
if !reflect.DeepEqual(result1, test.expected1) || !reflect.DeepEqual(result2, test.expected2) {
694+
t.Errorf("input: %q, getStorageAccount result1: %q, expected1: %q, result2: %q, expected2: %q, result3: %q, expected3: %q", test.options, result1, test.expected1, result2, test.expected2,
695+
result3, test.expected3)
696+
} else {
697+
if result1 == "" || result2 == "" {
698+
assert.Error(t, result3)
699+
}
700+
}
701+
}
702+
}

pkg/blob/controllerserver.go

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -118,18 +118,24 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
118118
}
119119

120120
var accountName, accountKey string
121-
err = wait.ExponentialBackoff(d.cloud.RequestBackoff(), func() (bool, error) {
122-
var retErr error
123-
accountName, accountKey, retErr = d.cloud.EnsureStorageAccount(accountOptions, protocol)
124-
if isRetriableError(retErr) {
125-
klog.Warningf("EnsureStorageAccount(%s) failed with error(%v), waiting for retrying", account, retErr)
126-
return false, nil
121+
if len(req.GetSecrets()) == 0 { // check whether account is provided by secret
122+
err = wait.ExponentialBackoff(d.cloud.RequestBackoff(), func() (bool, error) {
123+
var retErr error
124+
accountName, accountKey, retErr = d.cloud.EnsureStorageAccount(accountOptions, protocol)
125+
if isRetriableError(retErr) {
126+
klog.Warningf("EnsureStorageAccount(%s) failed with error(%v), waiting for retrying", account, retErr)
127+
return false, nil
128+
}
129+
return true, retErr
130+
})
131+
if err != nil {
132+
return nil, status.Errorf(codes.Internal, "failed to ensure storage account: %v", err)
133+
}
134+
} else {
135+
accountName, accountKey, err = getStorageAccount(req.GetSecrets())
136+
if err != nil {
137+
return nil, status.Errorf(codes.Internal, "failed to get storage account from secrets: %v", err)
127138
}
128-
return true, retErr
129-
})
130-
131-
if err != nil {
132-
return nil, status.Errorf(codes.Internal, "failed to ensure storage account: %v", err)
133139
}
134140

135141
if containerName == "" {
@@ -189,9 +195,17 @@ func (d *Driver) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest)
189195
resourceGroupName = d.cloud.ResourceGroup
190196
}
191197

192-
accountKey, err := d.cloud.GetStorageAccesskey(accountName, resourceGroupName)
193-
if err != nil {
194-
return nil, fmt.Errorf("no key for storage account(%s) under resource group(%s), err %v", accountName, resourceGroupName, err)
198+
var accountKey string
199+
if len(req.GetSecrets()) == 0 { // check whether account is provided by secret
200+
accountKey, err = d.cloud.GetStorageAccesskey(accountName, resourceGroupName)
201+
if err != nil {
202+
return nil, fmt.Errorf("no key for storage account(%s) under resource group(%s), err %v", accountName, resourceGroupName, err)
203+
}
204+
} else {
205+
accountName, accountKey, err = getStorageAccount(req.GetSecrets())
206+
if err != nil {
207+
return nil, status.Errorf(codes.Internal, "failed to get storage account from secrets: %v", err)
208+
}
195209
}
196210

197211
klog.V(2).Infof("deleting container(%s) rg(%s) account(%s) volumeID(%s)", containerName, resourceGroupName, accountName, volumeID)
@@ -238,9 +252,17 @@ func (d *Driver) ValidateVolumeCapabilities(ctx context.Context, req *csi.Valida
238252
resourceGroupName = d.cloud.ResourceGroup
239253
}
240254

241-
accountKey, err := d.cloud.GetStorageAccesskey(accountName, resourceGroupName)
242-
if err != nil {
243-
return nil, fmt.Errorf("no key for storage account(%s) under resource group(%s), err %v", accountName, resourceGroupName, err)
255+
var accountKey string
256+
if len(req.GetSecrets()) == 0 { // check whether account is provided by secret
257+
accountKey, err = d.cloud.GetStorageAccesskey(accountName, resourceGroupName)
258+
if err != nil {
259+
return nil, fmt.Errorf("no key for storage account(%s) under resource group(%s), err %v", accountName, resourceGroupName, err)
260+
}
261+
} else {
262+
accountName, accountKey, err = getStorageAccount(req.GetSecrets())
263+
if err != nil {
264+
return nil, status.Errorf(codes.Internal, "failed to get storage account from secrets: %v", err)
265+
}
244266
}
245267

246268
client, err := azstorage.NewBasicClientOnSovereignCloud(accountName, accountKey, d.cloud.Environment)

0 commit comments

Comments
 (0)