diff --git a/docs/using-manila-csi-plugin.md b/docs/using-manila-csi-plugin.md index 767132226c..2fe32e86a2 100644 --- a/docs/using-manila-csi-plugin.md +++ b/docs/using-manila-csi-plugin.md @@ -48,6 +48,7 @@ Parameter | Required | Description `type` | _yes_ | Manila [share type](https://wiki.openstack.org/wiki/Manila/Concepts#share_type) `shareNetworkID` | _no_ | Manila [share network ID](https://wiki.openstack.org/wiki/Manila/Concepts#share_network) `availability` | _no_ | Manila availability zone of the provisioned share. If none is provided, the default Manila zone will be used. Note that this parameter is opaque to the CO and does not influence placement of workloads that will consume this share, meaning they may be scheduled onto any node of the cluster. If the specified Manila AZ is not equally accessible from all compute nodes of the cluster, use [Topology-aware dynamic provisioning](#topology-aware-dynamic-provisioning). +`appendShareMetadata` | _no_ | Append user-defined metadata to the provisioned share. If not empty, this field must be a string with a valid JSON object. The object must consist of key-value pairs of type string. Example: `"{..., \"key\": \"value\"}"`. `cephfs-mounter` | _no_ | Relevant for CephFS Manila shares. Specifies which mounting method to use with the CSI CephFS driver. Available options are `kernel` and `fuse`, defaults to `fuse`. See [CSI CephFS docs](https://github.com/ceph/ceph-csi/blob/csi-v1.0/docs/deploy-cephfs.md#configuration) for further information. `nfs-shareClient` | _no_ | Relevant for NFS Manila shares. Specifies what address has access to the NFS share. Defaults to `0.0.0.0/0`, i.e. anyone. diff --git a/pkg/csi/manila/options/shareoptions.go b/pkg/csi/manila/options/shareoptions.go index 806c869d2e..e4d94a5116 100644 --- a/pkg/csi/manila/options/shareoptions.go +++ b/pkg/csi/manila/options/shareoptions.go @@ -21,10 +21,11 @@ import ( ) type ControllerVolumeContext struct { - Protocol string `name:"protocol" matches:"^(?i)CEPHFS|NFS$"` - Type string `name:"type" value:"default:default"` - ShareNetworkID string `name:"shareNetworkID" value:"optional"` - AvailabilityZone string `name:"availability" value:"optional"` + Protocol string `name:"protocol" matches:"^(?i)CEPHFS|NFS$"` + Type string `name:"type" value:"default:default"` + ShareNetworkID string `name:"shareNetworkID" value:"optional"` + AvailabilityZone string `name:"availability" value:"optional"` + AppendShareMetadata string `name:"appendShareMetadata" value:"optional"` // Adapter options diff --git a/pkg/csi/manila/volumesource.go b/pkg/csi/manila/volumesource.go index be1b738a7d..f56ffad686 100644 --- a/pkg/csi/manila/volumesource.go +++ b/pkg/csi/manila/volumesource.go @@ -17,6 +17,8 @@ limitations under the License. package manila import ( + "encoding/json" + "github.com/container-storage-interface/spec/lib/go/csi" "github.com/gophercloud/gophercloud/openstack/sharedfilesystems/v2/shares" "google.golang.org/grpc/codes" @@ -35,6 +37,11 @@ type volumeCreator interface { type blankVolume struct{} func (blankVolume) create(req *csi.CreateVolumeRequest, shareName string, sizeInGiB int, manilaClient manilaclient.Interface, shareOpts *options.ControllerVolumeContext) (*shares.Share, error) { + shareMetadata, err := parseStringMapFromJson(shareOpts.AppendShareMetadata) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "failed to parse appendShareMetadata field: %v", err) + } + klog.V(4).Infof("creating a new share (%s) in AZ %s", shareName, coalesceValue(shareOpts.AvailabilityZone)) createOpts := &shares.CreateOpts{ @@ -45,6 +52,7 @@ func (blankVolume) create(req *csi.CreateVolumeRequest, shareName string, sizeIn Name: shareName, Description: shareDescription, Size: sizeInGiB, + Metadata: shareMetadata, } share, manilaErrCode, err := getOrCreateShare(shareName, createOpts, manilaClient) @@ -78,6 +86,11 @@ func (volumeFromSnapshot) create(req *csi.CreateVolumeRequest, shareName string, return nil, status.Error(codes.InvalidArgument, "snapshot ID cannot be empty") } + shareMetadata, err := parseStringMapFromJson(shareOpts.AppendShareMetadata) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "failed to parse appendShareMetadata field: %v", err) + } + klog.V(4).Infof("restoring snapshot %s into a share (%s) in AZ %s", snapshotSource.GetSnapshotId(), shareName, coalesceValue(shareOpts.AvailabilityZone)) snapshot, err := manilaClient.GetSnapshotByID(snapshotSource.GetSnapshotId()) @@ -106,6 +119,7 @@ func (volumeFromSnapshot) create(req *csi.CreateVolumeRequest, shareName string, Name: shareName, Description: shareDescription, Size: sizeInGiB, + Metadata: shareMetadata, } share, manilaErrCode, err := getOrCreateShare(shareName, createOpts, manilaClient) @@ -124,3 +138,12 @@ func (volumeFromSnapshot) create(req *csi.CreateVolumeRequest, shareName string, return share, err } + +func parseStringMapFromJson(data string) (m map[string]string, err error) { + if data == "" { + return + } + + err = json.Unmarshal([]byte(data), &m) + return +}