diff --git a/README.md b/README.md index 9f072662..15f5a52a 100644 --- a/README.md +++ b/README.md @@ -246,6 +246,25 @@ spec: storage: 10Gi storageClassName: linode-block-storage-retain-luks ``` +### Adding Tags to created volumes +This feature gives users the ability to add tags to volumes created by a specific storageClass, to allow for better tracking of volumes. +Tags are added as a comma seperated string value for a parameter `linodebs.csi.linode.com/volumeTags` + +#### Example StorageClass +``` +allowVolumeExpansion: true +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + annotations: + storageclass.kubernetes.io/is-default-class: "true" + name: linode-block-storage + namespace: kube-system +provisioner: linodebs.csi.linode.com +parameters: + linodebs.csi.linode.com/volumeTags: "test, foo, yolo" +``` + ## Disclaimers diff --git a/helm-chart/csi-driver/templates/linode-block-storage-retain.yaml b/helm-chart/csi-driver/templates/linode-block-storage-retain.yaml index 861f83bc..966e52eb 100644 --- a/helm-chart/csi-driver/templates/linode-block-storage-retain.yaml +++ b/helm-chart/csi-driver/templates/linode-block-storage-retain.yaml @@ -7,6 +7,10 @@ metadata: annotations: storageclass.kubernetes.io/is-default-class: "true" {{- end }} +{{- if .Values.volumeTags }} +parameters: + linodebs.csi.linode.com/volumeTags: {{ join "," .Values.volumeTags }} +{{- end}} allowVolumeExpansion: true provisioner: linodebs.csi.linode.com reclaimPolicy: Retain diff --git a/helm-chart/csi-driver/templates/linode-block-storage.yaml b/helm-chart/csi-driver/templates/linode-block-storage.yaml index cd26adfa..0f50315d 100644 --- a/helm-chart/csi-driver/templates/linode-block-storage.yaml +++ b/helm-chart/csi-driver/templates/linode-block-storage.yaml @@ -7,5 +7,9 @@ metadata: annotations: storageclass.kubernetes.io/is-default-class: "true" {{- end }} +{{- if .Values.volumeTags }} +parameters: + linodebs.csi.linode.com/volumeTags: {{ join "," .Values.volumeTags }} +{{- end}} allowVolumeExpansion: true provisioner: linodebs.csi.linode.com diff --git a/helm-chart/csi-driver/values.yaml b/helm-chart/csi-driver/values.yaml index f70cd74f..ad63df36 100644 --- a/helm-chart/csi-driver/values.yaml +++ b/helm-chart/csi-driver/values.yaml @@ -18,7 +18,13 @@ namespace: kube-system # "linode-block-storage" or left as an empty string defaultStorageClass: linode-block-storage-retain -# Images - Default +# set these value to a comma seperated string if you'd like to add tags to the created volumes +#volumeTags: +# - example +# - test + +# Images - Default + csiProvisioner: image: registry.k8s.io/sig-storage/csi-provisioner tag: v3.0.0 @@ -45,4 +51,4 @@ kubectl: csiNodeDriverRegistrar: image: registry.k8s.io/sig-storage/csi-node-driver-registrar - tag: v1.3.0 \ No newline at end of file + tag: v1.3.0 diff --git a/pkg/linode-bs/controllerserver.go b/pkg/linode-bs/controllerserver.go index a62be526..c5107fa9 100644 --- a/pkg/linode-bs/controllerserver.go +++ b/pkg/linode-bs/controllerserver.go @@ -18,10 +18,28 @@ import ( "google.golang.org/grpc/status" ) -const gigabyte = 1024 * 1024 * 1024 -const minProviderVolumeBytes = 10 * gigabyte -const waitTimeout = 300 -const devicePathKey = "devicePath" +type VolumeLifecycle string + +const ( + gigabyte = 1024 * 1024 * 1024 + driverName = "linodebs.csi.linode.com" + devicePathKey = "devicePath" + waitTimeout = 300 + minProviderVolumeBytes = 10 * gigabyte + + // VolumeTags is a comma seperated string used to pass information to the linode APIs to tag the + // created volumes + VolumeTags = driverName + "/volumeTags" + + // PublishInfoVolumeName is used to pass the volume name from + // `ControllerPublishVolume` to `NodeStageVolume or `NodePublishVolume` + PublishInfoVolumeName = driverName + "/volume-name" + + VolumeLifecycleNodeStageVolume VolumeLifecycle = "NodeStageVolume" + VolumeLifecycleNodePublishVolume VolumeLifecycle = "NodePublishVolume" + VolumeLifecycleNodeUnstageVolume VolumeLifecycle = "NodeUnstageVolume" + VolumeLifecycleNodeUnpublishVolume VolumeLifecycle = "NodeUnpublishVolume" +) type LinodeControllerServer struct { Driver *LinodeDriver @@ -102,6 +120,8 @@ func (linodeCS *LinodeControllerServer) CreateVolume(ctx context.Context, req *c volumeContext[LuksKeySizeAttribute] = req.Parameters[LuksKeySizeAttribute] } + tags := req.Parameters[VolumeTags] + if len(volumes) != 0 { if len(volumes) > 1 { return nil, status.Error(codes.AlreadyExists, fmt.Sprintf("duplicate volume %q exists", volumeName)) @@ -131,7 +151,7 @@ func (linodeCS *LinodeControllerServer) CreateVolume(ctx context.Context, req *c vol, err = linodeCS.cloneLinodeVolume(ctx, volumeName, volumeSizeGB, sourceVolumeInfo.VolumeID) } else { // Create the volume from scratch - vol, err = linodeCS.createLinodeVolume(ctx, volumeName, volumeSizeGB) + vol, err = linodeCS.createLinodeVolume(ctx, volumeName, volumeSizeGB, tags) } // Error handling for the above function calls @@ -546,11 +566,13 @@ func (linodeCS *LinodeControllerServer) attemptGetContentSourceVolume( // createLinodeVolume creates a Linode volume and returns the result func (linodeCS *LinodeControllerServer) createLinodeVolume( - ctx context.Context, label string, sizeGB int) (*linodego.Volume, error) { + ctx context.Context, label string, sizeGB int, tags string) (*linodego.Volume, error) { + volumeReq := linodego.VolumeCreateOptions{ Region: linodeCS.MetadataService.GetZone(), Label: label, Size: sizeGB, + Tags: strings.Split(tags, ","), } glog.V(4).Infoln("creating volume", map[string]interface{}{"volume_req": volumeReq}) diff --git a/pkg/linode-bs/driver_test.go b/pkg/linode-bs/driver_test.go index 1766ddc7..7c14283d 100644 --- a/pkg/linode-bs/driver_test.go +++ b/pkg/linode-bs/driver_test.go @@ -245,6 +245,7 @@ func (f *fakeAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) { Size: v.Size, FilesystemPath: path, Status: linodego.VolumeActive, + Tags: v.Tags, Created: &now, Updated: &now, } diff --git a/pkg/linode-bs/luks.go b/pkg/linode-bs/luks.go index 31f72256..cc030f07 100644 --- a/pkg/linode-bs/luks.go +++ b/pkg/linode-bs/luks.go @@ -32,8 +32,6 @@ import ( "github.com/golang/glog" ) -type VolumeLifecycle string - type LuksContext struct { EncryptionEnabled bool EncryptionKey string @@ -44,12 +42,6 @@ type LuksContext struct { } const ( - driverName = "linodebs.csi.linode.com" - - // PublishInfoVolumeName is used to pass the volume name from - // `ControllerPublishVolume` to `NodeStageVolume or `NodePublishVolume` - PublishInfoVolumeName = driverName + "/volume-name" - // LuksEncryptedAttribute is used to pass the information if the volume should be // encrypted with luks to `NodeStageVolume` LuksEncryptedAttribute = driverName + "/luks-encrypted" @@ -64,11 +56,6 @@ const ( // LuksKeyAttribute is the key of the luks key used in the map of secrets passed from the CO LuksKeyAttribute = "luksKey" - - VolumeLifecycleNodeStageVolume VolumeLifecycle = "NodeStageVolume" - VolumeLifecycleNodePublishVolume VolumeLifecycle = "NodePublishVolume" - VolumeLifecycleNodeUnstageVolume VolumeLifecycle = "NodeUnstageVolume" - VolumeLifecycleNodeUnpublishVolume VolumeLifecycle = "NodeUnpublishVolume" ) func (ctx *LuksContext) validate() error { @@ -257,7 +244,7 @@ func luksClose(volume string) error { func luksOpen(volume string, keyFile string, ctx LuksContext) error { // check if the luks volume is already open if _, err := os.Stat("/dev/mapper/" + ctx.VolumeName); !os.IsNotExist(err) { - glog.V(4).Info("luks volume is already open %s", volume) + glog.V(4).Infof("luks volume is already open %s", volume) return nil } diff --git a/pkg/linode-bs/nodeserver.go b/pkg/linode-bs/nodeserver.go index 2a315bb0..46694f5b 100644 --- a/pkg/linode-bs/nodeserver.go +++ b/pkg/linode-bs/nodeserver.go @@ -203,7 +203,7 @@ func (ns *LinodeNodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.No return nil, status.Error(codes.Internal, fmt.Sprintf("Unmount failed: %v\nUnmounting arguments: %s\n", err, targetPath)) } - glog.V(4).Infof("NodeUnpublishVolume called with args: %v, targetPath ", req, targetPath) + glog.V(4).Infof("NodeUnpublishVolume called with args: %v, targetPath %s", req, targetPath) if err := closeMountSources(targetPath); err != nil { return nil, err @@ -370,7 +370,7 @@ func closeMountSources(path string) error { return status.Error(codes.Internal, fmt.Sprintf("closeMountSources failed determine if mount is a luks mapping %s: %v", path, err)) } if isLuksMapping { - glog.V(4).Infof("luksClose ", mappingName) + glog.V(4).Infof("luksClose %s", mappingName) if err := luksClose(mappingName); err != nil { return status.Error(codes.Internal, fmt.Sprintf("closeMountSources failed to close luks mount %s: %v", path, err)) }