diff --git a/cmd/main.go b/cmd/main.go index 82df25ff5..5bacc3ab6 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -30,6 +30,7 @@ func main() { drv, err := driver.NewDriver( driver.WithEndpoint(options.ServerOptions.Endpoint), + driver.WithExtraTags(options.ControllerOptions.ExtraTags), driver.WithExtraVolumeTags(options.ControllerOptions.ExtraVolumeTags), driver.WithMode(options.DriverMode), driver.WithVolumeAttachLimit(options.NodeOptions.VolumeAttachLimit), diff --git a/cmd/options/controller_options.go b/cmd/options/controller_options.go index 314b7c39a..9b6287f2f 100644 --- a/cmd/options/controller_options.go +++ b/cmd/options/controller_options.go @@ -24,15 +24,19 @@ import ( // ControllerOptions contains options and configuration settings for the controller service. type ControllerOptions struct { + // ExtraTags is a map of tags that will be attached to each dynamically provisioned + // resource. + ExtraTags map[string]string // ExtraVolumeTags is a map of tags that will be attached to each dynamically provisioned // volume. + // DEPRECATED: Use ExtraTags instead. ExtraVolumeTags map[string]string - // ID of the kubernetes cluster. This is used only to create the same tags on volumes that - // in-tree volume volume plugin does. + // ID of the kubernetes cluster. KubernetesClusterID string } func (s *ControllerOptions) AddFlags(fs *flag.FlagSet) { - fs.Var(cliflag.NewMapStringString(&s.ExtraVolumeTags), "extra-volume-tags", "Extra volume tags to attach to each dynamically provisioned volume. It is a comma separated list of key value pairs like '=,='") + fs.Var(cliflag.NewMapStringString(&s.ExtraTags), "extra-tags", "Extra tags to attach to each dynamically provisioned resource. It is a comma separated list of key value pairs like '=,='") + fs.Var(cliflag.NewMapStringString(&s.ExtraVolumeTags), "extra-volume-tags", "DEPRECATED: Please use --extra-tags instead. Extra volume tags to attach to each dynamically provisioned volume. It is a comma separated list of key value pairs like '=,='") fs.StringVar(&s.KubernetesClusterID, "k8s-tag-cluster-id", "", "ID of the Kubernetes cluster used for tagging provisioned EBS volumes (optional).") } diff --git a/cmd/options_test.go b/cmd/options_test.go index ef4bffe19..37743a90c 100644 --- a/cmd/options_test.go +++ b/cmd/options_test.go @@ -39,11 +39,11 @@ func TestGetOptions(t *testing.T) { endpointFlagName := "endpoint" endpoint := "foo" - extraVolumeTagsFlagName := "extra-volume-tags" - extraVolumeTagKey := "bar" - extraVolumeTagValue := "baz" - extraVolumeTags := map[string]string{ - extraVolumeTagKey: extraVolumeTagValue, + extraTagsFlagName := "extra-tags" + extraTagKey := "bar" + extraTagValue := "baz" + extraTags := map[string]string{ + extraTagKey: extraTagValue, } VolumeAttachLimitFlagName := "volume-attach-limit" @@ -57,7 +57,7 @@ func TestGetOptions(t *testing.T) { args = append(args, "-"+endpointFlagName+"="+endpoint) } if withControllerOptions { - args = append(args, "-"+extraVolumeTagsFlagName+"="+extraVolumeTagKey+"="+extraVolumeTagValue) + args = append(args, "-"+extraTagsFlagName+"="+extraTagKey+"="+extraTagValue) } if withNodeOptions { args = append(args, "-"+VolumeAttachLimitFlagName+"="+strconv.FormatInt(VolumeAttachLimit, 10)) @@ -80,12 +80,12 @@ func TestGetOptions(t *testing.T) { } if withControllerOptions { - extraVolumeTagsFlag := flagSet.Lookup(extraVolumeTagsFlagName) - if extraVolumeTagsFlag == nil { - t.Fatalf("expected %q flag to be added but it is not", extraVolumeTagsFlagName) + extraTagsFlag := flagSet.Lookup(extraTagsFlagName) + if extraTagsFlag == nil { + t.Fatalf("expected %q flag to be added but it is not", extraTagsFlagName) } - if !reflect.DeepEqual(options.ControllerOptions.ExtraVolumeTags, extraVolumeTags) { - t.Fatalf("expected extra volume tags to be %q but it is %q", extraVolumeTags, options.ControllerOptions.ExtraVolumeTags) + if !reflect.DeepEqual(options.ControllerOptions.ExtraTags, extraTags) { + t.Fatalf("expected extra tags to be %q but it is %q", extraTags, options.ControllerOptions.ExtraTags) } } diff --git a/pkg/cloud/cloud.go b/pkg/cloud/cloud.go index 56ca0d9dc..47d15b048 100644 --- a/pkg/cloud/cloud.go +++ b/pkg/cloud/cloud.go @@ -533,7 +533,9 @@ func (c *cloud) CreateSnapshot(ctx context.Context, volumeID string, snapshotOpt var tags []*ec2.Tag for key, value := range snapshotOptions.Tags { - tags = append(tags, &ec2.Tag{Key: &key, Value: &value}) + copiedKey := key + copiedValue := value + tags = append(tags, &ec2.Tag{Key: &copiedKey, Value: &copiedValue}) } tagSpec := ec2.TagSpecification{ ResourceType: aws.String("snapshot"), diff --git a/pkg/cloud/cloud_test.go b/pkg/cloud/cloud_test.go index d85683ef1..b7d6e4b7a 100644 --- a/pkg/cloud/cloud_test.go +++ b/pkg/cloud/cloud_test.go @@ -20,6 +20,8 @@ import ( "context" "errors" "fmt" + "reflect" + "sort" "strings" "testing" @@ -562,6 +564,7 @@ func TestCreateSnapshot(t *testing.T) { name string snapshotName string snapshotOptions *SnapshotOptions + expInput *ec2.CreateSnapshotInput expSnapshot *Snapshot expErr error }{ @@ -571,8 +574,29 @@ func TestCreateSnapshot(t *testing.T) { snapshotOptions: &SnapshotOptions{ Tags: map[string]string{ SnapshotNameTagKey: "snap-test-name", + "extra-tag-key": "extra-tag-value", }, }, + expInput: &ec2.CreateSnapshotInput{ + VolumeId: aws.String("snap-test-volume"), + DryRun: aws.Bool(false), + TagSpecifications: []*ec2.TagSpecification{ + { + ResourceType: aws.String("snapshot"), + Tags: []*ec2.Tag{ + { + Key: aws.String(SnapshotNameTagKey), + Value: aws.String("snap-test-name"), + }, + { + Key: aws.String("extra-tag-key"), + Value: aws.String("extra-tag-value"), + }, + }, + }, + }, + Description: aws.String("Created by AWS EBS CSI driver for volume snap-test-volume"), + }, expSnapshot: &Snapshot{ SourceVolumeID: "snap-test-volume", }, @@ -593,7 +617,7 @@ func TestCreateSnapshot(t *testing.T) { } ctx := context.Background() - mockEC2.EXPECT().CreateSnapshotWithContext(gomock.Eq(ctx), gomock.Any()).Return(ec2snapshot, tc.expErr) + mockEC2.EXPECT().CreateSnapshotWithContext(gomock.Eq(ctx), eqCreateSnapshotInput(tc.expInput)).Return(ec2snapshot, tc.expErr) mockEC2.EXPECT().DescribeSnapshotsWithContext(gomock.Eq(ctx), gomock.Any()).Return(&ec2.DescribeSnapshotsOutput{Snapshots: []*ec2.Snapshot{ec2snapshot}}, nil).AnyTimes() snapshot, err := c.CreateSnapshot(ctx, tc.expSnapshot.SourceVolumeID, tc.snapshotOptions) @@ -845,6 +869,7 @@ func TestGetSnapshotByName(t *testing.T) { snapshotOptions: &SnapshotOptions{ Tags: map[string]string{ SnapshotNameTagKey: "snap-test-name", + "extra-tag-key": "extra-tag-value", }, }, expSnapshot: &Snapshot{ @@ -899,6 +924,7 @@ func TestGetSnapshotByID(t *testing.T) { snapshotOptions: &SnapshotOptions{ Tags: map[string]string{ SnapshotNameTagKey: "snap-test-name", + "extra-tag-key": "extra-tag-value", }, }, expSnapshot: &Snapshot{ @@ -1166,3 +1192,34 @@ func newDescribeInstancesOutput(nodeID string) *ec2.DescribeInstancesOutput { }}, } } + +type eqCreateSnapshotInputMatcher struct { + expected *ec2.CreateSnapshotInput +} + +func eqCreateSnapshotInput(expected *ec2.CreateSnapshotInput) gomock.Matcher { + return &eqCreateSnapshotInputMatcher{expected} +} + +func (m *eqCreateSnapshotInputMatcher) Matches(x interface{}) bool { + input, ok := x.(*ec2.CreateSnapshotInput) + if !ok { + return false + } + + if input != nil { + for _, ts := range input.TagSpecifications { + // Because these tags are generated from a map + // which has a random order. + sort.SliceStable(ts.Tags, func(i, j int) bool { + return *ts.Tags[i].Key < *ts.Tags[j].Key + }) + } + } + + return reflect.DeepEqual(m.expected, input) +} + +func (m *eqCreateSnapshotInputMatcher) String() string { + return m.expected.String() +} diff --git a/pkg/driver/controller.go b/pkg/driver/controller.go index 814e1a59f..be4ed798d 100644 --- a/pkg/driver/controller.go +++ b/pkg/driver/controller.go @@ -199,7 +199,7 @@ func (d *controllerService) CreateVolume(ctx context.Context, req *csi.CreateVol volumeTags[resourceLifecycleTag] = ResourceLifecycleOwned volumeTags[NameTag] = d.driverOptions.kubernetesClusterID + "-dynamic-" + volName } - for k, v := range d.driverOptions.extraVolumeTags { + for k, v := range d.driverOptions.extraTags { volumeTags[k] = v } @@ -441,9 +441,22 @@ func (d *controllerService) CreateSnapshot(ctx context.Context, req *csi.CreateS klog.V(4).Infof("Snapshot %s of volume %s already exists; nothing to do", snapshotName, volumeID) return newCreateSnapshotResponse(snapshot) } + + snapshotTags := map[string]string{ + cloud.SnapshotNameTagKey: snapshotName, + } + if d.driverOptions.kubernetesClusterID != "" { + resourceLifecycleTag := ResourceLifecycleTagPrefix + d.driverOptions.kubernetesClusterID + snapshotTags[resourceLifecycleTag] = ResourceLifecycleOwned + snapshotTags[NameTag] = d.driverOptions.kubernetesClusterID + "-dynamic-" + snapshotName + } + for k, v := range d.driverOptions.extraTags { + snapshotTags[k] = v + } opts := &cloud.SnapshotOptions{ - Tags: map[string]string{cloud.SnapshotNameTagKey: snapshotName}, + Tags: snapshotTags, } + snapshot, err = d.cloud.CreateSnapshot(ctx, volumeID, opts) if err != nil { diff --git a/pkg/driver/controller_test.go b/pkg/driver/controller_test.go index 2c5592e08..5822e2352 100644 --- a/pkg/driver/controller_test.go +++ b/pkg/driver/controller_test.go @@ -1185,7 +1185,7 @@ func TestCreateVolume(t *testing.T) { awsDriver := controllerService{ cloud: mockCloud, driverOptions: &DriverOptions{ - extraVolumeTags: map[string]string{ + extraTags: map[string]string{ extraVolumeTagKey: extraVolumeTagValue, }, }, @@ -1723,6 +1723,118 @@ func TestCreateSnapshot(t *testing.T) { } }, }, + { + name: "success with cluster-id", + testFunc: func(t *testing.T) { + const ( + snapshotName = "test-snapshot" + clusterID = "test-cluster-id" + expectedOwnerTag = "kubernetes.io/cluster/test-cluster-id" + expectedOwnerTagValue = "owned" + expectedNameTag = "Name" + expectedNameTagValue = "test-cluster-id-dynamic-test-snapshot" + ) + req := &csi.CreateSnapshotRequest{ + Name: snapshotName, + Parameters: nil, + SourceVolumeId: "vol-test", + } + expSnapshot := &csi.Snapshot{ + ReadyToUse: true, + } + + ctx := context.Background() + mockSnapshot := &cloud.Snapshot{ + SnapshotID: fmt.Sprintf("snapshot-%d", rand.New(rand.NewSource(time.Now().UnixNano())).Uint64()), + SourceVolumeID: req.SourceVolumeId, + Size: 1, + CreationTime: time.Now(), + } + snapshotOptions := &cloud.SnapshotOptions{ + Tags: map[string]string{ + cloud.SnapshotNameTagKey: snapshotName, + expectedOwnerTag: expectedOwnerTagValue, + expectedNameTag: expectedNameTagValue, + }, + } + mockCtl := gomock.NewController(t) + defer mockCtl.Finish() + + mockCloud := mocks.NewMockCloud(mockCtl) + mockCloud.EXPECT().CreateSnapshot(gomock.Eq(ctx), gomock.Eq(req.SourceVolumeId), gomock.Eq(snapshotOptions)).Return(mockSnapshot, nil) + mockCloud.EXPECT().GetSnapshotByName(gomock.Eq(ctx), gomock.Eq(req.GetName())).Return(nil, cloud.ErrNotFound) + + awsDriver := controllerService{ + cloud: mockCloud, + driverOptions: &DriverOptions{ + kubernetesClusterID: clusterID, + }, + } + resp, err := awsDriver.CreateSnapshot(context.Background(), req) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if snap := resp.GetSnapshot(); snap == nil { + t.Fatalf("Expected snapshot %v, got nil", expSnapshot) + } + }, + }, + { + name: "success with extra tags", + testFunc: func(t *testing.T) { + const ( + snapshotName = "test-snapshot" + extraVolumeTagKey = "extra-tag-key" + extraVolumeTagValue = "extra-tag-value" + ) + req := &csi.CreateSnapshotRequest{ + Name: snapshotName, + Parameters: nil, + SourceVolumeId: "vol-test", + } + expSnapshot := &csi.Snapshot{ + ReadyToUse: true, + } + + ctx := context.Background() + mockSnapshot := &cloud.Snapshot{ + SnapshotID: fmt.Sprintf("snapshot-%d", rand.New(rand.NewSource(time.Now().UnixNano())).Uint64()), + SourceVolumeID: req.SourceVolumeId, + Size: 1, + CreationTime: time.Now(), + } + snapshotOptions := &cloud.SnapshotOptions{ + Tags: map[string]string{ + cloud.SnapshotNameTagKey: snapshotName, + extraVolumeTagKey: extraVolumeTagValue, + }, + } + mockCtl := gomock.NewController(t) + defer mockCtl.Finish() + + mockCloud := mocks.NewMockCloud(mockCtl) + mockCloud.EXPECT().CreateSnapshot(gomock.Eq(ctx), gomock.Eq(req.SourceVolumeId), gomock.Eq(snapshotOptions)).Return(mockSnapshot, nil) + mockCloud.EXPECT().GetSnapshotByName(gomock.Eq(ctx), gomock.Eq(req.GetName())).Return(nil, cloud.ErrNotFound) + + awsDriver := controllerService{ + cloud: mockCloud, + driverOptions: &DriverOptions{ + extraTags: map[string]string{ + extraVolumeTagKey: extraVolumeTagValue, + }, + }, + } + resp, err := awsDriver.CreateSnapshot(context.Background(), req) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if snap := resp.GetSnapshot(); snap == nil { + t.Fatalf("Expected snapshot %v, got nil", expSnapshot) + } + }, + }, { name: "fail no name", testFunc: func(t *testing.T) { diff --git a/pkg/driver/driver.go b/pkg/driver/driver.go index 186bdf9e5..e631e0123 100644 --- a/pkg/driver/driver.go +++ b/pkg/driver/driver.go @@ -58,7 +58,7 @@ type Driver struct { type DriverOptions struct { endpoint string - extraVolumeTags map[string]string + extraTags map[string]string mode Mode volumeAttachLimit int64 kubernetesClusterID string @@ -150,9 +150,18 @@ func WithEndpoint(endpoint string) func(*DriverOptions) { } } +func WithExtraTags(extraTags map[string]string) func(*DriverOptions) { + return func(o *DriverOptions) { + o.extraTags = extraTags + } +} + func WithExtraVolumeTags(extraVolumeTags map[string]string) func(*DriverOptions) { return func(o *DriverOptions) { - o.extraVolumeTags = extraVolumeTags + if o.extraTags == nil && extraVolumeTags != nil { + klog.Warning("DEPRECATION WARNING: --extra-volume-tags is deprecated, please use --extra-tags instead") + o.extraTags = extraVolumeTags + } } } diff --git a/pkg/driver/driver_test.go b/pkg/driver/driver_test.go index c26231ad3..a9bc3f75c 100644 --- a/pkg/driver/driver_test.go +++ b/pkg/driver/driver_test.go @@ -30,12 +30,32 @@ func TestWithEndpoint(t *testing.T) { } } +func TestWithExtraTags(t *testing.T) { + value := map[string]string{"foo": "bar"} + options := &DriverOptions{} + WithExtraTags(value)(options) + if !reflect.DeepEqual(options.extraTags, value) { + t.Fatalf("expected extraTags option got set to %+v but is set to %+v", value, options.extraTags) + } +} + func TestWithExtraVolumeTags(t *testing.T) { value := map[string]string{"foo": "bar"} options := &DriverOptions{} WithExtraVolumeTags(value)(options) - if !reflect.DeepEqual(options.extraVolumeTags, value) { - t.Fatalf("expected extraVolumeTags option got set to %+v but is set to %+v", value, options.extraVolumeTags) + if !reflect.DeepEqual(options.extraTags, value) { + t.Fatalf("expected extraTags option got set to %+v but is set to %+v", value, options.extraTags) + } +} + +func TestWithExtraVolumeTagsNoOverwrite(t *testing.T) { + extraTagsValue := map[string]string{"foo": "bar"} + options := &DriverOptions{} + WithExtraTags(extraTagsValue)(options) + extraVolumeTagsValue := map[string]string{"baz": "qux"} + WithExtraVolumeTags(extraVolumeTagsValue)(options) + if !reflect.DeepEqual(options.extraTags, extraTagsValue) { + t.Fatalf("expected extraTags option got set to %+v but is set to %+v", extraTagsValue, options.extraTags) } } diff --git a/pkg/driver/validation.go b/pkg/driver/validation.go index 1a69e1734..6c25fa877 100644 --- a/pkg/driver/validation.go +++ b/pkg/driver/validation.go @@ -24,8 +24,8 @@ import ( ) func ValidateDriverOptions(options *DriverOptions) error { - if err := validateExtraVolumeTags(options.extraVolumeTags); err != nil { - return fmt.Errorf("Invalid extra volume tags: %v", err) + if err := validateExtraTags(options.extraTags); err != nil { + return fmt.Errorf("Invalid extra tags: %v", err) } if err := validateMode(options.mode); err != nil { @@ -35,26 +35,29 @@ func ValidateDriverOptions(options *DriverOptions) error { return nil } -func validateExtraVolumeTags(tags map[string]string) error { +func validateExtraTags(tags map[string]string) error { if len(tags) > cloud.MaxNumTagsPerResource { - return fmt.Errorf("Too many volume tags (actual: %d, limit: %d)", len(tags), cloud.MaxNumTagsPerResource) + return fmt.Errorf("Too many tags (actual: %d, limit: %d)", len(tags), cloud.MaxNumTagsPerResource) } for k, v := range tags { if len(k) > cloud.MaxTagKeyLength { - return fmt.Errorf("Volume tag key too long (actual: %d, limit: %d)", len(k), cloud.MaxTagKeyLength) + return fmt.Errorf("Tag key too long (actual: %d, limit: %d)", len(k), cloud.MaxTagKeyLength) } if len(v) > cloud.MaxTagValueLength { - return fmt.Errorf("Volume tag value too long (actual: %d, limit: %d)", len(v), cloud.MaxTagValueLength) + return fmt.Errorf("Tag value too long (actual: %d, limit: %d)", len(v), cloud.MaxTagValueLength) } if k == cloud.VolumeNameTagKey { - return fmt.Errorf("Volume tag key '%s' is reserved", cloud.VolumeNameTagKey) + return fmt.Errorf("Tag key '%s' is reserved", cloud.VolumeNameTagKey) + } + if k == cloud.SnapshotNameTagKey { + return fmt.Errorf("Tag key '%s' is reserved", cloud.VolumeNameTagKey) } if strings.HasPrefix(k, cloud.KubernetesTagKeyPrefix) { - return fmt.Errorf("Volume tag key prefix '%s' is reserved", cloud.KubernetesTagKeyPrefix) + return fmt.Errorf("Tag key prefix '%s' is reserved", cloud.KubernetesTagKeyPrefix) } if strings.HasPrefix(k, cloud.AWSTagKeyPrefix) { - return fmt.Errorf("Volume tag key prefix '%s' is reserved", cloud.AWSTagKeyPrefix) + return fmt.Errorf("Tag key prefix '%s' is reserved", cloud.AWSTagKeyPrefix) } } diff --git a/pkg/driver/validation_test.go b/pkg/driver/validation_test.go index 64427a00f..283ff80a9 100644 --- a/pkg/driver/validation_test.go +++ b/pkg/driver/validation_test.go @@ -62,46 +62,46 @@ func TestValidateExtraVolumeTags(t *testing.T) { tags: map[string]string{ randomString(cloud.MaxTagKeyLength + 1): "extra-tag-value", }, - expErr: fmt.Errorf("Volume tag key too long (actual: %d, limit: %d)", cloud.MaxTagKeyLength+1, cloud.MaxTagKeyLength), + expErr: fmt.Errorf("Tag key too long (actual: %d, limit: %d)", cloud.MaxTagKeyLength+1, cloud.MaxTagKeyLength), }, { name: "invalid tag: value too long", tags: map[string]string{ "extra-tag-key": randomString(cloud.MaxTagValueLength + 1), }, - expErr: fmt.Errorf("Volume tag value too long (actual: %d, limit: %d)", cloud.MaxTagValueLength+1, cloud.MaxTagValueLength), + expErr: fmt.Errorf("Tag value too long (actual: %d, limit: %d)", cloud.MaxTagValueLength+1, cloud.MaxTagValueLength), }, { name: "invalid tag: reserved CSI key", tags: map[string]string{ cloud.VolumeNameTagKey: "extra-tag-value", }, - expErr: fmt.Errorf("Volume tag key '%s' is reserved", cloud.VolumeNameTagKey), + expErr: fmt.Errorf("Tag key '%s' is reserved", cloud.VolumeNameTagKey), }, { name: "invalid tag: reserved Kubernetes key prefix", tags: map[string]string{ cloud.KubernetesTagKeyPrefix + "/cluster": "extra-tag-value", }, - expErr: fmt.Errorf("Volume tag key prefix '%s' is reserved", cloud.KubernetesTagKeyPrefix), + expErr: fmt.Errorf("Tag key prefix '%s' is reserved", cloud.KubernetesTagKeyPrefix), }, { name: "invalid tag: reserved AWS key prefix", tags: map[string]string{ cloud.AWSTagKeyPrefix + "foo": "extra-tag-value", }, - expErr: fmt.Errorf("Volume tag key prefix '%s' is reserved", cloud.AWSTagKeyPrefix), + expErr: fmt.Errorf("Tag key prefix '%s' is reserved", cloud.AWSTagKeyPrefix), }, { - name: "invalid tag: too many volume tags", + name: "invalid tag: too many tags", tags: randomStringMap(cloud.MaxNumTagsPerResource + 1), - expErr: fmt.Errorf("Too many volume tags (actual: %d, limit: %d)", cloud.MaxNumTagsPerResource+1, cloud.MaxNumTagsPerResource), + expErr: fmt.Errorf("Too many tags (actual: %d, limit: %d)", cloud.MaxNumTagsPerResource+1, cloud.MaxNumTagsPerResource), }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - err := validateExtraVolumeTags(tc.tags) + err := validateExtraTags(tc.tags) if !reflect.DeepEqual(err, tc.expErr) { t.Fatalf("error not equal\ngot:\n%s\nexpected:\n%s", err, tc.expErr) } @@ -170,15 +170,15 @@ func TestValidateDriverOptions(t *testing.T) { extraVolumeTags: map[string]string{ randomString(cloud.MaxTagKeyLength + 1): "extra-tag-value", }, - expErr: fmt.Errorf("Invalid extra volume tags: Volume tag key too long (actual: %d, limit: %d)", cloud.MaxTagKeyLength+1, cloud.MaxTagKeyLength), + expErr: fmt.Errorf("Invalid extra tags: Tag key too long (actual: %d, limit: %d)", cloud.MaxTagKeyLength+1, cloud.MaxTagKeyLength), }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { err := ValidateDriverOptions(&DriverOptions{ - extraVolumeTags: tc.extraVolumeTags, - mode: tc.mode, + extraTags: tc.extraVolumeTags, + mode: tc.mode, }) if !reflect.DeepEqual(err, tc.expErr) { t.Fatalf("error not equal\ngot:\n%s\nexpected:\n%s", err, tc.expErr)