Skip to content

Commit

Permalink
Add option --extra-create-metadata-prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
nagius committed Jul 5, 2024
1 parent e45cf27 commit 5a3f299
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 19 deletions.
18 changes: 10 additions & 8 deletions cmd/csi-provisioner/csi-provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,15 @@ var (

enableLeaderElection = flag.Bool("leader-election", false, "Enables leader election. If leader election is enabled, additional RBAC rules are required. Please refer to the Kubernetes CSI documentation for instructions on setting up these RBAC rules.")

leaderElectionNamespace = flag.String("leader-election-namespace", "", "Namespace where the leader election resource lives. Defaults to the pod namespace if not set.")
strictTopology = flag.Bool("strict-topology", false, "Late binding: pass only selected node topology to CreateVolume Request, unlike default behavior of passing aggregated cluster topologies that match with topology keys of the selected node.")
immediateTopology = flag.Bool("immediate-topology", true, "Immediate binding: pass aggregated cluster topologies for all nodes where the CSI driver is available (enabled, the default) or no topology requirements (if disabled).")
extraCreateMetadata = flag.Bool("extra-create-metadata", false, "If set, add pv/pvc metadata to plugin create requests as parameters.")
metricsAddress = flag.String("metrics-address", "", "(deprecated) The TCP network address where the prometheus metrics endpoint will listen (example: `:8080`). The default is empty string, which means metrics endpoint is disabled. Only one of `--metrics-address` and `--http-endpoint` can be set.")
httpEndpoint = flag.String("http-endpoint", "", "The TCP network address where the HTTP server for diagnostics, including pprof, metrics and leader election health check, will listen (example: `:8080`). The default is empty string, which means the server is disabled. Only one of `--metrics-address` and `--http-endpoint` can be set.")
metricsPath = flag.String("metrics-path", "/metrics", "The HTTP path where prometheus metrics will be exposed. Default is `/metrics`.")
enableProfile = flag.Bool("enable-pprof", false, "Enable pprof profiling on the TCP network address specified by --http-endpoint. The HTTP path is `/debug/pprof/`.")
leaderElectionNamespace = flag.String("leader-election-namespace", "", "Namespace where the leader election resource lives. Defaults to the pod namespace if not set.")
strictTopology = flag.Bool("strict-topology", false, "Late binding: pass only selected node topology to CreateVolume Request, unlike default behavior of passing aggregated cluster topologies that match with topology keys of the selected node.")
immediateTopology = flag.Bool("immediate-topology", true, "Immediate binding: pass aggregated cluster topologies for all nodes where the CSI driver is available (enabled, the default) or no topology requirements (if disabled).")
extraCreateMetadata = flag.Bool("extra-create-metadata", false, "If set, add pv/pvc metadata to plugin create requests as parameters.")
extraCreateMetadataPrefix = flag.String("extra-create-metadata-prefix", "", "If set, add pvc annotations starting with this prefix to plugin create requests as parameters.")
metricsAddress = flag.String("metrics-address", "", "(deprecated) The TCP network address where the prometheus metrics endpoint will listen (example: `:8080`). The default is empty string, which means metrics endpoint is disabled. Only one of `--metrics-address` and `--http-endpoint` can be set.")
httpEndpoint = flag.String("http-endpoint", "", "The TCP network address where the HTTP server for diagnostics, including pprof, metrics and leader election health check, will listen (example: `:8080`). The default is empty string, which means the server is disabled. Only one of `--metrics-address` and `--http-endpoint` can be set.")
metricsPath = flag.String("metrics-path", "/metrics", "The HTTP path where prometheus metrics will be exposed. Default is `/metrics`.")
enableProfile = flag.Bool("enable-pprof", false, "Enable pprof profiling on the TCP network address specified by --http-endpoint. The HTTP path is `/debug/pprof/`.")

leaderElectionLeaseDuration = flag.Duration("leader-election-lease-duration", 15*time.Second, "Duration, in seconds, that non-leader candidates will wait to force acquire leadership. Defaults to 15 seconds.")
leaderElectionRenewDeadline = flag.Duration("leader-election-renew-deadline", 10*time.Second, "Duration, in seconds, that the acting leader will retry refreshing leadership before giving up. Defaults to 10 seconds.")
Expand Down Expand Up @@ -424,6 +425,7 @@ func main() {
vaLister,
referenceGrantLister,
*extraCreateMetadata,
*extraCreateMetadataPrefix,
*defaultFSType,
nodeDeployment,
*controllerPublishReadOnly,
Expand Down
12 changes: 12 additions & 0 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ type csiProvisioner struct {
vaLister storagelistersv1.VolumeAttachmentLister
referenceGrantLister referenceGrantv1beta1.ReferenceGrantLister
extraCreateMetadata bool
extraCreateMetadataPrefix string
eventRecorder record.EventRecorder
nodeDeployment *internalNodeDeployment
controllerPublishReadOnly bool
Expand Down Expand Up @@ -353,6 +354,7 @@ func NewCSIProvisioner(client kubernetes.Interface,
vaLister storagelistersv1.VolumeAttachmentLister,
referenceGrantLister referenceGrantv1beta1.ReferenceGrantLister,
extraCreateMetadata bool,
extraCreateMetadataPrefix string,
defaultFSType string,
nodeDeployment *NodeDeployment,
controllerPublishReadOnly bool,
Expand Down Expand Up @@ -389,6 +391,7 @@ func NewCSIProvisioner(client kubernetes.Interface,
vaLister: vaLister,
referenceGrantLister: referenceGrantLister,
extraCreateMetadata: extraCreateMetadata,
extraCreateMetadataPrefix: extraCreateMetadataPrefix,
eventRecorder: eventRecorder,
controllerPublishReadOnly: controllerPublishReadOnly,
preventVolumeModeConversion: preventVolumeModeConversion,
Expand Down Expand Up @@ -749,6 +752,15 @@ func (p *csiProvisioner) prepareProvision(ctx context.Context, claim *v1.Persist
req.Parameters[pvcNamespaceKey] = claim.GetNamespace()
req.Parameters[pvNameKey] = pvName
}

if p.extraCreateMetadataPrefix != "" {
// add pvc annotations starting with this prefix as parameters to request for use by the plugin
for annotation, value := range claim.Annotations {
if strings.HasPrefix(annotation, p.extraCreateMetadataPrefix) {
req.Parameters[annotation] = value
}
}
}
deletionAnnSecrets := new(deletionSecretParams)

if provisionerSecretRef != nil {
Expand Down
61 changes: 50 additions & 11 deletions pkg/controller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ func TestCreateDriverReturnsInvalidCapacityDuringProvision(t *testing.T) {

pluginCaps, controllerCaps := provisionCapabilities()
csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test",
5, csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), nil, nil, nil, nil, nil, nil, false, defaultfsType, nil, true, false)
5, csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), nil, nil, nil, nil, nil, nil, false, "", defaultfsType, nil, true, false)

// Requested PVC with requestedBytes storage
deletePolicy := v1.PersistentVolumeReclaimDelete
Expand Down Expand Up @@ -871,6 +871,7 @@ type provisioningTestcase struct {
expectState controller.ProvisioningState
expectCreateVolDo func(t *testing.T, ctx context.Context, req *csi.CreateVolumeRequest)
withExtraMetadata bool
withExtraMetadataPrefix string
skipCreateVolume bool
deploymentNode string // fake distributed provisioning with this node as host
immediateBinding bool // enable immediate binding support for distributed provisioning
Expand Down Expand Up @@ -1181,6 +1182,44 @@ func provisionTestcases() (int64, map[string]provisioningTestcase) {
},
expectState: controller.ProvisioningFinished,
},
"normal provision with extra metadata prefix": {
volOpts: controller.ProvisionOptions{
StorageClass: &storagev1.StorageClass{
ReclaimPolicy: &deletePolicy,
Parameters: map[string]string{
"fstype": "ext3",
},
},
PVName: "test-name",
PVC: createFakeNamedPVC(requestedBytes, "fake-pvc", map[string]string{"csi.my.company.org/some_annotation": "1234"}),
},
withExtraMetadataPrefix: "csi.my.company.org",
expectedPVSpec: &pvSpec{
Name: "test-testi",
ReclaimPolicy: v1.PersistentVolumeReclaimDelete,
Capacity: v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): bytesToQuantity(requestedBytes),
},
CSIPVS: &v1.CSIPersistentVolumeSource{
Driver: "test-driver",
VolumeHandle: "test-volume-id",
FSType: "ext3",
VolumeAttributes: map[string]string{
"storage.kubernetes.io/csiProvisionerIdentity": "test-provisioner",
},
},
},
expectCreateVolDo: func(t *testing.T, ctx context.Context, req *csi.CreateVolumeRequest) {
expectedParams := map[string]string{
"csi.my.company.org/some_annotation": "1234",
"fstype": "ext3",
}
if fmt.Sprintf("%v", req.Parameters) != fmt.Sprintf("%v", expectedParams) { // only pvc name/namespace left
t.Errorf("Unexpected parameters: %v", req.Parameters)
}
},
expectState: controller.ProvisioningFinished,
},
"multiple fsType provision": {
volOpts: controller.ProvisionOptions{
StorageClass: &storagev1.StorageClass{
Expand Down Expand Up @@ -2566,7 +2605,7 @@ func runFSTypeProvisionTest(t *testing.T, k string, tc provisioningFSTypeTestcas
myDefaultfsType = ""
}
csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5, csiConn.conn,
nil, provisionDriverName, pluginCaps, controllerCaps, supportsMigrationFromInTreePluginName, false, true, csitrans.New(), nil, nil, nil, nil, nil, nil, false, myDefaultfsType, nil, false, false)
nil, provisionDriverName, pluginCaps, controllerCaps, supportsMigrationFromInTreePluginName, false, true, csitrans.New(), nil, nil, nil, nil, nil, nil, false, "", myDefaultfsType, nil, false, false)
out := &csi.CreateVolumeResponse{
Volume: &csi.Volume{
CapacityBytes: requestedBytes,
Expand Down Expand Up @@ -2750,7 +2789,7 @@ func runProvisionTest(t *testing.T, tc provisioningTestcase, requestedBytes int6
}
mycontrollerPublishReadOnly := tc.controllerPublishReadOnly
csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5, csiConn.conn,
nil, provisionDriverName, pluginCaps, controllerCaps, supportsMigrationFromInTreePluginName, false, true, csitrans.New(), scInformer.Lister(), csiNodeInformer.Lister(), nodeInformer.Lister(), nil, nil, nil, tc.withExtraMetadata, defaultfsType, nodeDeployment, mycontrollerPublishReadOnly, false)
nil, provisionDriverName, pluginCaps, controllerCaps, supportsMigrationFromInTreePluginName, false, true, csitrans.New(), scInformer.Lister(), csiNodeInformer.Lister(), nodeInformer.Lister(), nil, nil, nil, tc.withExtraMetadata, tc.withExtraMetadataPrefix, defaultfsType, nodeDeployment, mycontrollerPublishReadOnly, false)

// Adding objects to the informer ensures that they are consistent with
// the fake storage without having to start the informers.
Expand Down Expand Up @@ -4539,7 +4578,7 @@ func TestProvisionFromSnapshot(t *testing.T) {

pluginCaps, controllerCaps := provisionFromSnapshotCapabilities()
csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5, csiConn.conn,
client, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), nil, nil, nil, nil, nil, refGrantLister, false, defaultfsType, nil, true, true)
client, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), nil, nil, nil, nil, nil, refGrantLister, false, "", defaultfsType, nil, true, true)

