Skip to content

Support to add ResoureManagerTags to GCP Compute Disk, Image, Snapshot #1377

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ See Github [Issues](https://github.com/kubernetes-sigs/gcp-compute-persistent-di
| labels | `key1=value1,key2=value2` | | Labels allow you to assign custom [GCE Disk labels](https://cloud.google.com/compute/docs/labeling-resources). |
| provisioned-iops-on-create | string (int64 format). Values typically between 10,000 and 120,000 | | Indicates how many IOPS to provision for the disk. See the [Extreme persistent disk documentation](https://cloud.google.com/compute/docs/disks/extreme-persistent-disk) for details, including valid ranges for IOPS. |
| provisioned-throughput-on-create | string (int64 format). Values typically between 1 and 7,124 mb per second | | Indicates how much throughput to provision for the disk. See the [hyperdisk documentation]([TBD](https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/hyperdisk#create)) for details, including valid ranges for throughput. |
| resource-tags | `<parent_id1>/<tag_key1>/<tag_value1>,<parent_id2>/<tag_key2>/<tag_value2>` | | Resource tags allow you to attach user-defined tags to each Compute Disk, Image and Snapshot. See [Tags overview](https://cloud.google.com/resource-manager/docs/tags/tags-overview), [Creating and managing tags](https://cloud.google.com/resource-manager/docs/tags/tags-creating-and-managing). |

### Topology

Expand Down
12 changes: 11 additions & 1 deletion cmd/gce-pd-csi-driver/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ var (

useInstanceAPIOnWaitForAttachDiskTypesFlag = flag.String("use-instance-api-to-poll-attachment-disk-types", "", "Comma separated list of disk types that should use instances.get API when polling for disk attach during ControllerPublish")

extraTagsStr = flag.String("extra-tags", "", "Extra tags to attach to each Compute Disk, Image, Snapshot created. It is a comma separated list of parent id, key and value like '<parent_id1>/<tag_key1>/<tag_value1>,...,<parent_idN>/<tag_keyN>/<tag_valueN>'. parent_id is the Organization or the Project ID or Project name where the tag key and the tag value resources exist. A maximum of 50 tags bindings is allowed for a resource. See https://cloud.google.com/resource-manager/docs/tags/tags-overview, https://cloud.google.com/resource-manager/docs/tags/tags-creating-and-managing for details")

version string
)

Expand Down Expand Up @@ -153,6 +155,14 @@ func handle() {
klog.Fatalf("Bad extra volume labels: %v", err.Error())
}

if len(*extraTagsStr) > 0 && !*runControllerService {
klog.Fatalf("Extra tags provided but not running controller")
}
extraTags, err := common.ConvertTagsStringToMap(*extraTagsStr)
if err != nil {
klog.Fatalf("Bad extra tags: %v", err.Error())
}

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

Expand Down Expand Up @@ -211,7 +221,7 @@ func handle() {
}
}

err = gceDriver.SetupGCEDriver(driverName, version, extraVolumeLabels, identityServer, controllerServer, nodeServer)
err = gceDriver.SetupGCEDriver(driverName, version, extraVolumeLabels, extraTags, identityServer, controllerServer, nodeServer)
if err != nil {
klog.Fatalf("Failed to initialize GCE CSI Driver: %v", err.Error())
}
Expand Down
8 changes: 8 additions & 0 deletions examples/kubernetes/demo-sc-with-resource-tags.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-gce-pd-with-resource-tags
provisioner: pd.csi.storage.gke.io
parameters:
resource-tags: parent1/key1/value1,parent2/key2/value2
volumeBindingMode: WaitForFirstConsumer
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: snapshot.storage.k8s.io/v1beta1
kind: VolumeSnapshotClass
metadata:
name: csi-gce-pd-snapshot-class-with-resource-tags
parameters:
resource-tags: parent1/key1/value1,parent2/key2/value2
driver: pd.csi.storage.gke.io
deletionPolicy: Delete
10 changes: 7 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
module sigs.k8s.io/gcp-compute-persistent-disk-csi-driver

go 1.22
go 1.22.0

toolchain go1.22.2

require (
cloud.google.com/go/compute/metadata v0.3.0
cloud.google.com/go/kms v1.15.8
cloud.google.com/go/resourcemanager v1.9.6
github.com/GoogleCloudPlatform/k8s-cloud-provider v1.24.0
github.com/container-storage-interface/spec v1.6.0
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.6.0
github.com/googleapis/gax-go/v2 v2.12.3
github.com/kubernetes-csi/csi-proxy/client v1.1.3
github.com/kubernetes-csi/csi-test/v4 v4.4.0
github.com/onsi/ginkgo/v2 v2.17.1
Expand All @@ -21,6 +24,7 @@ require (
go.opentelemetry.io/otel/sdk v1.22.0
golang.org/x/oauth2 v0.19.0
golang.org/x/sys v0.19.0
golang.org/x/time v0.5.0
google.golang.org/api v0.172.0
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de
google.golang.org/grpc v1.63.2
Expand All @@ -38,7 +42,9 @@ require (
)

require (
cloud.google.com/go v0.112.1 // indirect
cloud.google.com/go/iam v1.1.7 // indirect
cloud.google.com/go/longrunning v0.5.5 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
Expand All @@ -65,7 +71,6 @@ require (
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.0 // indirect
Expand Down Expand Up @@ -99,7 +104,6 @@ require (
golang.org/x/sync v0.7.0 // indirect
golang.org/x/term v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.20.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeN
cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE=
cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc=
cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo=
cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg=
cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s=
cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE=
cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM=
cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA=
Expand Down Expand Up @@ -471,6 +473,8 @@ cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7L
cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots=
cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo=
cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI=
cloud.google.com/go/resourcemanager v1.9.6 h1:VPfJFbWxrTYQzEXCDbJNpcvSB8eZhTSM0YHH146fIB8=
cloud.google.com/go/resourcemanager v1.9.6/go.mod h1:d+XUOGbxg6Aka3lmC4fDiserslux3d15uX08C6a0MBg=
cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU=
cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg=
cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA=
Expand Down
40 changes: 38 additions & 2 deletions pkg/common/parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (
ParameterAvailabilityClass = "availability-class"
ParameterKeyEnableConfidentialCompute = "enable-confidential-storage"
ParameterKeyStoragePools = "storage-pools"
ParameterKeyResourceTags = "resource-tags"

// Parameters for VolumeSnapshotClass
ParameterKeyStorageLocations = "storage-locations"
Expand Down Expand Up @@ -98,6 +99,9 @@ type DiskParameters struct {
// Values: {[]string}
// Default: ""
StoragePools []StoragePool
// Values: {map[string]string}
// Default: ""
ResourceTags map[string]string
}

// SnapshotParameters contains normalized and defaulted parameters for snapshots
Expand All @@ -107,6 +111,7 @@ type SnapshotParameters struct {
ImageFamily string
Tags map[string]string
Labels map[string]string
ResourceTags map[string]string
}

type StoragePool struct {
Expand All @@ -120,19 +125,24 @@ type StoragePool struct {
// put them into a well defined struct making sure to default unspecified fields.
// extraVolumeLabels are added as labels; if there are also labels specified in
// parameters, any matching extraVolumeLabels will be overridden.
func ExtractAndDefaultParameters(parameters map[string]string, driverName string, extraVolumeLabels map[string]string, enableStoragePools bool) (DiskParameters, error) {
func ExtractAndDefaultParameters(parameters map[string]string, driverName string, extraVolumeLabels map[string]string, enableStoragePools bool, extraTags map[string]string) (DiskParameters, error) {
p := DiskParameters{
DiskType: "pd-standard", // Default
ReplicationType: replicationTypeNone, // Default
DiskEncryptionKMSKey: "", // Default
Tags: make(map[string]string), // Default
Labels: make(map[string]string), // Default
ResourceTags: make(map[string]string), // Default
}

for k, v := range extraVolumeLabels {
p.Labels[k] = v
}

for k, v := range extraTags {
p.ResourceTags[k] = v
}

for k, v := range parameters {
if k == "csiProvisionerSecretName" || k == "csiProvisionerSecretNamespace" {
// These are hardcoded secrets keys required to function but not needed by GCE PD
Expand Down Expand Up @@ -208,6 +218,10 @@ func ExtractAndDefaultParameters(parameters map[string]string, driverName string
return p, fmt.Errorf("parameters contain invalid value for %s parameter: %w", ParameterKeyStoragePools, err)
}
p.StoragePools = storagePools
case ParameterKeyResourceTags:
if err := extractResourceTagsParameter(v, p.ResourceTags); err != nil {
return p, err
}
default:
return p, fmt.Errorf("parameters contains invalid option %q", k)
}
Expand All @@ -218,13 +232,19 @@ func ExtractAndDefaultParameters(parameters map[string]string, driverName string
return p, nil
}

func ExtractAndDefaultSnapshotParameters(parameters map[string]string, driverName string) (SnapshotParameters, error) {
func ExtractAndDefaultSnapshotParameters(parameters map[string]string, driverName string, extraTags map[string]string) (SnapshotParameters, error) {
p := SnapshotParameters{
StorageLocations: []string{},
SnapshotType: DiskSnapshotType,
Tags: make(map[string]string), // Default
Labels: make(map[string]string), // Default
ResourceTags: make(map[string]string), // Default
}

for k, v := range extraTags {
p.ResourceTags[k] = v
}

for k, v := range parameters {
switch strings.ToLower(k) {
case ParameterKeyStorageLocations:
Expand Down Expand Up @@ -256,6 +276,10 @@ func ExtractAndDefaultSnapshotParameters(parameters map[string]string, driverNam
for labelKey, labelValue := range paramLabels {
p.Labels[labelKey] = labelValue
}
case ParameterKeyResourceTags:
if err := extractResourceTagsParameter(v, p.ResourceTags); err != nil {
return p, err
}
default:
return p, fmt.Errorf("parameters contains invalid option %q", k)
}
Expand All @@ -265,3 +289,15 @@ func ExtractAndDefaultSnapshotParameters(parameters map[string]string, driverNam
}
return p, nil
}

func extractResourceTagsParameter(tagsString string, resourceTags map[string]string) error {
paramResourceTags, err := ConvertTagsStringToMap(tagsString)
if err != nil {
return fmt.Errorf("parameters contain invalid %s parameter: %w", ParameterKeyResourceTags, err)
}
// Override any existing resource tags with those from this parameter.
for tagParentIDKey, tagValue := range paramResourceTags {
resourceTags[tagParentIDKey] = tagValue
}
return nil
}
Loading