Skip to content

Commit

Permalink
migrate mgmt client to track2 one
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinForReal committed Sep 25, 2024
1 parent 44cf32f commit ffce2a8
Show file tree
Hide file tree
Showing 12 changed files with 404 additions and 87 deletions.
47 changes: 25 additions & 22 deletions pkg/azurefile/azurefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"sync"
"time"

"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage"
"github.com/Azure/azure-storage-file-go/azfile"
"github.com/container-storage-interface/spec/lib/go/csi"
Expand All @@ -49,7 +50,6 @@ import (
csicommon "sigs.k8s.io/azurefile-csi-driver/pkg/csi-common"
"sigs.k8s.io/azurefile-csi-driver/pkg/mounter"
fileutil "sigs.k8s.io/azurefile-csi-driver/pkg/util"
"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/fileclient"
azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
azure "sigs.k8s.io/cloud-provider-azure/pkg/provider"
"sigs.k8s.io/cloud-provider-azure/pkg/retry"
Expand Down Expand Up @@ -444,31 +444,25 @@ func (d *Driver) Run(ctx context.Context) error {
}

// getFileShareQuota return (-1, nil) means file share does not exist
func (d *Driver) getFileShareQuota(ctx context.Context, subsID, resourceGroupName, accountName, fileShareName string, secrets map[string]string) (int, error) {
func (d *Driver) getFileShareQuota(ctx context.Context, accountOptions *azure.AccountOptions, fileShareName string, secrets map[string]string) (int, error) {
var fileClient azureFileClient
var err error
if len(secrets) > 0 {
accountName, accountKey, err := getStorageAccount(secrets)
if err != nil {
return -1, err
}
fileClient, err := newAzureFileClient(accountName, accountKey, d.getStorageEndPointSuffix(), &retry.Backoff{Steps: 1})
fileClient, err = newAzureFileClient(accountName, accountKey, d.getStorageEndPointSuffix(), &retry.Backoff{Steps: 1})
if err != nil {
return -1, err
}
return fileClient.GetFileShareQuota(ctx, fileShareName)
}

fileShare, err := d.cloud.GetFileShare(ctx, subsID, resourceGroupName, accountName, fileShareName)
if err != nil {
if strings.Contains(err.Error(), "ShareNotFound") {
return -1, nil
} else {
fileClient, err = newAzureFileMgmtClient(d.cloud.ComputeClientFactory, accountOptions)
if err != nil {
return -1, err
}
return -1, err
}

if fileShare.FileShareProperties == nil || fileShare.FileShareProperties.ShareQuota == nil {
return -1, fmt.Errorf("FileShareProperties or FileShareProperties.ShareQuota is nil")
}
return int(*fileShare.FileShareProperties.ShareQuota), nil
return fileClient.GetFileShareQuota(ctx, fileShareName)
}

// get file share info according to volume id, e.g.
Expand Down Expand Up @@ -912,22 +906,31 @@ func isSupportedFSGroupChangePolicy(policy string) bool {
}

// CreateFileShare creates a file share
func (d *Driver) CreateFileShare(ctx context.Context, accountOptions *azure.AccountOptions, shareOptions *fileclient.ShareOptions, secrets map[string]string) error {
func (d *Driver) CreateFileShare(ctx context.Context, accountOptions *azure.AccountOptions, shareOptions *ShareOptions, secrets map[string]string) error {
return wait.ExponentialBackoff(d.cloud.RequestBackoff(), func() (bool, error) {
var err error
var fileClient azureFileClient
if len(secrets) > 0 {
accountName, accountKey, rerr := getStorageAccount(secrets)
if rerr != nil {
return true, rerr
}
fileClient, rerr := newAzureFileClient(accountName, accountKey, d.getStorageEndPointSuffix(), &retry.Backoff{Steps: 1})
fileClient, rerr = newAzureFileClient(accountName, accountKey, d.getStorageEndPointSuffix(), &retry.Backoff{Steps: 1})
if rerr != nil {
return true, rerr
}
err = fileClient.CreateFileShare(ctx, shareOptions)
} else {
_, err = d.cloud.FileClient.WithSubscriptionID(accountOptions.SubscriptionID).CreateFileShare(ctx, accountOptions.ResourceGroup, accountOptions.Name, shareOptions, "")
_, _, err := d.cloud.EnsureStorageAccount(ctx, accountOptions, FileShareAccountNamePrefix)
if err != nil {
return true, fmt.Errorf("could not get storage key for storage account %s: %w", accountOptions.Name, err)
}
fileClient, err = newAzureFileMgmtClient(d.cloud.ComputeClientFactory, accountOptions)
if err != nil {
return true, err
}
}
err = fileClient.CreateFileShare(ctx, shareOptions)

if isRetriableError(err) {
klog.Warningf("CreateFileShare(%s) on account(%s) failed with error(%v), waiting for retrying", shareOptions.Name, accountOptions.Name, err)
sleepIfThrottled(err, fileOpThrottlingSleepSec)
Expand Down Expand Up @@ -1005,8 +1008,8 @@ func (d *Driver) ResizeFileShare(ctx context.Context, subsID, resourceGroup, acc
}

// copyFileShare copies a fileshare, if dstAccountName is empty, then copy in the same account
func (d *Driver) copyFileShare(ctx context.Context, req *csi.CreateVolumeRequest, dstAccountName string, dstAccountSasToken string, authAzcopyEnv []string, secretNamespace string, shareOptions *fileclient.ShareOptions, accountOptions *azure.AccountOptions, storageEndpointSuffix string) error {
if shareOptions.Protocol == storage.EnabledProtocolsNFS {
func (d *Driver) copyFileShare(ctx context.Context, req *csi.CreateVolumeRequest, dstAccountName string, dstAccountSasToken string, authAzcopyEnv []string, secretNamespace string, shareOptions *ShareOptions, accountOptions *azure.AccountOptions, storageEndpointSuffix string) error {
if shareOptions.Protocol == armstorage.EnabledProtocolsNFS {
return fmt.Errorf("protocol nfs is not supported for volume cloning")
}
var sourceVolumeID string
Expand Down
3 changes: 1 addition & 2 deletions pkg/azurefile/azurefile_dataplane_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
"k8s.io/klog/v2"

"sigs.k8s.io/cloud-provider-azure/pkg/azclient/utils"
"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/fileclient"
"sigs.k8s.io/cloud-provider-azure/pkg/retry"
)

Expand Down Expand Up @@ -77,7 +76,7 @@ func newAzureFileClient(accountName, accountKey, storageEndpointSuffix string, b
}, nil
}

func (f *azureFileDataplaneClient) CreateFileShare(ctx context.Context, shareOptions *fileclient.ShareOptions) error {
func (f *azureFileDataplaneClient) CreateFileShare(ctx context.Context, shareOptions *ShareOptions) error {
if shareOptions == nil {
return fmt.Errorf("shareOptions of account(%s) is nil", f.accountName)
}
Expand Down
4 changes: 1 addition & 3 deletions pkg/azurefile/azurefile_dataplane_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import (
"reflect"
"strings"
"testing"

"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/fileclient"
)

func TestCreateFileShare(t *testing.T) {
Expand All @@ -35,7 +33,7 @@ func TestCreateFileShare(t *testing.T) {
{
name: "",
testFunc: func(t *testing.T) {
options := &fileclient.ShareOptions{
options := &ShareOptions{
Name: "devstoreaccount1",
RequestGiB: 10,
}
Expand Down
22 changes: 20 additions & 2 deletions pkg/azurefile/azurefile_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,29 @@ package azurefile
import (
"context"

"sigs.k8s.io/cloud-provider-azure/pkg/azureclients/fileclient"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
)

const (
// FileShareAccountNamePrefix is the file share account name prefix
FileShareAccountNamePrefix = "f"
)

// ShareOptions contains the fields which are used to create file share.
type ShareOptions struct {
Name string
Protocol armstorage.EnabledProtocols
RequestGiB int
// supported values: ""(by default), "TransactionOptimized", "Cool", "Hot", "Premium"
AccessTier string
// supported values: ""(by default), "AllSquash", "NoRootSquash", "RootSquash"
RootSquash string
// Metadata - A name-value pair to associate with the share as metadata.
Metadata map[string]*string
}

type azureFileClient interface {
CreateFileShare(ctx context.Context, shareOptions *fileclient.ShareOptions) error
CreateFileShare(ctx context.Context, shareOptions *ShareOptions) error
DeleteFileShare(ctx context.Context, name string) error
GetFileShareQuota(ctx context.Context, name string) (int, error)
ResizeFileShare(ctx context.Context, name string, sizeGiB int) error
Expand Down
3 changes: 1 addition & 2 deletions pkg/azurefile/azurefile_interface_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

125 changes: 125 additions & 0 deletions pkg/azurefile/azurefile_mgmt_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
Copyright 2020 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 azurefile

import (
"context"
"fmt"

"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
"k8s.io/klog/v2"
"sigs.k8s.io/cloud-provider-azure/pkg/azclient"
"sigs.k8s.io/cloud-provider-azure/pkg/azclient/fileshareclient"
azure "sigs.k8s.io/cloud-provider-azure/pkg/provider"
)

type azureFileMgmtClient struct {
fileShareClient fileshareclient.Interface
accountOptions *azure.AccountOptions
}

func newAzureFileMgmtClient(clientFactory azclient.ClientFactory, accountOptions *azure.AccountOptions) (azureFileClient, error) {
if clientFactory == nil {
return nil, fmt.Errorf("clientFactory is nil")
}
if accountOptions == nil {
return nil, fmt.Errorf("accountOptions is nil")
}
fileShareClient, err := clientFactory.GetFileShareClientForSub(accountOptions.SubscriptionID)
if err != nil {
return nil, fmt.Errorf("failed to get file share client for subscription %s: %w", accountOptions.SubscriptionID, err)
}

return &azureFileMgmtClient{
accountOptions: accountOptions,
fileShareClient: fileShareClient,
}, nil

}

// CreateFileShare creates a file share, using a matching storage account type, account kind, etc.
// storage account will be created if specified account is not found
func (az *azureFileMgmtClient) CreateFileShare(ctx context.Context, shareOptions *ShareOptions) error {
if shareOptions == nil {
return fmt.Errorf("shareOptions of account(%s) is nil", az.accountOptions.Name)
}
az.accountOptions.EnableHTTPSTrafficOnly = true
if shareOptions.Protocol == armstorage.EnabledProtocolsNFS {
az.accountOptions.EnableHTTPSTrafficOnly = false
}
shareOps := armstorage.FileShare{
Name: to.Ptr(shareOptions.Name),
FileShareProperties: &armstorage.FileShareProperties{},
}
if shareOptions.RequestGiB > 0 {
quota := int32(shareOptions.RequestGiB)
shareOps.FileShareProperties.ShareQuota = &quota
}
if shareOptions.Protocol == armstorage.EnabledProtocolsNFS {
shareOps.FileShareProperties.EnabledProtocols = to.Ptr(shareOptions.Protocol)
}
if shareOptions.AccessTier != "" {
shareOps.FileShareProperties.AccessTier = to.Ptr(armstorage.ShareAccessTier(shareOptions.AccessTier))
}
if shareOptions.RootSquash != "" {
shareOps.FileShareProperties.RootSquash = to.Ptr(armstorage.RootSquashType(shareOptions.RootSquash))
}
if shareOptions.Metadata != nil {
shareOps.FileShareProperties.Metadata = shareOptions.Metadata
}
if _, err := az.fileShareClient.Create(ctx, az.accountOptions.ResourceGroup, az.accountOptions.Name, shareOptions.Name, shareOps); err != nil {
return fmt.Errorf("failed to create share %s in account %s: %w", shareOptions.Name, az.accountOptions.Name, err)
}
klog.V(4).Infof("created share %s in account %s", shareOptions.Name, az.accountOptions.Name)
return nil
}

// DeleteFileShare deletes a file share using storage account name and key
func (az *azureFileMgmtClient) DeleteFileShare(ctx context.Context, shareName string) error {
if err := az.fileShareClient.Delete(ctx, az.accountOptions.ResourceGroup, az.accountOptions.Name, shareName); err != nil {
return err
}
klog.V(4).Infof("share %s deleted", shareName)
return nil
}

// ResizeFileShare resizes a file share
func (az *azureFileMgmtClient) ResizeFileShare(ctx context.Context, name string, sizeGiB int) error {
fileShare, err := az.fileShareClient.Get(ctx, az.accountOptions.ResourceGroup, az.accountOptions.Name, name)
if err != nil {
return err
}
if int(*fileShare.FileShareProperties.ShareQuota) >= sizeGiB {
klog.Warningf("file share size(%dGi) is already greater or equal than requested size(%dGi), accountName: %s, shareName: %s",
*fileShare.FileShareProperties.ShareQuota, sizeGiB, az.accountOptions.Name, name)
return nil
}

fileShare.FileShareProperties.ShareQuota = to.Ptr(int32(sizeGiB))
_, err = az.fileShareClient.Update(ctx, az.accountOptions.ResourceGroup, az.accountOptions.Name, name, *fileShare)
return err
}

// GetFileShare gets a file share
func (az *azureFileMgmtClient) GetFileShareQuota(ctx context.Context, name string) (int, error) {
share, err := az.fileShareClient.Get(ctx, az.accountOptions.ResourceGroup, az.accountOptions.Name, name)
if err != nil {
return -1, err
}
return int(*share.FileShareProperties.ShareQuota), nil
}
67 changes: 67 additions & 0 deletions pkg/azurefile/azurefile_mgmt_client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
Copyright 2020 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 azurefile

import (
"fmt"
"reflect"
"testing"

"go.uber.org/mock/gomock"
"sigs.k8s.io/cloud-provider-azure/pkg/azclient/fileshareclient/mock_fileshareclient"
"sigs.k8s.io/cloud-provider-azure/pkg/azclient/mock_azclient"
"sigs.k8s.io/cloud-provider-azure/pkg/provider"
)

func TestNewAzureMgmtFileClientClientFactoryNil(t *testing.T) {
_, actualErr := newAzureFileMgmtClient(nil, nil)
if actualErr != nil {
expectedErr := fmt.Errorf("clientFactory is nil")
if !reflect.DeepEqual(actualErr, expectedErr) {
t.Errorf("actualErr: (%v), expectedErr: (%v)", actualErr, expectedErr)
}
}
}
func TestNewAzureMgmtFileClientAccountOptionNil(t *testing.T) {
cntl := gomock.NewController(t)
defer cntl.Finish()
_, actualErr := newAzureFileMgmtClient(mock_azclient.NewMockClientFactory(cntl), nil)
if actualErr != nil {
expectedErr := fmt.Errorf("accountOptions is nil")
if !reflect.DeepEqual(actualErr, expectedErr) {
t.Errorf("actualErr: (%v), expectedErr: (%v)", actualErr, expectedErr)
}
}
}

func TestNewAzureMgmtFileClient(t *testing.T) {
cntl := gomock.NewController(t)
defer cntl.Finish()
clientFactory := mock_azclient.NewMockClientFactory(cntl)
fileClient := mock_fileshareclient.NewMockInterface(cntl)
clientFactory.EXPECT().GetFileShareClientForSub("testsub").Return(fileClient, nil)
_, actualErr := newAzureFileMgmtClient(clientFactory, &provider.AccountOptions{
SubscriptionID: "testsub",
ResourceGroup: "testrg",
})
if actualErr != nil {
expectedErr := fmt.Errorf("accountOptions is nil")
if !reflect.DeepEqual(actualErr, expectedErr) {
t.Errorf("actualErr: (%v), expectedErr: (%v)", actualErr, expectedErr)
}
}
}
Loading

0 comments on commit ffce2a8

Please sign in to comment.