out := &csi.CreateVolumeResponse{
Volume: &csi.Volume{
Expand Down Expand Up @@ -4719,7 +4758,7 @@ func TestProvisionWithTopologyEnabled(t *testing.T) {
defer close(stopChan)

csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5,
csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), scLister, csiNodeLister, nodeLister, claimLister, vaLister, nil, false, defaultfsType, nil, true, false)
csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), scLister, csiNodeLister, nodeLister, claimLister, vaLister, nil, false, "", defaultfsType, nil, true, false)

pv, _, err := csiProvisioner.Provision(context.Background(), controller.ProvisionOptions{
StorageClass: &storagev1.StorageClass{},
Expand Down Expand Up @@ -4813,7 +4852,7 @@ func TestProvisionErrorHandling(t *testing.T) {
defer close(stopChan)

csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5,
csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), scLister, csiNodeLister, nodeLister, claimLister, vaLister, nil, false, defaultfsType, nil, true, false)
csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), scLister, csiNodeLister, nodeLister, claimLister, vaLister, nil, false, "", defaultfsType, nil, true, false)

options := controller.ProvisionOptions{
StorageClass: &storagev1.StorageClass{},
Expand Down Expand Up @@ -4886,7 +4925,7 @@ func TestProvisionWithTopologyDisabled(t *testing.T) {
clientSet := fakeclientset.NewSimpleClientset()
pluginCaps, controllerCaps := provisionWithTopologyCapabilities()
csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5,
csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), nil, nil, nil, nil, nil, nil, false, defaultfsType, nil, true, false)
csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), nil, nil, nil, nil, nil, nil, false, "", defaultfsType, nil, true, false)

