Skip to content

Commit 23903c7

Browse files
authored
Merge pull request kubernetes#92825 from ZeroMagic/azurefile-tag
Add tags support for Azure File Driver
2 parents 780f7f0 + 7e7cf6a commit 23903c7

File tree

16 files changed

+243
-140
lines changed

16 files changed

+243
-140
lines changed

pkg/volume/azure_dd/azure_provision.go

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,6 @@ import (
3535
"k8s.io/legacy-cloud-providers/azure"
3636
)
3737

38-
const (
39-
TagsDelimiter = ","
40-
TagKeyValueDelimiter = "="
41-
)
42-
4338
type azureDiskProvisioner struct {
4439
plugin *azureDataDiskPlugin
4540
options volume.VolumeOptions
@@ -269,7 +264,7 @@ func (p *azureDiskProvisioner) Provision(selectedNode *v1.Node, allowedTopologie
269264
diskURI := ""
270265
labels := map[string]string{}
271266
if kind == v1.AzureManagedDisk {
272-
tags, err := ConvertTagsToMap(customTags)
267+
tags, err := azure.ConvertTagsToMap(customTags)
273268
if err != nil {
274269
return nil, err
275270
}
@@ -399,28 +394,3 @@ func (p *azureDiskProvisioner) Provision(selectedNode *v1.Node, allowedTopologie
399394

400395
return pv, nil
401396
}
402-
403-
// ConvertTagsToMap convert the tags from string to map
404-
// the valid tags fomat is "key1=value1,key2=value2", which could be converted to
405-
// {"key1": "value1", "key2": "value2"}
406-
func ConvertTagsToMap(tags string) (map[string]string, error) {
407-
m := make(map[string]string)
408-
if tags == "" {
409-
return m, nil
410-
}
411-
s := strings.Split(tags, TagsDelimiter)
412-
for _, tag := range s {
413-
kv := strings.Split(tag, TagKeyValueDelimiter)
414-
if len(kv) != 2 {
415-
return nil, fmt.Errorf("Tags '%s' are invalid, the format should like: 'key1=value1,key2=value2'", tags)
416-
}
417-
key := strings.TrimSpace(kv[0])
418-
if key == "" {
419-
return nil, fmt.Errorf("Tags '%s' are invalid, the format should like: 'key1=value1,key2=value2'", tags)
420-
}
421-
value := strings.TrimSpace(kv[1])
422-
m[key] = value
423-
}
424-
425-
return m, nil
426-
}

pkg/volume/azure_dd/azure_provision_test.go

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ package azure_dd
2020

2121
import (
2222
"fmt"
23-
"reflect"
2423
"testing"
2524

2625
"github.com/stretchr/testify/assert"
@@ -97,69 +96,3 @@ func TestParseZoned(t *testing.T) {
9796
}
9897
}
9998
}
100-
101-
func TestConvertTagsToMap(t *testing.T) {
102-
testCases := []struct {
103-
desc string
104-
tags string
105-
expectedOutput map[string]string
106-
expectedError bool
107-
}{
108-
{
109-
desc: "should return empty map when tag is empty",
110-
tags: "",
111-
expectedOutput: map[string]string{},
112-
expectedError: false,
113-
},
114-
{
115-
desc: "sing valid tag should be converted",
116-
tags: "key=value",
117-
expectedOutput: map[string]string{
118-
"key": "value",
119-
},
120-
expectedError: false,
121-
},
122-
{
123-
desc: "multiple valid tags should be converted",
124-
tags: "key1=value1,key2=value2",
125-
expectedOutput: map[string]string{
126-
"key1": "value1",
127-
"key2": "value2",
128-
},
129-
expectedError: false,
130-
},
131-
{
132-
desc: "whitespaces should be trimmed",
133-
tags: "key1=value1, key2=value2",
134-
expectedOutput: map[string]string{
135-
"key1": "value1",
136-
"key2": "value2",
137-
},
138-
expectedError: false,
139-
},
140-
{
141-
desc: "should return error for invalid format",
142-
tags: "foo,bar",
143-
expectedOutput: nil,
144-
expectedError: true,
145-
},
146-
{
147-
desc: "should return error for when key is missed",
148-
tags: "key1=value1,=bar",
149-
expectedOutput: nil,
150-
expectedError: true,
151-
},
152-
}
153-
154-
for i, c := range testCases {
155-
m, err := ConvertTagsToMap(c.tags)
156-
if c.expectedError {
157-
assert.NotNil(t, err, "TestCase[%d]: %s", i, c.desc)
158-
} else {
159-
assert.Nil(t, err, "TestCase[%d]: %s", i, c.desc)
160-
if !reflect.DeepEqual(m, c.expectedOutput) {
161-
t.Errorf("got: %v, expected: %v, desc: %v", m, c.expectedOutput, c.desc)
162-
}
163-
}
164-
}
165-
}

pkg/volume/azure_file/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ go_library(
2222
"//staging/src/k8s.io/cloud-provider:go_default_library",
2323
"//staging/src/k8s.io/cloud-provider/volume/helpers:go_default_library",
2424
"//staging/src/k8s.io/legacy-cloud-providers/azure:go_default_library",
25+
"//staging/src/k8s.io/legacy-cloud-providers/azure/clients/fileclient:go_default_library",
2526
"//vendor/github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage:go_default_library",
2627
"//vendor/k8s.io/klog/v2:go_default_library",
2728
"//vendor/k8s.io/utils/mount:go_default_library",

pkg/volume/azure_file/azure_provision.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"k8s.io/kubernetes/pkg/volume"
3434
"k8s.io/kubernetes/pkg/volume/util"
3535
"k8s.io/legacy-cloud-providers/azure"
36+
"k8s.io/legacy-cloud-providers/azure/clients/fileclient"
3637
utilstrings "k8s.io/utils/strings"
3738
)
3839

@@ -47,7 +48,7 @@ var (
4748
// azure cloud provider should implement it
4849
type azureCloudProvider interface {
4950
// create a file share
50-
CreateFileShare(shareName, accountName, accountType, accountKind, resourceGroup, location string, protocol storage.EnabledProtocols, requestGiB int) (string, string, error)
51+
CreateFileShare(account *azure.AccountOptions, fileShare *fileclient.ShareOptions) (string, string, error)
5152
// delete a file share
5253
DeleteFileShare(resourceGroup, accountName, shareName string) error
5354
// resize a file share
@@ -155,7 +156,7 @@ func (a *azureFileProvisioner) Provision(selectedNode *v1.Node, allowedTopologie
155156
return nil, fmt.Errorf("%s does not support block volume provisioning", a.plugin.GetPluginName())
156157
}
157158

158-
var sku, resourceGroup, location, account, shareName string
159+
var sku, resourceGroup, location, account, shareName, customTags string
159160

160161
capacity := a.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
161162
requestGiB, err := volumehelpers.RoundUpToGiBInt(capacity)
@@ -180,6 +181,8 @@ func (a *azureFileProvisioner) Provision(selectedNode *v1.Node, allowedTopologie
180181
resourceGroup = v
181182
case "sharename":
182183
shareName = v
184+
case "tags":
185+
customTags = v
183186
default:
184187
return nil, fmt.Errorf("invalid option %q for volume plugin %s", k, a.plugin.GetPluginName())
185188
}
@@ -189,6 +192,11 @@ func (a *azureFileProvisioner) Provision(selectedNode *v1.Node, allowedTopologie
189192
return nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on Azure file")
190193
}
191194

195+
tags, err := azure.ConvertTagsToMap(customTags)
196+
if err != nil {
197+
return nil, err
198+
}
199+
192200
if shareName == "" {
193201
// File share name has a length limit of 63, and it cannot contain two consecutive '-'s.
194202
name := util.GenerateVolumeName(a.options.ClusterName, a.options.PVName, 63)
@@ -204,7 +212,23 @@ func (a *azureFileProvisioner) Provision(selectedNode *v1.Node, allowedTopologie
204212
if strings.HasPrefix(strings.ToLower(sku), "premium") {
205213
accountKind = string(storage.FileStorage)
206214
}
207-
account, key, err := a.azureProvider.CreateFileShare(shareName, account, sku, accountKind, resourceGroup, location, storage.SMB, requestGiB)
215+
216+
accountOptions := &azure.AccountOptions{
217+
Name: account,
218+
Type: sku,
219+
Kind: accountKind,
220+
ResourceGroup: resourceGroup,
221+
Location: location,
222+
Tags: tags,
223+
}
224+
225+
shareOptions := &fileclient.ShareOptions{
226+
Name: shareName,
227+
Protocol: storage.SMB,
228+
RequestGiB: requestGiB,
229+
}
230+
231+
account, key, err := a.azureProvider.CreateFileShare(accountOptions, shareOptions)
208232
if err != nil {
209233
return nil, err
210234
}

staging/src/k8s.io/legacy-cloud-providers/azure/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ go_test(
151151
"//staging/src/k8s.io/legacy-cloud-providers/azure/cache:go_default_library",
152152
"//staging/src/k8s.io/legacy-cloud-providers/azure/clients:go_default_library",
153153
"//staging/src/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient:go_default_library",
154+
"//staging/src/k8s.io/legacy-cloud-providers/azure/clients/fileclient:go_default_library",
154155
"//staging/src/k8s.io/legacy-cloud-providers/azure/clients/fileclient/mockfileclient:go_default_library",
155156
"//staging/src/k8s.io/legacy-cloud-providers/azure/clients/interfaceclient/mockinterfaceclient:go_default_library",
156157
"//staging/src/k8s.io/legacy-cloud-providers/azure/clients/loadbalancerclient/mockloadbalancerclient:go_default_library",

staging/src/k8s.io/legacy-cloud-providers/azure/azure_blobDiskController.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,15 @@ func (c *BlobDiskController) initStorageAccounts() {
8484
// If no storage account is given, search all the storage accounts associated with the resource group and pick one that
8585
// fits storage type and location.
8686
func (c *BlobDiskController) CreateVolume(blobName, accountName, accountType, location string, requestGB int) (string, string, int, error) {
87-
account, key, err := c.common.cloud.EnsureStorageAccount(accountName, accountType, string(defaultStorageAccountKind), c.common.resourceGroup, location, dedicatedDiskAccountNamePrefix, true)
87+
accountOptions := &AccountOptions{
88+
Name: accountName,
89+
Type: accountType,
90+
Kind: string(defaultStorageAccountKind),
91+
ResourceGroup: c.common.resourceGroup,
92+
Location: location,
93+
EnableHTTPSTrafficOnly: true,
94+
}
95+
account, key, err := c.common.cloud.EnsureStorageAccount(accountOptions, dedicatedDiskAccountNamePrefix)
8896
if err != nil {
8997
return "", "", 0, fmt.Errorf("could not get storage key for storage account %s: %v", accountName, err)
9098
}

staging/src/k8s.io/legacy-cloud-providers/azure/azure_file.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ package azure
2020

2121
import (
2222
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage"
23+
"k8s.io/legacy-cloud-providers/azure/clients/fileclient"
2324
)
2425

2526
// create file share
26-
func (az *Cloud) createFileShare(resourceGroupName, accountName, name string, protocol storage.EnabledProtocols, sizeGiB int) error {
27-
return az.FileClient.CreateFileShare(resourceGroupName, accountName, name, protocol, sizeGiB)
27+
func (az *Cloud) createFileShare(resourceGroupName, accountName string, shareOptions *fileclient.ShareOptions) error {
28+
return az.FileClient.CreateFileShare(resourceGroupName, accountName, shareOptions)
2829
}
2930

3031
func (az *Cloud) deleteFileShare(resourceGroupName, accountName, name string) error {

staging/src/k8s.io/legacy-cloud-providers/azure/azure_storage.go

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage"
2525

2626
"k8s.io/klog/v2"
27+
"k8s.io/legacy-cloud-providers/azure/clients/fileclient"
2728
)
2829

2930
const (
@@ -36,25 +37,32 @@ const (
3637

3738
// CreateFileShare creates a file share, using a matching storage account type, account kind, etc.
3839
// storage account will be created if specified account is not found
39-
func (az *Cloud) CreateFileShare(shareName, accountName, accountType, accountKind, resourceGroup, location string, protocol storage.EnabledProtocols, requestGiB int) (string, string, error) {
40-
if resourceGroup == "" {
41-
resourceGroup = az.resourceGroup
40+
func (az *Cloud) CreateFileShare(accountOptions *AccountOptions, shareOptions *fileclient.ShareOptions) (string, string, error) {
41+
if accountOptions == nil {
42+
return "", "", fmt.Errorf("account options is nil")
43+
}
44+
if shareOptions == nil {
45+
return "", "", fmt.Errorf("share options is nil")
46+
}
47+
if accountOptions.ResourceGroup == "" {
48+
accountOptions.ResourceGroup = az.resourceGroup
4249
}
4350

44-
enableHTTPSTrafficOnly := true
45-
if protocol == storage.NFS {
46-
enableHTTPSTrafficOnly = false
51+
accountOptions.EnableHTTPSTrafficOnly = true
52+
if shareOptions.Protocol == storage.NFS {
53+
accountOptions.EnableHTTPSTrafficOnly = false
4754
}
48-
account, key, err := az.EnsureStorageAccount(accountName, accountType, accountKind, resourceGroup, location, fileShareAccountNamePrefix, enableHTTPSTrafficOnly)
55+
56+
accountName, accountKey, err := az.EnsureStorageAccount(accountOptions, fileShareAccountNamePrefix)
4957
if err != nil {
50-
return "", "", fmt.Errorf("could not get storage key for storage account %s: %v", accountName, err)
58+
return "", "", fmt.Errorf("could not get storage key for storage account %s: %v", accountOptions.Name, err)
5159
}
5260

53-
if err := az.createFileShare(resourceGroup, account, shareName, protocol, requestGiB); err != nil {
54-
return "", "", fmt.Errorf("failed to create share %s in account %s: %v", shareName, account, err)
61+
if err := az.createFileShare(accountOptions.ResourceGroup, accountName, shareOptions); err != nil {
62+
return "", "", fmt.Errorf("failed to create share %s in account %s: %v", shareOptions.Name, accountName, err)
5563
}
56-
klog.V(4).Infof("created share %s in account %s", shareName, account)
57-
return account, key, nil
64+
klog.V(4).Infof("created share %s in account %s", shareOptions.Name, accountOptions.Name)
65+
return accountName, accountKey, nil
5866
}
5967

6068
// DeleteFileShare deletes a file share using storage account name and key

staging/src/k8s.io/legacy-cloud-providers/azure/azure_storage_test.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage"
2626
"github.com/golang/mock/gomock"
2727

28+
"k8s.io/legacy-cloud-providers/azure/clients/fileclient"
2829
"k8s.io/legacy-cloud-providers/azure/clients/fileclient/mockfileclient"
2930
"k8s.io/legacy-cloud-providers/azure/clients/storageaccountclient/mockstorageaccountclient"
3031
)
@@ -141,15 +142,29 @@ func TestCreateFileShare(t *testing.T) {
141142
for _, test := range tests {
142143
mockFileClient := mockfileclient.NewMockInterface(ctrl)
143144
cloud.FileClient = mockFileClient
144-
mockFileClient.EXPECT().CreateFileShare(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(test.err).AnyTimes()
145+
mockFileClient.EXPECT().CreateFileShare(gomock.Any(), gomock.Any(), gomock.Any()).Return(test.err).AnyTimes()
145146

146147
mockStorageAccountsClient := mockstorageaccountclient.NewMockInterface(ctrl)
147148
cloud.StorageAccountClient = mockStorageAccountsClient
148149
mockStorageAccountsClient.EXPECT().ListKeys(gomock.Any(), "rg", gomock.Any()).Return(test.keys, nil).AnyTimes()
149150
mockStorageAccountsClient.EXPECT().ListByResourceGroup(gomock.Any(), "rg").Return(test.accounts, nil).AnyTimes()
150151
mockStorageAccountsClient.EXPECT().Create(gomock.Any(), "rg", gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
151152

152-
account, key, err := cloud.CreateFileShare(test.name, test.acct, test.acctType, test.acctKind, test.rg, test.loc, storage.SMB, test.gb)
153+
mockAccount := &AccountOptions{
154+
Name: test.acct,
155+
Type: test.acctType,
156+
Kind: test.acctKind,
157+
ResourceGroup: test.rg,
158+
Location: test.loc,
159+
}
160+
161+
mockFileShare := &fileclient.ShareOptions{
162+
Name: test.name,
163+
Protocol: storage.SMB,
164+
RequestGiB: test.gb,
165+
}
166+
167+
account, key, err := cloud.CreateFileShare(mockAccount, mockFileShare)
153168
if test.expectErr && err == nil {
154169
t.Errorf("unexpected non-error")
155170
continue

0 commit comments

Comments
 (0)