From 53bdc4e9d199cc3c37d6fa2aaaa0e3ad5e9db4e6 Mon Sep 17 00:00:00 2001 From: SHASHIKANTH MADDINENI Date: Fri, 12 May 2023 00:09:24 -0400 Subject: [PATCH] Re-use Access point. --- docs/README.md | 1 + .../specs/storageclass.yaml | 3 +- pkg/cloud/cloud.go | 61 +++++- pkg/cloud/cloud_test.go | 133 ++++++++++++- pkg/cloud/fakes.go | 6 +- pkg/driver/controller.go | 31 ++- pkg/driver/controller_test.go | 143 +++++++++---- pkg/driver/mocks/mock_cloud.go | 188 +++++++++++++++--- 8 files changed, 483 insertions(+), 83 deletions(-) diff --git a/docs/README.md b/docs/README.md index 1b8e2d0fa..e41ba16fd 100644 --- a/docs/README.md +++ b/docs/README.md @@ -37,6 +37,7 @@ The following CSI interfaces are implemented: | subPathPattern | | `/${.PV.name}` | true | The template used to construct the subPath under which each of the access points created under Dynamic Provisioning. Can be made up of fixed strings and limited variables, is akin to the 'subPathPattern' variable on the [nfs-subdir-external-provisioner](https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner) chart. Supports `.PVC.name`,`.PVC.namespace` and `.PV.name` | | ensureUniqueDirectory | | true | true | **NOTE: Only set this to false if you're sure this is the behaviour you want**.
Used when dynamic provisioning is enabled, if set to true, appends the a UID to the pattern specified in `subPathPattern` to ensure that access points will not accidentally point at the same directory. | | az | | "" | true | Used for cross-account mount. `az` under storage class parameter is optional. If specified, mount target associated with the az will be used for cross-account mount. If not specified, a random mount target will be picked for cross account mount | +| reuseAccessPoint | | false | true | When set to true, it creates Accesspoint client-token from the provided PVC name. So that the AccessPoint can be re-used from a differen cluster if same PVC name and storageclass configuration are used. | **Note** * Custom Posix group Id range for Access Point root directory must include both `gidRangeStart` and `gidRangeEnd` parameters. These parameters are optional only if both are omitted. If you specify one, the other becomes mandatory. diff --git a/examples/kubernetes/dynamic_provisioning/specs/storageclass.yaml b/examples/kubernetes/dynamic_provisioning/specs/storageclass.yaml index 14c9a8efc..6bf895af6 100644 --- a/examples/kubernetes/dynamic_provisioning/specs/storageclass.yaml +++ b/examples/kubernetes/dynamic_provisioning/specs/storageclass.yaml @@ -11,4 +11,5 @@ parameters: gidRangeEnd: "2000" # optional basePath: "/dynamic_provisioning" # optional subPathPattern: "${.PVC.namespace}/${.PVC.name}" # optional - ensureUniqueDirectory: "true" # optional \ No newline at end of file + ensureUniqueDirectory: "true" # optional + reuseAccessPoint: "false" # optional \ No newline at end of file diff --git a/pkg/cloud/cloud.go b/pkg/cloud/cloud.go index 0bcc46905..6d34e6561 100644 --- a/pkg/cloud/cloud.go +++ b/pkg/cloud/cloud.go @@ -35,7 +35,9 @@ import ( ) const ( - AccessDeniedException = "AccessDeniedException" + AccessDeniedException = "AccessDeniedException" + AccessPointAlreadyExists = "AccessPointAlreadyExists" + PvcNameTagKey = "pvcName" ) var ( @@ -94,7 +96,7 @@ type Efs interface { type Cloud interface { GetMetadata() MetadataService - CreateAccessPoint(ctx context.Context, volumeName string, accessPointOpts *AccessPointOptions) (accessPoint *AccessPoint, err error) + CreateAccessPoint(ctx context.Context, clientToken string, accessPointOpts *AccessPointOptions, reuseAccessPoint bool) (accessPoint *AccessPoint, err error) DeleteAccessPoint(ctx context.Context, accessPointId string) (err error) DescribeAccessPoint(ctx context.Context, accessPointId string) (accessPoint *AccessPoint, err error) ListAccessPoints(ctx context.Context, fileSystemId string) (accessPoints []*AccessPoint, err error) @@ -161,10 +163,28 @@ func (c *cloud) GetMetadata() MetadataService { return c.metadata } -func (c *cloud) CreateAccessPoint(ctx context.Context, volumeName string, accessPointOpts *AccessPointOptions) (accessPoint *AccessPoint, err error) { +func (c *cloud) CreateAccessPoint(ctx context.Context, clientToken string, accessPointOpts *AccessPointOptions, reuseAccessPoint bool) (accessPoint *AccessPoint, err error) { efsTags := parseEfsTags(accessPointOpts.Tags) + + //if reuseAccessPoint is true, check for AP with same Root Directory exists in efs + // if found reuse that AP + if reuseAccessPoint { + existingAP, err := c.findAccessPointByClientToken(ctx, clientToken, accessPointOpts) + if err != nil { + return nil, fmt.Errorf("failed to find access point: %v", err) + } + if existingAP != nil { + //AP path already exists + klog.V(2).Infof("Existing AccessPoint found : %+v", existingAP) + return &AccessPoint{ + AccessPointId: existingAP.AccessPointId, + FileSystemId: existingAP.FileSystemId, + CapacityGiB: accessPointOpts.CapacityGiB, + }, nil + } + } createAPInput := &efs.CreateAccessPointInput{ - ClientToken: &volumeName, + ClientToken: &clientToken, FileSystemId: &accessPointOpts.FileSystemId, PosixUser: &efs.PosixUser{ Gid: &accessPointOpts.Gid, @@ -189,6 +209,7 @@ func (c *cloud) CreateAccessPoint(ctx context.Context, volumeName string, access } return nil, fmt.Errorf("Failed to create access point: %v", err) } + klog.V(5).Infof("Create AP response : %+v", res) return &AccessPoint{ AccessPointId: *res.AccessPointId, @@ -240,6 +261,38 @@ func (c *cloud) DescribeAccessPoint(ctx context.Context, accessPointId string) ( }, nil } +func (c *cloud) findAccessPointByClientToken(ctx context.Context, clientToken string, accessPointOpts *AccessPointOptions) (accessPoint *AccessPoint, err error) { + klog.V(5).Infof("AccessPointOptions to find AP : %+v", accessPointOpts) + klog.V(2).Infof("ClientToken to find AP : %s", clientToken) + describeAPInput := &efs.DescribeAccessPointsInput{ + FileSystemId: &accessPointOpts.FileSystemId, + MaxResults: aws.Int64(1000), + } + res, err := c.efs.DescribeAccessPointsWithContext(ctx, describeAPInput) + if err != nil { + if isAccessDenied(err) { + return + } + if isFileSystemNotFound(err) { + return + } + err = fmt.Errorf("failed to list Access Points of efs = %s : %v", accessPointOpts.FileSystemId, err) + return + } + for _, ap := range res.AccessPoints { + // check if AP exists with same client token + if aws.StringValue(ap.ClientToken) == clientToken { + return &AccessPoint{ + AccessPointId: *ap.AccessPointId, + FileSystemId: *ap.FileSystemId, + AccessPointRootDir: *ap.RootDirectory.Path, + }, nil + } + } + klog.V(2).Infof("Access point does not exist") + return nil, nil +} + func (c *cloud) ListAccessPoints(ctx context.Context, fileSystemId string) (accessPoints []*AccessPoint, err error) { describeAPInput := &efs.DescribeAccessPointsInput{ FileSystemId: &fileSystemId, diff --git a/pkg/cloud/cloud_test.go b/pkg/cloud/cloud_test.go index 337e2441f..9e6dfbeb2 100644 --- a/pkg/cloud/cloud_test.go +++ b/pkg/cloud/cloud_test.go @@ -3,6 +3,7 @@ package cloud import ( "context" "errors" + "reflect" "testing" "github.com/aws/aws-sdk-go/aws" @@ -27,13 +28,14 @@ func TestCreateAccessPoint(t *testing.T) { directoryPerms = "0777" directoryPath = "/test" volName = "volName" + clientToken = volName ) testCases := []struct { name string testFunc func(t *testing.T) }{ { - name: "Success", + name: "Success - AP does not exist", testFunc: func(t *testing.T) { mockCtl := gomock.NewController(t) mockEfs := mocks.NewMockEfs(mockCtl) @@ -72,9 +74,63 @@ func TestCreateAccessPoint(t *testing.T) { }, } + describeAPOutput := &efs.DescribeAccessPointsOutput{ + AccessPoints: nil, + } + ctx := context.Background() + mockEfs.EXPECT().DescribeAccessPointsWithContext(gomock.Eq(ctx), gomock.Any()).Return(describeAPOutput, nil) mockEfs.EXPECT().CreateAccessPointWithContext(gomock.Eq(ctx), gomock.Any()).Return(output, nil) - res, err := c.CreateAccessPoint(ctx, volName, req) + res, err := c.CreateAccessPoint(ctx, clientToken, req, true) + + if err != nil { + t.Fatalf("CreateAccessPointFailed is failed: %v", err) + } + + if res == nil { + t.Fatal("Result is nil") + } + + if accessPointId != res.AccessPointId { + t.Fatalf("AccessPointId mismatched. Expected: %v, Actual: %v", accessPointId, res.AccessPointId) + } + + if fsId != res.FileSystemId { + t.Fatalf("FileSystemId mismatched. Expected: %v, Actual: %v", fsId, res.FileSystemId) + } + mockCtl.Finish() + }, + }, + { + name: "Success - AP already exists", + testFunc: func(t *testing.T) { + mockCtl := gomock.NewController(t) + mockEfs := mocks.NewMockEfs(mockCtl) + c := &cloud{ + efs: mockEfs, + } + + tags := make(map[string]string) + tags["cluster"] = "efs" + + req := &AccessPointOptions{ + FileSystemId: fsId, + Uid: uid, + Gid: gid, + DirectoryPerms: directoryPerms, + DirectoryPath: directoryPath, + Tags: tags, + } + + describeAPOutput := &efs.DescribeAccessPointsOutput{ + AccessPoints: []*efs.AccessPointDescription{ + {AccessPointId: aws.String(accessPointId), FileSystemId: aws.String(fsId), ClientToken: aws.String(clientToken), RootDirectory: &efs.RootDirectory{Path: aws.String(directoryPath)}, Tags: []*efs.Tag{{Key: aws.String(PvcNameTagKey), Value: aws.String(volName)}}}, + }, + } + + ctx := context.Background() + mockEfs.EXPECT().DescribeAccessPointsWithContext(gomock.Eq(ctx), gomock.Any()).Return(describeAPOutput, nil) + res, err := c.CreateAccessPoint(ctx, clientToken, req, true) if err != nil { t.Fatalf("CreateAccessPointFailed is failed: %v", err) @@ -108,10 +164,14 @@ func TestCreateAccessPoint(t *testing.T) { DirectoryPerms: directoryPerms, DirectoryPath: directoryPath, } + describeAPOutput := &efs.DescribeAccessPointsOutput{ + AccessPoints: nil, + } ctx := context.Background() + mockEfs.EXPECT().DescribeAccessPointsWithContext(gomock.Eq(ctx), gomock.Any()).Return(describeAPOutput, nil) mockEfs.EXPECT().CreateAccessPointWithContext(gomock.Eq(ctx), gomock.Any()).Return(nil, errors.New("CreateAccessPointWithContext failed")) - _, err := c.CreateAccessPoint(ctx, volName, req) + _, err := c.CreateAccessPoint(ctx, clientToken, req, true) if err == nil { t.Fatalf("CreateAccessPoint did not fail") } @@ -135,7 +195,7 @@ func TestCreateAccessPoint(t *testing.T) { ctx := context.Background() mockEfs.EXPECT().CreateAccessPointWithContext(gomock.Eq(ctx), gomock.Any()).Return(nil, awserr.New(AccessDeniedException, "Access Denied", errors.New("Access Denied"))) - _, err := c.CreateAccessPoint(ctx, volName, req) + _, err := c.CreateAccessPoint(ctx, clientToken, req, false) if err == nil { t.Fatalf("CreateAccessPoint did not fail") } @@ -862,3 +922,68 @@ func testResult(t *testing.T, funcName string, ret interface{}, err error, expec } } } + +func Test_findAccessPointByPath(t *testing.T) { + fsId := "testFsId" + clientToken := "testPvcName" + dirPath := "testPath" + diffClientToken := aws.String("diff") + + mockctl := gomock.NewController(t) + defer mockctl.Finish() + mockEfs := mocks.NewMockEfs(mockctl) + + expectedSingleAP := &AccessPoint{ + AccessPointId: "testApId", + AccessPointRootDir: dirPath, + FileSystemId: fsId, + } + + type args struct { + clientToken string + accessPointOpts *AccessPointOptions + } + tests := []struct { + name string + args args + prepare func(*mocks.MockEfs) + wantAccessPoint *AccessPoint + wantErr bool + }{ + {name: "Expected_ClientToken_Not_Found", args: args{clientToken, &AccessPointOptions{FileSystemId: fsId, DirectoryPath: dirPath}}, prepare: func(mockEfs *mocks.MockEfs) { + mockEfs.EXPECT().DescribeAccessPointsWithContext(gomock.Any(), gomock.Any()).Return(&efs.DescribeAccessPointsOutput{ + AccessPoints: []*efs.AccessPointDescription{{FileSystemId: aws.String(fsId), ClientToken: diffClientToken, AccessPointId: aws.String(expectedSingleAP.AccessPointId), RootDirectory: &efs.RootDirectory{Path: aws.String("differentPath")}}}, + }, nil) + }, wantAccessPoint: nil, wantErr: false}, + {name: "Expected_Path_Found_In_Multiple_APs_And_One_AP_Filtered_By_ClientToken", args: args{clientToken, &AccessPointOptions{FileSystemId: fsId, DirectoryPath: dirPath}}, prepare: func(mockEfs *mocks.MockEfs) { + mockEfs.EXPECT().DescribeAccessPointsWithContext(gomock.Any(), gomock.Any()).Return(&efs.DescribeAccessPointsOutput{ + AccessPoints: []*efs.AccessPointDescription{ + {FileSystemId: aws.String(fsId), ClientToken: diffClientToken, AccessPointId: aws.String("differentApId"), RootDirectory: &efs.RootDirectory{Path: aws.String(expectedSingleAP.AccessPointRootDir)}}, + {FileSystemId: aws.String(fsId), ClientToken: &clientToken, AccessPointId: aws.String(expectedSingleAP.AccessPointId), RootDirectory: &efs.RootDirectory{Path: aws.String(expectedSingleAP.AccessPointRootDir)}}, + }, + }, nil) + }, wantAccessPoint: expectedSingleAP, wantErr: false}, + {name: "Fail_DescribeAccessPoints", args: args{clientToken, &AccessPointOptions{FileSystemId: fsId, DirectoryPath: dirPath}}, prepare: func(mockEfs *mocks.MockEfs) { + mockEfs.EXPECT().DescribeAccessPointsWithContext(gomock.Any(), gomock.Any()).Return(nil, errors.New("access_denied")) + }, wantAccessPoint: nil, wantErr: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &cloud{efs: mockEfs} + ctx := context.Background() + + if tt.prepare != nil { + tt.prepare(mockEfs) + } + + gotAccessPoint, err := c.findAccessPointByClientToken(ctx, tt.args.clientToken, tt.args.accessPointOpts) + if (err != nil) != tt.wantErr { + t.Errorf("findAccessPointByClientToken() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotAccessPoint, tt.wantAccessPoint) { + t.Errorf("findAccessPointByClientToken() gotAccessPoint = %v, want %v", gotAccessPoint, tt.wantAccessPoint) + } + }) + } +} diff --git a/pkg/cloud/fakes.go b/pkg/cloud/fakes.go index 5cbb2af5d..49953665b 100644 --- a/pkg/cloud/fakes.go +++ b/pkg/cloud/fakes.go @@ -27,8 +27,8 @@ func (c *FakeCloudProvider) GetMetadata() MetadataService { return c.m } -func (c *FakeCloudProvider) CreateAccessPoint(ctx context.Context, volumeName string, accessPointOpts *AccessPointOptions) (accessPoint *AccessPoint, err error) { - ap, exists := c.accessPoints[volumeName] +func (c *FakeCloudProvider) CreateAccessPoint(ctx context.Context, clientToken string, accessPointOpts *AccessPointOptions, usePvcName bool) (accessPoint *AccessPoint, err error) { + ap, exists := c.accessPoints[clientToken] if exists { if accessPointOpts.CapacityGiB == ap.CapacityGiB { return ap, nil @@ -45,7 +45,7 @@ func (c *FakeCloudProvider) CreateAccessPoint(ctx context.Context, volumeName st CapacityGiB: accessPointOpts.CapacityGiB, } - c.accessPoints[volumeName] = ap + c.accessPoints[clientToken] = ap return ap, nil } diff --git a/pkg/driver/controller.go b/pkg/driver/controller.go index be82c5445..695c4e2fa 100644 --- a/pkg/driver/controller.go +++ b/pkg/driver/controller.go @@ -18,6 +18,7 @@ package driver import ( "context" + "crypto/sha256" "fmt" "github.com/google/uuid" "os" @@ -56,6 +57,8 @@ const ( SubPathPattern = "subPathPattern" TempMountPathPrefix = "/var/lib/csi/pv" Uid = "uid" + ReuseAccessPointKey = "reuseAccessPoint" + PvcNameKey = "csi.storage.k8s.io/pvc/name" ) var ( @@ -74,7 +77,25 @@ var ( func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) { klog.V(4).Infof("CreateVolume: called with args %+v", *req) + + var reuseAccessPoint bool + var err error + volumeParams := req.GetParameters() volName := req.GetName() + clientToken := volName + + // if true, then use sha256 hash of pvcName as clientToken instead of PVC Id + // This allows users to reconnect to the same AP from different k8s cluster + if reuseAccessPointStr, ok := volumeParams[ReuseAccessPointKey]; ok { + reuseAccessPoint, err = strconv.ParseBool(reuseAccessPointStr) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "Invalid value for reuseAccessPoint parameter") + } + if reuseAccessPoint { + clientToken = get64LenHash(volumeParams[PvcNameKey]) + klog.V(5).Infof("Client token : %s", clientToken) + } + } if volName == "" { return nil, status.Error(codes.InvalidArgument, "Volume name not provided") } @@ -98,7 +119,6 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) var ( azName string basePath string - err error gid int64 gidMin int gidMax int @@ -109,7 +129,6 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) ) //Parse parameters - volumeParams := req.GetParameters() if value, ok := volumeParams[ProvisioningMode]; ok { provisioningMode = value //TODO: Add FS provisioning mode check when implemented @@ -287,7 +306,7 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) accessPointsOptions.Gid = gid accessPointsOptions.DirectoryPath = rootDir - accessPointId, err := localCloud.CreateAccessPoint(ctx, volName, accessPointsOptions) + accessPointId, err := localCloud.CreateAccessPoint(ctx, clientToken, accessPointsOptions, reuseAccessPoint) if err != nil { if err == cloud.ErrAccessDenied { return nil, status.Errorf(codes.Unauthenticated, "Access Denied. Please ensure you have the right AWS permissions: %v", err) @@ -565,3 +584,9 @@ func validateEfsPathRequirements(proposedPath string) (bool, error) { return true, nil } } + +func get64LenHash(text string) string { + h := sha256.New() + h.Write([]byte(text)) + return fmt.Sprintf("%x", h.Sum(nil)) +} diff --git a/pkg/driver/controller_test.go b/pkg/driver/controller_test.go index 7d93ae990..3d702f522 100644 --- a/pkg/driver/controller_test.go +++ b/pkg/driver/controller_test.go @@ -79,8 +79,8 @@ func TestCreateVolume(t *testing.T) { FileSystemId: fsId, } mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Eq(volumeName), gomock.Any(), gomock.Eq(false)).Return(accessPoint, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if accessPointOpts.Uid != 1000 { t.Fatalf("Uid mimatched. Expected: %v, actual: %v", accessPointOpts.Uid, 1000) } @@ -146,8 +146,8 @@ func TestCreateVolume(t *testing.T) { FileSystemId: fsId, } mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(accessPoint, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if accessPointOpts.Uid != 1000 { t.Fatalf("Uid mimatched. Expected: %v, actual: %v", accessPointOpts.Uid, 1000) } @@ -232,8 +232,8 @@ func TestCreateVolume(t *testing.T) { var expectedGid int64 = 1001 //1003 and 1002 are taken, next available is 1001 mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(accessPoints, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), false).Return(accessPoint, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if accessPointOpts.Uid != expectedGid { t.Fatalf("Uid mismatched. Expected: %v, actual: %v", expectedGid, accessPointOpts.Uid) } @@ -331,8 +331,8 @@ func TestCreateVolume(t *testing.T) { mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(accessPoints, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(ap2, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), false).Return(ap2, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if accessPointOpts.Uid != expectedGid { t.Fatalf("Uid mismatched. Expected: %v, actual: %v", expectedGid, accessPointOpts.Uid) } @@ -349,8 +349,8 @@ func TestCreateVolume(t *testing.T) { mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(accessPoints, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(ap3, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), false).Return(ap3, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if accessPointOpts.Uid != expectedGid { t.Fatalf("Uid mismatched. Expected: %v, actual: %v", expectedGid, accessPointOpts.Uid) } @@ -366,8 +366,8 @@ func TestCreateVolume(t *testing.T) { expectedGid = 1003 mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(accessPoints, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(ap2, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), false).Return(ap2, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if accessPointOpts.Uid != expectedGid { t.Fatalf("Uid mismatched. Expected: %v, actual: %v", expectedGid, accessPointOpts.Uid) } @@ -457,8 +457,8 @@ func TestCreateVolume(t *testing.T) { expectedGid := 1001 mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(accessPoints, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(lastAccessPoint, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), false).Return(lastAccessPoint, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if accessPointOpts.Uid != int64(expectedGid) { t.Fatalf("Uid mismatched. Expected: %v, actual: %v", expectedGid, accessPointOpts.Uid) } @@ -533,7 +533,7 @@ func TestCreateVolume(t *testing.T) { accessPoints := []*cloud.AccessPoint{accessPoint} mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(accessPoints, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil) + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Eq(volumeName), gomock.Any(), gomock.Any()).Return(accessPoint, nil) res, err := driver.CreateVolume(ctx, req) @@ -593,7 +593,7 @@ func TestCreateVolume(t *testing.T) { accessPoints := []*cloud.AccessPoint{accessPoint} mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(accessPoints, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil) + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(accessPoint, nil) res, err := driver.CreateVolume(ctx, req) @@ -656,7 +656,7 @@ func TestCreateVolume(t *testing.T) { accessPoints := []*cloud.AccessPoint{accessPoint} mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(accessPoints, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil) + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(accessPoint, nil) res, err := driver.CreateVolume(ctx, req) @@ -719,7 +719,7 @@ func TestCreateVolume(t *testing.T) { accessPoints := []*cloud.AccessPoint{accessPoint} mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(accessPoints, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil) + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(accessPoint, nil) res, err := driver.CreateVolume(ctx, req) @@ -737,6 +737,75 @@ func TestCreateVolume(t *testing.T) { mockCtl.Finish() }, }, + { + name: "Success: reuseAccessPointName is true", + testFunc: func(t *testing.T) { + mockCtl := gomock.NewController(t) + mockCloud := mocks.NewMockCloud(mockCtl) + + driver := &Driver{ + endpoint: endpoint, + cloud: mockCloud, + gidAllocator: NewGidAllocator(mockCloud), + tags: parseTagsFromStr(""), + } + pvcNameVal := "test-pvc" + + req := &csi.CreateVolumeRequest{ + Name: volumeName, + VolumeCapabilities: []*csi.VolumeCapability{ + stdVolCap, + }, + CapacityRange: &csi.CapacityRange{ + RequiredBytes: capacityRange, + }, + Parameters: map[string]string{ + ProvisioningMode: "efs-ap", + FsId: fsId, + GidMin: "1000", + GidMax: "2000", + DirectoryPerms: "777", + AzName: "us-east-1a", + ReuseAccessPointKey: "true", + PvcNameKey: pvcNameVal, + }, + } + + ctx := context.Background() + fileSystem := &cloud.FileSystem{ + FileSystemId: fsId, + } + + accessPoint := &cloud.AccessPoint{ + AccessPointId: apId, + FileSystemId: fsId, + PosixUser: &cloud.PosixUser{ + Gid: 1000, + Uid: 1000, + }, + } + accessPoints := []*cloud.AccessPoint{accessPoint} + mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) + mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(accessPoints, nil) + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Eq(get64LenHash(pvcNameVal)), gomock.Any(), gomock.Any()).Return(accessPoint, nil) + + res, err := driver.CreateVolume(ctx, req) + + if err != nil { + t.Fatalf("CreateVolume failed: %v", err) + } + + if res.Volume == nil { + t.Fatal("Volume is nil") + } + + if res.Volume.VolumeId != volumeId { + t.Fatalf("Volume Id mismatched. Expected: %v, Actual: %v", volumeId, res.Volume.VolumeId) + } + + mockCtl.Finish() + }, + }, { name: "Success: Normal flow with a valid directory structure set", testFunc: func(t *testing.T) { @@ -785,8 +854,8 @@ func TestCreateVolume(t *testing.T) { mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(nil, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(accessPoint, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPoint bool) { if !verifyPathWhenUUIDIncluded(accessPointOpts.DirectoryPath, directoryCreated) { t.Fatalf("Root directory mismatch. Expected: %v (with UID appended), actual: %v", directoryCreated, @@ -857,8 +926,8 @@ func TestCreateVolume(t *testing.T) { mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(nil, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(accessPoint, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if !verifyPathWhenUUIDIncluded(accessPointOpts.DirectoryPath, directoryCreated) { t.Fatalf("Root directory mismatch. Expected: %v (with UID appended), actual: %v", directoryCreated, @@ -932,8 +1001,8 @@ func TestCreateVolume(t *testing.T) { mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(nil, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(accessPoint, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if !verifyPathWhenUUIDIncluded(accessPointOpts.DirectoryPath, directoryCreated) { t.Fatalf("Root directory mismatch. Expected: %v (with UID appended), actual: %v", directoryCreated, @@ -1007,8 +1076,8 @@ func TestCreateVolume(t *testing.T) { mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(nil, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(accessPoint, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if accessPointOpts.DirectoryPath != directoryCreated { t.Fatalf("Root directory mismatch. Expected: %v, actual: %v", directoryCreated, @@ -1081,8 +1150,8 @@ func TestCreateVolume(t *testing.T) { mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(nil, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(accessPoint, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if !verifyPathWhenUUIDIncluded(accessPointOpts.DirectoryPath, directoryCreated) { t.Fatalf("Root directory mismatch. Expected: %v (with UID appended), actual: %v", directoryCreated, @@ -1150,8 +1219,8 @@ func TestCreateVolume(t *testing.T) { mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(nil, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(accessPoint, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if accessPointOpts.DirectoryPath != "/" { t.Fatalf("Root directory mismatch. Expected: %v, actual: %v", "/", @@ -1220,8 +1289,8 @@ func TestCreateVolume(t *testing.T) { mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(nil, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(accessPoint, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if accessPointOpts.DirectoryPath != "/" { t.Fatalf("Root directory mismatch. Expected: %v, actual: %v", "/", @@ -1292,8 +1361,8 @@ func TestCreateVolume(t *testing.T) { mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return(nil, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(accessPoint, nil). - Do(func(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) { + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(accessPoint, nil). + Do(func(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, reuseAccessPointName bool) { if !verifyPathWhenUUIDIncluded(accessPointOpts.DirectoryPath, directoryCreated) { t.Fatalf("Root directory mismatch. Expected: %v (with UID appended), actual: %v", directoryCreated, @@ -2188,7 +2257,7 @@ func TestCreateVolume(t *testing.T) { } mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return([]*cloud.AccessPoint{}, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(nil, errors.New("CreateAccessPoint call failed")) + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("CreateAccessPoint call failed")) _, err := driver.CreateVolume(ctx, req) if err == nil { t.Fatal("CreateVolume did not fail") @@ -2231,7 +2300,7 @@ func TestCreateVolume(t *testing.T) { } mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil) mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return([]*cloud.AccessPoint{}, nil) - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(nil, cloud.ErrAccessDenied) + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, cloud.ErrAccessDenied) _, err := driver.CreateVolume(ctx, req) if err == nil { t.Fatal("CreateVolume did not fail") @@ -2290,7 +2359,7 @@ func TestCreateVolume(t *testing.T) { } mockCloud.EXPECT().DescribeFileSystem(gomock.Eq(ctx), gomock.Any()).Return(fileSystem, nil).AnyTimes() mockCloud.EXPECT().ListAccessPoints(gomock.Eq(ctx), gomock.Any()).Return([]*cloud.AccessPoint{ap1, ap2}, nil).AnyTimes() - mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any()).Return(ap2, nil).AnyTimes() + mockCloud.EXPECT().CreateAccessPoint(gomock.Eq(ctx), gomock.Any(), gomock.Any(), gomock.Any()).Return(ap2, nil).AnyTimes() var err error // All GIDs from available range are taken, CreateVolume should fail. diff --git a/pkg/driver/mocks/mock_cloud.go b/pkg/driver/mocks/mock_cloud.go index 557e5b9a5..eacf69fae 100644 --- a/pkg/driver/mocks/mock_cloud.go +++ b/pkg/driver/mocks/mock_cloud.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/kubernetes-sigs/aws-efs-csi-driver/pkg/cloud (interfaces: Cloud) +// Source: ./pkg/cloud/cloud.go // Package mock_cloud is a generated GoMock package. package mocks @@ -8,90 +8,216 @@ import ( context "context" reflect "reflect" + aws "github.com/aws/aws-sdk-go/aws" + request "github.com/aws/aws-sdk-go/aws/request" + efs "github.com/aws/aws-sdk-go/service/efs" gomock "github.com/golang/mock/gomock" cloud "github.com/kubernetes-sigs/aws-efs-csi-driver/pkg/cloud" ) -// MockCloud is a mock of Cloud interface +// MockEfs is a mock of Efs interface. +type MockEfs struct { + ctrl *gomock.Controller + recorder *MockEfsMockRecorder +} + +// MockEfsMockRecorder is the mock recorder for MockEfs. +type MockEfsMockRecorder struct { + mock *MockEfs +} + +// NewMockEfs creates a new mock instance. +func NewMockEfs(ctrl *gomock.Controller) *MockEfs { + mock := &MockEfs{ctrl: ctrl} + mock.recorder = &MockEfsMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockEfs) EXPECT() *MockEfsMockRecorder { + return m.recorder +} + +// CreateAccessPointWithContext mocks base method. +func (m *MockEfs) CreateAccessPointWithContext(arg0 aws.Context, arg1 *efs.CreateAccessPointInput, arg2 ...request.Option) (*efs.CreateAccessPointOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateAccessPointWithContext", varargs...) + ret0, _ := ret[0].(*efs.CreateAccessPointOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateAccessPointWithContext indicates an expected call of CreateAccessPointWithContext. +func (mr *MockEfsMockRecorder) CreateAccessPointWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessPointWithContext", reflect.TypeOf((*MockEfs)(nil).CreateAccessPointWithContext), varargs...) +} + +// DeleteAccessPointWithContext mocks base method. +func (m *MockEfs) DeleteAccessPointWithContext(arg0 aws.Context, arg1 *efs.DeleteAccessPointInput, arg2 ...request.Option) (*efs.DeleteAccessPointOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteAccessPointWithContext", varargs...) + ret0, _ := ret[0].(*efs.DeleteAccessPointOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteAccessPointWithContext indicates an expected call of DeleteAccessPointWithContext. +func (mr *MockEfsMockRecorder) DeleteAccessPointWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessPointWithContext", reflect.TypeOf((*MockEfs)(nil).DeleteAccessPointWithContext), varargs...) +} + +// DescribeAccessPointsWithContext mocks base method. +func (m *MockEfs) DescribeAccessPointsWithContext(arg0 aws.Context, arg1 *efs.DescribeAccessPointsInput, arg2 ...request.Option) (*efs.DescribeAccessPointsOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeAccessPointsWithContext", varargs...) + ret0, _ := ret[0].(*efs.DescribeAccessPointsOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DescribeAccessPointsWithContext indicates an expected call of DescribeAccessPointsWithContext. +func (mr *MockEfsMockRecorder) DescribeAccessPointsWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAccessPointsWithContext", reflect.TypeOf((*MockEfs)(nil).DescribeAccessPointsWithContext), varargs...) +} + +// DescribeFileSystemsWithContext mocks base method. +func (m *MockEfs) DescribeFileSystemsWithContext(arg0 aws.Context, arg1 *efs.DescribeFileSystemsInput, arg2 ...request.Option) (*efs.DescribeFileSystemsOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeFileSystemsWithContext", varargs...) + ret0, _ := ret[0].(*efs.DescribeFileSystemsOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DescribeFileSystemsWithContext indicates an expected call of DescribeFileSystemsWithContext. +func (mr *MockEfsMockRecorder) DescribeFileSystemsWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeFileSystemsWithContext", reflect.TypeOf((*MockEfs)(nil).DescribeFileSystemsWithContext), varargs...) +} + +// DescribeMountTargetsWithContext mocks base method. +func (m *MockEfs) DescribeMountTargetsWithContext(arg0 aws.Context, arg1 *efs.DescribeMountTargetsInput, arg2 ...request.Option) (*efs.DescribeMountTargetsOutput, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeMountTargetsWithContext", varargs...) + ret0, _ := ret[0].(*efs.DescribeMountTargetsOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DescribeMountTargetsWithContext indicates an expected call of DescribeMountTargetsWithContext. +func (mr *MockEfsMockRecorder) DescribeMountTargetsWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeMountTargetsWithContext", reflect.TypeOf((*MockEfs)(nil).DescribeMountTargetsWithContext), varargs...) +} + +// MockCloud is a mock of Cloud interface. type MockCloud struct { ctrl *gomock.Controller recorder *MockCloudMockRecorder } -// MockCloudMockRecorder is the mock recorder for MockCloud +// MockCloudMockRecorder is the mock recorder for MockCloud. type MockCloudMockRecorder struct { mock *MockCloud } -// NewMockCloud creates a new mock instance +// NewMockCloud creates a new mock instance. func NewMockCloud(ctrl *gomock.Controller) *MockCloud { mock := &MockCloud{ctrl: ctrl} mock.recorder = &MockCloudMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockCloud) EXPECT() *MockCloudMockRecorder { return m.recorder } -// CreateAccessPoint mocks base method -func (m *MockCloud) CreateAccessPoint(ctx context.Context, volumeName string, accessPointOpts *cloud.AccessPointOptions) (*cloud.AccessPoint, error) { +// CreateAccessPoint mocks base method. +func (m *MockCloud) CreateAccessPoint(ctx context.Context, clientToken string, accessPointOpts *cloud.AccessPointOptions, usePvcName bool) (*cloud.AccessPoint, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateAccessPoint", ctx, volumeName, accessPointOpts) + ret := m.ctrl.Call(m, "CreateAccessPoint", ctx, clientToken, accessPointOpts, usePvcName) ret0, _ := ret[0].(*cloud.AccessPoint) ret1, _ := ret[1].(error) return ret0, ret1 } -// CreateAccessPoint indicates an expected call of CreateAccessPoint -func (mr *MockCloudMockRecorder) CreateAccessPoint(ctx, volumeName, accessPointOpts interface{}) *gomock.Call { +// CreateAccessPoint indicates an expected call of CreateAccessPoint. +func (mr *MockCloudMockRecorder) CreateAccessPoint(ctx, clientToken, accessPointOpts, usePvcName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessPoint", reflect.TypeOf((*MockCloud)(nil).CreateAccessPoint), ctx, volumeName, accessPointOpts) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccessPoint", reflect.TypeOf((*MockCloud)(nil).CreateAccessPoint), ctx, clientToken, accessPointOpts, usePvcName) } -// DeleteAccessPoint mocks base method -func (m *MockCloud) DeleteAccessPoint(arg0 context.Context, arg1 string) error { +// DeleteAccessPoint mocks base method. +func (m *MockCloud) DeleteAccessPoint(ctx context.Context, accessPointId string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteAccessPoint", arg0, arg1) + ret := m.ctrl.Call(m, "DeleteAccessPoint", ctx, accessPointId) ret0, _ := ret[0].(error) return ret0 } -// DeleteAccessPoint indicates an expected call of DeleteAccessPoint -func (mr *MockCloudMockRecorder) DeleteAccessPoint(arg0, arg1 interface{}) *gomock.Call { +// DeleteAccessPoint indicates an expected call of DeleteAccessPoint. +func (mr *MockCloudMockRecorder) DeleteAccessPoint(ctx, accessPointId interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessPoint", reflect.TypeOf((*MockCloud)(nil).DeleteAccessPoint), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAccessPoint", reflect.TypeOf((*MockCloud)(nil).DeleteAccessPoint), ctx, accessPointId) } -// DescribeAccessPoint mocks base method -func (m *MockCloud) DescribeAccessPoint(arg0 context.Context, arg1 string) (*cloud.AccessPoint, error) { +// DescribeAccessPoint mocks base method. +func (m *MockCloud) DescribeAccessPoint(ctx context.Context, accessPointId string) (*cloud.AccessPoint, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeAccessPoint", arg0, arg1) + ret := m.ctrl.Call(m, "DescribeAccessPoint", ctx, accessPointId) ret0, _ := ret[0].(*cloud.AccessPoint) ret1, _ := ret[1].(error) return ret0, ret1 } -// DescribeAccessPoint indicates an expected call of DescribeAccessPoint -func (mr *MockCloudMockRecorder) DescribeAccessPoint(arg0, arg1 interface{}) *gomock.Call { +// DescribeAccessPoint indicates an expected call of DescribeAccessPoint. +func (mr *MockCloudMockRecorder) DescribeAccessPoint(ctx, accessPointId interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAccessPoint", reflect.TypeOf((*MockCloud)(nil).DescribeAccessPoint), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAccessPoint", reflect.TypeOf((*MockCloud)(nil).DescribeAccessPoint), ctx, accessPointId) } -// DescribeFileSystem mocks base method -func (m *MockCloud) DescribeFileSystem(arg0 context.Context, arg1 string) (*cloud.FileSystem, error) { +// DescribeFileSystem mocks base method. +func (m *MockCloud) DescribeFileSystem(ctx context.Context, fileSystemId string) (*cloud.FileSystem, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeFileSystem", arg0, arg1) + ret := m.ctrl.Call(m, "DescribeFileSystem", ctx, fileSystemId) ret0, _ := ret[0].(*cloud.FileSystem) ret1, _ := ret[1].(error) return ret0, ret1 } -// DescribeFileSystem indicates an expected call of DescribeFileSystem -func (mr *MockCloudMockRecorder) DescribeFileSystem(arg0, arg1 interface{}) *gomock.Call { +// DescribeFileSystem indicates an expected call of DescribeFileSystem. +func (mr *MockCloudMockRecorder) DescribeFileSystem(ctx, fileSystemId interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeFileSystem", reflect.TypeOf((*MockCloud)(nil).DescribeFileSystem), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeFileSystem", reflect.TypeOf((*MockCloud)(nil).DescribeFileSystem), ctx, fileSystemId) } // DescribeMountTargets mocks base method. @@ -109,7 +235,7 @@ func (mr *MockCloudMockRecorder) DescribeMountTargets(ctx, fileSystemId, az inte return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeMountTargets", reflect.TypeOf((*MockCloud)(nil).DescribeMountTargets), ctx, fileSystemId, az) } -// GetMetadata mocks base method +// GetMetadata mocks base method. func (m *MockCloud) GetMetadata() cloud.MetadataService { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetMetadata") @@ -117,7 +243,7 @@ func (m *MockCloud) GetMetadata() cloud.MetadataService { return ret0 } -// GetMetadata indicates an expected call of GetMetadata +// GetMetadata indicates an expected call of GetMetadata. func (mr *MockCloudMockRecorder) GetMetadata() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetadata", reflect.TypeOf((*MockCloud)(nil).GetMetadata))