out := &csi.CreateVolumeResponse{
Volume: &csi.Volume{
Expand Down Expand Up @@ -5582,7 +5621,7 @@ func runDeleteTest(t *testing.T, k string, tc deleteTestcase) {
pluginCaps, controllerCaps := provisionCapabilities()
scLister, _, _, _, vaLister, _ := listers(clientSet)
csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5,
csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), scLister, nil, nil, nil, vaLister, nil, false, defaultfsType, nodeDeployment, true, false)
csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), scLister, nil, nil, nil, vaLister, nil, false, "", defaultfsType, nodeDeployment, true, false)

err = csiProvisioner.Delete(context.Background(), tc.persistentVolume)
if tc.expectErr && err == nil {
Expand Down Expand Up @@ -6668,7 +6707,7 @@ func TestProvisionFromPVC(t *testing.T) {

// Phase: execute the test
csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5, csiConn.conn,
nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), nil, nil, nil, claimLister, nil, refGrantLister, false, defaultfsType, nil, true, false)
nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), nil, nil, nil, claimLister, nil, refGrantLister, false, "", defaultfsType, nil, true, false)

pv, _, err = csiProvisioner.Provision(context.Background(), tc.volOpts)
if tc.expectErr && err == nil {
Expand Down Expand Up @@ -6802,7 +6841,7 @@ func TestProvisionWithMigration(t *testing.T) {
pluginCaps, controllerCaps := provisionCapabilities()
csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner",
"test", 5, csiConn.conn, nil, driverName, pluginCaps, controllerCaps,
inTreePluginName, false, true, mockTranslator, nil, nil, nil, nil, nil, nil, false, defaultfsType, nil, true, false)
inTreePluginName, false, true, mockTranslator, nil, nil, nil, nil, nil, nil, false, "", defaultfsType, nil, true, false)

// Set up return values (AnyTimes to avoid overfitting on implementation)

Expand Down Expand Up @@ -6978,7 +7017,7 @@ func TestDeleteMigration(t *testing.T) {
defer close(stopCh)
csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner",
"test", 5, csiConn.conn, nil, driverName, pluginCaps, controllerCaps, inTreePluginName,
false, true, mockTranslator, scLister, nil, nil, nil, vaLister, nil, false, defaultfsType, nil, true, false)
false, true, mockTranslator, scLister, nil, nil, nil, vaLister, nil, false, "", defaultfsType, nil, true, false)

// Set mock return values (AnyTimes to avoid overfitting on implementation details)
mockTranslator.EXPECT().IsPVMigratable(gomock.Any()).Return(tc.expectTranslation).AnyTimes()
Expand Down

0 comments on commit 5a3f299

Please sign in to comment.