Repository: kubernetes-sigs/gcp-compute-persistent-disk-csi-driver
Pull request #1017 (2022-06-23 20:39:46)

add support for setting snapshot labels
<!--  Thanks for sending a pull request!  Here are some tips for you:

1. If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
2. Follow the instructions for writing a release note: https://git.k8s.io/community/contributors/guide/release-notes.md
3. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
-->

**What type of PR is this?**

/kind feature


**What this PR does / why we need it**:

This PR adds support for adding labels to snapshots, similar how it can be done with disks via storage class parameters.

_Why is it needed?_
We use labels to calculate costs inside our GCP project, this PR allows us to set custom labels on snapshots to properly count them for cost calculations.

_How to test?_
Add `parameters` to your `VolumeSnapshotClass` like so:
```
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: csi-gce-pd-snapshot-class
parameters:
  labels: cluster=preview,region=us,custom-label=awesome
driver: pd.csi.storage.gke.io
deletionPolicy: Delete
```
When snapshot is created, observe that labels were added to it in GCP console:
![image](https://user-images.githubusercontent.com/18602811/175395108-c79b85d4-fecc-46ff-bc3d-7b70b0923d18.png)



**Which issue(s) this PR fixes**:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #

**Special notes for your reviewer**:

**Does this PR introduce a user-facing change?**:
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note
Add support for setting snapshot labels
```



Patch:
diff --git a/pkg/common/parameters.go b/pkg/common/parameters.go
index d0f5366f..b2bde107 100644
--- a/pkg/common/parameters.go
+++ b/pkg/common/parameters.go
@@ -83,6 +83,7 @@ type SnapshotParameters struct {
 	SnapshotType     string
 	ImageFamily      string
 	Tags             map[string]string
+	Labels           map[string]string
 }
 
 // ExtractAndDefaultParameters will take the relevant parameters from a map and
@@ -149,6 +150,7 @@ func ExtractAndDefaultSnapshotParameters(parameters map[string]string, driverNam
 		StorageLocations: []string{},
 		SnapshotType:     DiskSnapshotType,
 		Tags:             make(map[string]string), // Default
+		Labels:           make(map[string]string), // Default
 	}
 	for k, v := range parameters {
 		switch strings.ToLower(k) {
@@ -172,6 +174,15 @@ func ExtractAndDefaultSnapshotParameters(parameters map[string]string, driverNam
 			p.Tags[tagKeyCreatedForSnapshotNamespace] = v
 		case ParameterKeyVolumeSnapshotContentName:
 			p.Tags[tagKeyCreatedForSnapshotContentName] = v
+		case ParameterKeyLabels:
+			paramLabels, err := ConvertLabelsStringToMap(v)
+			if err != nil {
+				return p, fmt.Errorf("parameters contain invalid labels parameter: %w", err)
+			}
+			// Override any existing labels with those from this parameter.
+			for labelKey, labelValue := range paramLabels {
+				p.Labels[labelKey] = labelValue
+			}
 		default:
 			return p, fmt.Errorf("parameters contains invalid option %q", k)
 		}
diff --git a/pkg/gce-cloud-provider/compute/fake-gce.go b/pkg/gce-cloud-provider/compute/fake-gce.go
index 309b0b39..309bf59d 100644
--- a/pkg/gce-cloud-provider/compute/fake-gce.go
+++ b/pkg/gce-cloud-provider/compute/fake-gce.go
@@ -344,6 +344,7 @@ func (cloud *FakeCloudProvider) CreateSnapshot(ctx context.Context, project stri
 		Status:            "UPLOADING",
 		SelfLink:          cloud.getGlobalSnapshotURI(project, snapshotName),
 		StorageLocations:  snapshotParams.StorageLocations,
+		Labels:            snapshotParams.Labels,
 	}
 	switch volKey.Type() {
 	case meta.Zonal:
diff --git a/pkg/gce-cloud-provider/compute/gce-compute.go b/pkg/gce-cloud-provider/compute/gce-compute.go
index 35c120e3..f3d8d441 100644
--- a/pkg/gce-cloud-provider/compute/gce-compute.go
+++ b/pkg/gce-cloud-provider/compute/gce-compute.go
@@ -1059,6 +1059,7 @@ func (cloud *CloudProvider) createZonalDiskSnapshot(ctx context.Context, project
 		Name:             snapshotName,
 		StorageLocations: snapshotParams.StorageLocations,
 		Description:      description,
+		Labels:           snapshotParams.Labels,
 	}
 
 	_, err := cloud.service.Disks.CreateSnapshot(project, volKey.Zone, volKey.Name, snapshotToCreate).Context(ctx).Do()
@@ -1075,6 +1076,7 @@ func (cloud *CloudProvider) createRegionalDiskSnapshot(ctx context.Context, proj
 		Name:             snapshotName,
 		StorageLocations: snapshotParams.StorageLocations,
 		Description:      description,
+		Labels:           snapshotParams.Labels,
 	}
 
 	_, err := cloud.service.RegionDisks.CreateSnapshot(project, volKey.Region, volKey.Name, snapshotToCreate).Context(ctx).Do()


Test patch:
diff --git a/pkg/common/parameters_test.go b/pkg/common/parameters_test.go
index 9a9b48d3..c9832731 100644
--- a/pkg/common/parameters_test.go
+++ b/pkg/common/parameters_test.go
@@ -183,6 +183,7 @@ func TestSnapshotParameters(t *testing.T) {
 				ParameterKeyVolumeSnapshotName:        "snapshot-name",
 				ParameterKeyVolumeSnapshotContentName: "snapshot-content-name",
 				ParameterKeyVolumeSnapshotNamespace:   "snapshot-namespace",
+				ParameterKeyLabels:                    "label-1=value-a,key1=value1",
 			},
 			expectedSnapshotParames: SnapshotParameters{
 				StorageLocations: []string{"asia"},
@@ -194,6 +195,7 @@ func TestSnapshotParameters(t *testing.T) {
 					tagKeyCreatedForSnapshotNamespace:   "snapshot-namespace",
 					tagKeyCreatedBy:                     "test-driver",
 				},
+				Labels: map[string]string{"label-1": "value-a", "key1": "value1"},
 			},
 			expectError: false,
 		},
@@ -204,6 +206,7 @@ func TestSnapshotParameters(t *testing.T) {
 				StorageLocations: []string{},
 				SnapshotType:     DiskSnapshotType,
 				Tags:             make(map[string]string),
+				Labels:           map[string]string{},
 			},
 			expectError: false,
 		},