diff --git a/Gopkg.lock b/Gopkg.lock index dc1c02953d..6f358b3513 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -534,8 +534,8 @@ "pkg/util/feature/testing", ] pruneopts = "NUT" - revision = "8b27c41bdbb11ff103caa673315e097bf0289171" - version = "kubernetes-1.14.0" + revision = "1ec86e4da56ce0573788fc12bb3a5530600c0e5d" + version = "kubernetes-1.14.1" [[projects]] digest = "1:85f25c196bc700354adc889a397f6550105865ad2588704094276f78f6e9d9ba" @@ -753,14 +753,14 @@ [[projects]] branch = "master" - digest = "1:4f625748474cd525730ed105e6f0d344a555881207bc7aed241a4356b63804f0" + digest = "1:3579cdaf49281ad05bf2679d5a2740476c1618649a3db724e7f519f25d55ba1f" name = "k8s.io/csi-translation-lib" packages = [ ".", "plugins", ] pruneopts = "NUT" - revision = "7f5cabc6aac80cb6cdcf30c37d23947401f26a21" + revision = "e1b42b89656a9ff97090d1e72559aec3b33c9dee" [[projects]] digest = "1:c263611800c3a97991dbcf9d3bc4de390f6224aaa8ca0a7226a9d734f65a416a" @@ -802,7 +802,7 @@ revision = "21c4ce38f2a793ec01e925ddc31216500183b773" [[projects]] - digest = "1:a2147c72c6ac436c7cbd3ffaefb3a8ca26264dd60fed5aec22cf4ed6d6c42690" + digest = "1:1628303a766eb8b6a1185756a064843933f453851720ad75e219489356dc26fa" name = "sigs.k8s.io/sig-storage-lib-external-provisioner" packages = [ "controller", @@ -810,8 +810,8 @@ "util", ] pruneopts = "NUT" - revision = "3eea7193b4c5c034f885913c03105178e9e23a4f" - version = "v3.1.0" + revision = "d22b74e900af4bf90174d259c3e52c3680b41ab4" + version = "v4.0.0" [[projects]] digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c" @@ -837,6 +837,7 @@ "github.com/spf13/pflag", "google.golang.org/grpc", "k8s.io/api/core/v1", + "k8s.io/api/storage/v1", "k8s.io/api/storage/v1beta1", "k8s.io/apimachinery/pkg/api/resource", "k8s.io/apimachinery/pkg/apis/meta/v1", diff --git a/Gopkg.toml b/Gopkg.toml index f22a09c711..a9ce8dea20 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -25,13 +25,17 @@ name = "github.com/container-storage-interface/spec" version = "1.0" +[[constraint]] + name = "k8s.io/csi-translation-lib" + branch = "master" + [[constraint]] name = "github.com/kubernetes-csi/csi-test" - version = "2.0" + version = "v2.0.0" [[constraint]] name = "sigs.k8s.io/sig-storage-lib-external-provisioner" - version = "v3.1.0" + version = "v4.0.0" # TODO: remove when released [[constraint]] @@ -45,7 +49,7 @@ # up with something older or master. [[constraint]] name = "k8s.io/apiserver" - version = "kubernetes-1.14.0" + version = "kubernetes-1.14.1" [[constraint]] name = "k8s.io/component-base" diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index cb98606d31..d2eb080b06 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -18,6 +18,7 @@ package controller import ( "context" + "errors" "fmt" "math" "os" @@ -311,46 +312,44 @@ func getAccessMode(pvcAccessMode v1.PersistentVolumeAccessMode) *csi.VolumeCapab } func getVolumeCapability( - pvcOptions controller.VolumeOptions, + options controller.ProvisionOptions, pvcAccessMode v1.PersistentVolumeAccessMode, fsType string, ) *csi.VolumeCapability { - if util.CheckPersistentVolumeClaimModeBlock(pvcOptions.PVC) { + if util.CheckPersistentVolumeClaimModeBlock(options.PVC) { return &csi.VolumeCapability{ AccessType: getAccessTypeBlock(), AccessMode: getAccessMode(pvcAccessMode), } } return &csi.VolumeCapability{ - AccessType: getAccessTypeMount(fsType, pvcOptions.MountOptions), + AccessType: getAccessTypeMount(fsType, options.StorageClass.MountOptions), AccessMode: getAccessMode(pvcAccessMode), } } -func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.PersistentVolume, error) { - createVolumeRequestParameters := options.Parameters +func (p *csiProvisioner) Provision(options controller.ProvisionOptions) (*v1.PersistentVolume, error) { + if options.StorageClass == nil { + return nil, errors.New("storage class was nil") + } + migratedVolume := false if p.supportsMigrationFromInTreePluginName != "" { - storageClassName := options.PVC.Spec.StorageClassName - // TODO(https://github.com/kubernetes-csi/external-provisioner/issues/256): use informers // NOTE: we cannot depend on PVC.Annotations[volume.beta.kubernetes.io/storage-provisioner] to get // the in-tree provisioner name in case of CSI migration scenarios. The annotation will be // set to the CSI provisioner name by PV controller for migration scenarios // so that external provisioner can correctly pick up the PVC pointing to an in-tree plugin - storageClass, err := p.client.StorageV1().StorageClasses().Get(*storageClassName, metav1.GetOptions{}) - if err != nil { - return nil, fmt.Errorf("failed to get storage class named %s: %v", *storageClassName, err) - } - if storageClass.Provisioner == p.supportsMigrationFromInTreePluginName { - klog.V(2).Infof("translating storage class parameters for in-tree plugin %s to CSI", storageClass.Provisioner) - createVolumeRequestParameters, err = csitranslationlib.TranslateInTreeStorageClassParametersToCSI(p.supportsMigrationFromInTreePluginName, options.Parameters) + if options.StorageClass.Provisioner == p.supportsMigrationFromInTreePluginName { + klog.V(2).Infof("translating storage class for in-tree plugin %s to CSI", options.StorageClass.Provisioner) + storageClass, err := csitranslationlib.TranslateInTreeStorageClassToCSI(p.supportsMigrationFromInTreePluginName, options.StorageClass) if err != nil { - return nil, fmt.Errorf("failed to translate storage class parameters: %v", err) + return nil, fmt.Errorf("failed to translate storage class: %v", err) } + options.StorageClass = storageClass migratedVolume = true } else { - klog.V(4).Infof("skip translation of storage class parameters for plugin: %s", storageClass.Provisioner) + klog.V(4).Infof("skip translation of storage class for plugin: %s", options.StorageClass.Provisioner) } } @@ -384,7 +383,7 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis fsTypesFound := 0 fsType := "" - for k, v := range createVolumeRequestParameters { + for k, v := range options.StorageClass.Parameters { if strings.ToLower(k) == "fstype" || k == prefixedFsTypeKey { fsType = v fsTypesFound++ @@ -412,7 +411,7 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis // Create a CSI CreateVolumeRequest and Response req := csi.CreateVolumeRequest{ Name: pvName, - Parameters: createVolumeRequestParameters, + Parameters: options.StorageClass.Parameters, VolumeCapabilities: volumeCaps, CapacityRange: &csi.CapacityRange{ RequiredBytes: int64(volSizeBytes), @@ -432,7 +431,7 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis p.client, p.driverName, options.PVC.Name, - options.AllowedTopologies, + options.StorageClass.AllowedTopologies, options.SelectedNode) if err != nil { return nil, fmt.Errorf("error generating accessibility requirements: %v", err) @@ -446,7 +445,7 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis // Resolve provision secret credentials. // No PVC is provided when resolving provision/delete secret names, since the PVC may or may not exist at delete time. - provisionerSecretRef, err := getSecretReference(provisionerSecretParams, createVolumeRequestParameters, pvName, nil) + provisionerSecretRef, err := getSecretReference(provisionerSecretParams, options.StorageClass.Parameters, pvName, nil) if err != nil { return nil, err } @@ -457,20 +456,20 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis req.Secrets = provisionerCredentials // Resolve controller publish, node stage, node publish secret references - controllerPublishSecretRef, err := getSecretReference(controllerPublishSecretParams, createVolumeRequestParameters, pvName, options.PVC) + controllerPublishSecretRef, err := getSecretReference(controllerPublishSecretParams, options.StorageClass.Parameters, pvName, options.PVC) if err != nil { return nil, err } - nodeStageSecretRef, err := getSecretReference(nodeStageSecretParams, createVolumeRequestParameters, pvName, options.PVC) + nodeStageSecretRef, err := getSecretReference(nodeStageSecretParams, options.StorageClass.Parameters, pvName, options.PVC) if err != nil { return nil, err } - nodePublishSecretRef, err := getSecretReference(nodePublishSecretParams, createVolumeRequestParameters, pvName, options.PVC) + nodePublishSecretRef, err := getSecretReference(nodePublishSecretParams, options.StorageClass.Parameters, pvName, options.PVC) if err != nil { return nil, err } - req.Parameters, err = removePrefixedParameters(createVolumeRequestParameters) + req.Parameters, err = removePrefixedParameters(options.StorageClass.Parameters) if err != nil { return nil, fmt.Errorf("failed to strip CSI Parameters of prefixed keys: %v", err) } @@ -511,9 +510,8 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis Name: pvName, }, Spec: v1.PersistentVolumeSpec{ - PersistentVolumeReclaimPolicy: options.PersistentVolumeReclaimPolicy, - AccessModes: options.PVC.Spec.AccessModes, - MountOptions: options.MountOptions, + AccessModes: options.PVC.Spec.AccessModes, + MountOptions: options.StorageClass.MountOptions, Capacity: v1.ResourceList{ v1.ResourceName(v1.ResourceStorage): bytesToGiQuantity(respCap), }, @@ -531,6 +529,10 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis }, } + if options.StorageClass.ReclaimPolicy != nil { + pv.Spec.PersistentVolumeReclaimPolicy = *options.StorageClass.ReclaimPolicy + } + if p.supportsTopology() { pv.Spec.NodeAffinity = GenerateVolumeNodeAffinity(rep.Volume.AccessibleTopology) } @@ -592,7 +594,7 @@ func removePrefixedParameters(param map[string]string) (map[string]string, error return newParam, nil } -func (p *csiProvisioner) getVolumeContentSource(options controller.VolumeOptions) (*csi.VolumeContentSource, error) { +func (p *csiProvisioner) getVolumeContentSource(options controller.ProvisionOptions) (*csi.VolumeContentSource, error) { snapshotObj, err := p.snapshotClient.VolumesnapshotV1alpha1().VolumeSnapshots(options.PVC.Namespace).Get(options.PVC.Spec.DataSource.Name, metav1.GetOptions{}) if err != nil { return nil, fmt.Errorf("error getting snapshot %s from api server: %v", options.PVC.Spec.DataSource.Name, err) diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go index 1b6ffffbfe..4dc42beef3 100644 --- a/pkg/controller/controller_test.go +++ b/pkg/controller/controller_test.go @@ -35,9 +35,9 @@ import ( crdv1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1" "github.com/kubernetes-csi/external-snapshotter/pkg/client/clientset/versioned/fake" "google.golang.org/grpc" - corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" - storage "k8s.io/api/storage/v1beta1" + storagev1 "k8s.io/api/storage/v1" + storagev1beta1 "k8s.io/api/storage/v1beta1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -395,11 +395,14 @@ func TestCreateDriverReturnsInvalidCapacityDuringProvision(t *testing.T) { csiProvisioner := NewCSIProvisioner(nil, 5*time.Second, "test-provisioner", "test", 5, csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "") // Requested PVC with requestedBytes storage - opts := controller.VolumeOptions{ - PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, - PVName: "test-name", - PVC: createFakePVC(requestedBytes), - Parameters: map[string]string{}, + deletePolicy := v1.PersistentVolumeReclaimDelete + opts := controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + ReclaimPolicy: &deletePolicy, + Parameters: map[string]string{}, + }, + PVName: "test-name", + PVC: createFakePVC(requestedBytes), } // Drivers CreateVolume response with lower capacity bytes than request @@ -628,7 +631,7 @@ func TestGetSecretReference(t *testing.T) { } type provisioningTestcase struct { - volOpts controller.VolumeOptions + volOpts controller.ProvisionOptions notNilSelector bool makeVolumeNameErr bool getSecretRefErr bool @@ -651,15 +654,18 @@ type pvSpec struct { func TestProvision(t *testing.T) { var requestedBytes int64 = 100 + deletePolicy := v1.PersistentVolumeReclaimDelete testcases := map[string]provisioningTestcase{ "normal provision": { - volOpts: controller.VolumeOptions{ - PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, - PVName: "test-name", - PVC: createFakePVC(requestedBytes), - Parameters: map[string]string{ - "fstype": "ext3", + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + ReclaimPolicy: &deletePolicy, + Parameters: map[string]string{ + "fstype": "ext3", + }, }, + PVName: "test-name", + PVC: createFakePVC(requestedBytes), }, expectedPVSpec: &pvSpec{ Name: "test-testi", @@ -678,25 +684,29 @@ func TestProvision(t *testing.T) { }, }, "multiple fsType provision": { - volOpts: controller.VolumeOptions{ - PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, - PVName: "test-name", - PVC: createFakePVC(requestedBytes), - Parameters: map[string]string{ - "fstype": "ext3", - prefixedFsTypeKey: "ext4", + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + ReclaimPolicy: &deletePolicy, + Parameters: map[string]string{ + "fstype": "ext3", + prefixedFsTypeKey: "ext4", + }, }, + PVName: "test-name", + PVC: createFakePVC(requestedBytes), }, expectErr: true, }, "provision with prefixed FS Type key": { - volOpts: controller.VolumeOptions{ - PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, - PVName: "test-name", - PVC: createFakePVC(requestedBytes), - Parameters: map[string]string{ - prefixedFsTypeKey: "ext3", + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + ReclaimPolicy: &deletePolicy, + Parameters: map[string]string{ + prefixedFsTypeKey: "ext3", + }, }, + PVName: "test-name", + PVC: createFakePVC(requestedBytes), }, expectedPVSpec: &pvSpec{ Name: "test-testi", @@ -720,9 +730,12 @@ func TestProvision(t *testing.T) { }, }, "provision with access mode multi node multi writer": { - volOpts: controller.VolumeOptions{ - PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, - PVName: "test-name", + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + ReclaimPolicy: &deletePolicy, + Parameters: map[string]string{}, + }, + PVName: "test-name", PVC: &v1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ UID: "testid", @@ -737,7 +750,6 @@ func TestProvision(t *testing.T) { AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteMany}, }, }, - Parameters: map[string]string{}, }, expectedPVSpec: &pvSpec{ Name: "test-testi", @@ -768,9 +780,12 @@ func TestProvision(t *testing.T) { }, }, "provision with access mode multi node multi readonly": { - volOpts: controller.VolumeOptions{ - PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, - PVName: "test-name", + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + ReclaimPolicy: &deletePolicy, + Parameters: map[string]string{}, + }, + PVName: "test-name", PVC: &v1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ UID: "testid", @@ -785,7 +800,6 @@ func TestProvision(t *testing.T) { AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany}, }, }, - Parameters: map[string]string{}, }, expectedPVSpec: &pvSpec{ Name: "test-testi", @@ -816,9 +830,12 @@ func TestProvision(t *testing.T) { }, }, "provision with access mode single writer": { - volOpts: controller.VolumeOptions{ - PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, - PVName: "test-name", + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + ReclaimPolicy: &deletePolicy, + Parameters: map[string]string{}, + }, + PVName: "test-name", PVC: &v1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ UID: "testid", @@ -833,7 +850,6 @@ func TestProvision(t *testing.T) { AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, }, }, - Parameters: map[string]string{}, }, expectedPVSpec: &pvSpec{ Name: "test-testi", @@ -864,9 +880,12 @@ func TestProvision(t *testing.T) { }, }, "provision with multiple access modes": { - volOpts: controller.VolumeOptions{ - PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, - PVName: "test-name", + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + ReclaimPolicy: &deletePolicy, + Parameters: map[string]string{}, + }, + PVName: "test-name", PVC: &v1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ UID: "testid", @@ -881,7 +900,6 @@ func TestProvision(t *testing.T) { AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany, v1.ReadWriteOnce}, }, }, - Parameters: map[string]string{}, }, expectedPVSpec: &pvSpec{ Name: "test-testi", @@ -918,10 +936,13 @@ func TestProvision(t *testing.T) { }, }, "provision with secrets": { - volOpts: controller.VolumeOptions{ - PVName: "test-name", - PVC: createFakePVC(requestedBytes), - Parameters: map[string]string{}, + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + ReclaimPolicy: &deletePolicy, + Parameters: map[string]string{}, + }, + PVName: "test-name", + PVC: createFakePVC(requestedBytes), }, withSecretRefs: true, expectedPVSpec: &pvSpec{ @@ -929,6 +950,7 @@ func TestProvision(t *testing.T) { Capacity: v1.ResourceList{ v1.ResourceName(v1.ResourceStorage): bytesToGiQuantity(requestedBytes), }, + ReclaimPolicy: v1.PersistentVolumeReclaimDelete, CSIPVS: &v1.CSIPersistentVolumeSource{ Driver: "test-driver", VolumeHandle: "test-volume-id", @@ -952,17 +974,21 @@ func TestProvision(t *testing.T) { }, }, "provision with volume mode(Filesystem)": { - volOpts: controller.VolumeOptions{ - PVName: "test-name", - PVC: createFakePVCWithVolumeMode(requestedBytes, volumeModeFileSystem), - Parameters: map[string]string{}, + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + ReclaimPolicy: &deletePolicy, + Parameters: map[string]string{}, + }, + PVName: "test-name", + PVC: createFakePVCWithVolumeMode(requestedBytes, volumeModeFileSystem), }, expectedPVSpec: &pvSpec{ Name: "test-testi", Capacity: v1.ResourceList{ v1.ResourceName(v1.ResourceStorage): bytesToGiQuantity(requestedBytes), }, - VolumeMode: &volumeModeFileSystem, + ReclaimPolicy: v1.PersistentVolumeReclaimDelete, + VolumeMode: &volumeModeFileSystem, CSIPVS: &v1.CSIPersistentVolumeSource{ Driver: "test-driver", VolumeHandle: "test-volume-id", @@ -974,17 +1000,21 @@ func TestProvision(t *testing.T) { }, }, "provision with volume mode(Block)": { - volOpts: controller.VolumeOptions{ - PVName: "test-name", - PVC: createFakePVCWithVolumeMode(requestedBytes, volumeModeBlock), - Parameters: map[string]string{}, + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + ReclaimPolicy: &deletePolicy, + Parameters: map[string]string{}, + }, + PVName: "test-name", + PVC: createFakePVCWithVolumeMode(requestedBytes, volumeModeBlock), }, expectedPVSpec: &pvSpec{ Name: "test-testi", Capacity: v1.ResourceList{ v1.ResourceName(v1.ResourceStorage): bytesToGiQuantity(requestedBytes), }, - VolumeMode: &volumeModeBlock, + ReclaimPolicy: v1.PersistentVolumeReclaimDelete, + VolumeMode: &volumeModeBlock, CSIPVS: &v1.CSIPersistentVolumeSource{ Driver: "test-driver", VolumeHandle: "test-volume-id", @@ -995,16 +1025,18 @@ func TestProvision(t *testing.T) { }, }, "fail to get secret reference": { - volOpts: controller.VolumeOptions{ - PVName: "test-name", - PVC: createFakePVC(requestedBytes), - Parameters: map[string]string{}, + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + Parameters: map[string]string{}, + }, + PVName: "test-name", + PVC: createFakePVC(requestedBytes), }, getSecretRefErr: true, expectErr: true, }, "fail not nil selector": { - volOpts: controller.VolumeOptions{ + volOpts: controller.ProvisionOptions{ PVName: "test-name", PVC: createFakePVC(requestedBytes), }, @@ -1012,7 +1044,7 @@ func TestProvision(t *testing.T) { expectErr: true, }, "fail to make volume name": { - volOpts: controller.VolumeOptions{ + volOpts: controller.ProvisionOptions{ PVName: "test-name", PVC: createFakePVC(requestedBytes), }, @@ -1020,27 +1052,35 @@ func TestProvision(t *testing.T) { expectErr: true, }, "fail to get credentials": { - volOpts: controller.VolumeOptions{ - PVName: "test-name", - PVC: createFakePVC(requestedBytes), - Parameters: map[string]string{}, + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + Parameters: map[string]string{}, + }, + PVName: "test-name", + PVC: createFakePVC(requestedBytes), }, getCredentialsErr: true, expectErr: true, }, "fail vol with less capacity": { - volOpts: controller.VolumeOptions{ - PVName: "test-name", - PVC: createFakePVC(requestedBytes), - Parameters: map[string]string{}, + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + Parameters: map[string]string{}, + }, + PVName: "test-name", + PVC: createFakePVC(requestedBytes), }, volWithLessCap: true, expectErr: true, }, "provision with mount options": { - volOpts: controller.VolumeOptions{ - PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, - PVName: "test-name", + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + Parameters: map[string]string{}, + MountOptions: []string{"foo=bar", "baz=qux"}, + ReclaimPolicy: &deletePolicy, + }, + PVName: "test-name", PVC: &v1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ UID: "testid", @@ -1055,8 +1095,6 @@ func TestProvision(t *testing.T) { AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, }, }, - MountOptions: []string{"foo=bar", "baz=qux"}, - Parameters: map[string]string{}, }, expectedPVSpec: &pvSpec{ Name: "test-testi", @@ -1101,7 +1139,7 @@ func TestProvision(t *testing.T) { } // newSnapshot returns a new snapshot object -func newSnapshot(name, className, boundToContent, snapshotUID, claimName string, ready bool, err *storage.VolumeError, creationTime *metav1.Time, size *resource.Quantity) *crdv1.VolumeSnapshot { +func newSnapshot(name, className, boundToContent, snapshotUID, claimName string, ready bool, err *storagev1beta1.VolumeError, creationTime *metav1.Time, size *resource.Quantity) *crdv1.VolumeSnapshot { snapshot := crdv1.VolumeSnapshot{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -1111,7 +1149,7 @@ func newSnapshot(name, className, boundToContent, snapshotUID, claimName string, SelfLink: "/apis/snapshot.storage.k8s.io/v1alpha1/namespaces/" + "default" + "/volumesnapshots/" + name, }, Spec: crdv1.VolumeSnapshotSpec{ - Source: &corev1.TypedLocalObjectReference{ + Source: &v1.TypedLocalObjectReference{ Name: claimName, Kind: "PersistentVolumeClaim", }, @@ -1175,12 +1213,12 @@ func runProvisionTest(t *testing.T, k string, tc provisioningTestcase, requested } if tc.withSecretRefs { - tc.volOpts.Parameters[controllerPublishSecretNameKey] = "ctrlpublishsecret" - tc.volOpts.Parameters[controllerPublishSecretNamespaceKey] = "default" - tc.volOpts.Parameters[nodeStageSecretNameKey] = "nodestagesecret" - tc.volOpts.Parameters[nodeStageSecretNamespaceKey] = "default" - tc.volOpts.Parameters[nodePublishSecretNameKey] = "nodepublishsecret" - tc.volOpts.Parameters[nodePublishSecretNamespaceKey] = "default" + tc.volOpts.StorageClass.Parameters[controllerPublishSecretNameKey] = "ctrlpublishsecret" + tc.volOpts.StorageClass.Parameters[controllerPublishSecretNamespaceKey] = "default" + tc.volOpts.StorageClass.Parameters[nodeStageSecretNameKey] = "nodestagesecret" + tc.volOpts.StorageClass.Parameters[nodeStageSecretNamespaceKey] = "default" + tc.volOpts.StorageClass.Parameters[nodePublishSecretNameKey] = "nodepublishsecret" + tc.volOpts.StorageClass.Parameters[nodePublishSecretNamespaceKey] = "default" } if tc.notNilSelector { @@ -1188,10 +1226,10 @@ func runProvisionTest(t *testing.T, k string, tc provisioningTestcase, requested } else if tc.makeVolumeNameErr { tc.volOpts.PVC.ObjectMeta.UID = "" } else if tc.getSecretRefErr { - tc.volOpts.Parameters[provisionerSecretNameKey] = "" + tc.volOpts.StorageClass.Parameters[provisionerSecretNameKey] = "" } else if tc.getCredentialsErr { - tc.volOpts.Parameters[provisionerSecretNameKey] = "secretx" - tc.volOpts.Parameters[provisionerSecretNamespaceKey] = "default" + tc.volOpts.StorageClass.Parameters[provisionerSecretNameKey] = "secretx" + tc.volOpts.StorageClass.Parameters[provisionerSecretNamespaceKey] = "default" } else if tc.volWithLessCap { out.Volume.CapacityBytes = int64(80) controllerServer.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(out, nil).Times(1) @@ -1292,6 +1330,7 @@ func TestProvisionFromSnapshot(t *testing.T) { var metaTimeNowUnix = &metav1.Time{ Time: time.Unix(0, timeNow), } + deletePolicy := v1.PersistentVolumeReclaimDelete type pvSpec struct { Name string @@ -1302,7 +1341,7 @@ func TestProvisionFromSnapshot(t *testing.T) { } testcases := map[string]struct { - volOpts controller.VolumeOptions + volOpts controller.ProvisionOptions restoredVolSizeSmall bool wrongDataSource bool snapshotStatusReady bool @@ -1310,9 +1349,12 @@ func TestProvisionFromSnapshot(t *testing.T) { expectErr bool }{ "provision with volume snapshot data source": { - volOpts: controller.VolumeOptions{ - PersistentVolumeReclaimPolicy: v1.PersistentVolumeReclaimDelete, - PVName: "test-name", + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + ReclaimPolicy: &deletePolicy, + Parameters: map[string]string{}, + }, + PVName: "test-name", PVC: &v1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ UID: "testid", @@ -1332,7 +1374,6 @@ func TestProvisionFromSnapshot(t *testing.T) { }, }, }, - Parameters: map[string]string{}, }, snapshotStatusReady: true, expectedPVSpec: &pvSpec{ @@ -1353,7 +1394,10 @@ func TestProvisionFromSnapshot(t *testing.T) { }, }, "fail vol size less than snapshot size": { - volOpts: controller.VolumeOptions{ + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + Parameters: map[string]string{}, + }, PVName: "test-name", PVC: &v1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ @@ -1374,14 +1418,16 @@ func TestProvisionFromSnapshot(t *testing.T) { }, }, }, - Parameters: map[string]string{}, }, restoredVolSizeSmall: true, snapshotStatusReady: true, expectErr: true, }, "fail empty snapshot name": { - volOpts: controller.VolumeOptions{ + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + Parameters: map[string]string{}, + }, PVName: "test-name", PVC: &v1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ @@ -1402,13 +1448,15 @@ func TestProvisionFromSnapshot(t *testing.T) { }, }, }, - Parameters: map[string]string{}, }, wrongDataSource: true, expectErr: true, }, "fail unsupported datasource kind": { - volOpts: controller.VolumeOptions{ + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + Parameters: map[string]string{}, + }, PVName: "test-name", PVC: &v1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ @@ -1429,13 +1477,15 @@ func TestProvisionFromSnapshot(t *testing.T) { }, }, }, - Parameters: map[string]string{}, }, wrongDataSource: true, expectErr: true, }, "fail unsupported apigroup": { - volOpts: controller.VolumeOptions{ + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + Parameters: map[string]string{}, + }, PVName: "test-name", PVC: &v1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ @@ -1456,13 +1506,15 @@ func TestProvisionFromSnapshot(t *testing.T) { }, }, }, - Parameters: map[string]string{}, }, wrongDataSource: true, expectErr: true, }, "fail invalid snapshot status": { - volOpts: controller.VolumeOptions{ + volOpts: controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + Parameters: map[string]string{}, + }, PVName: "test-name", PVC: &v1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ @@ -1483,7 +1535,6 @@ func TestProvisionFromSnapshot(t *testing.T) { }, }, }, - Parameters: map[string]string{}, }, snapshotStatusReady: false, expectErr: true, @@ -1668,8 +1719,9 @@ func TestProvisionWithTopologyEnabled(t *testing.T) { clientSet := fakeclientset.NewSimpleClientset(nodes, nodeInfos) csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5, csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "") - pv, err := csiProvisioner.Provision(controller.VolumeOptions{ - PVC: createFakePVC(requestBytes), + pv, err := csiProvisioner.Provision(controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{}, + PVC: createFakePVC(requestBytes), }) if !tc.expectError { if err != nil { @@ -1731,16 +1783,18 @@ func TestProvisionWithTopologyDisabled(t *testing.T) { controllerServer.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(out, nil).Times(1) - pv, err := csiProvisioner.Provision(controller.VolumeOptions{ - PVC: createFakePVC(requestBytes), + pv, err := csiProvisioner.Provision(controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{}, + PVC: createFakePVC(requestBytes), SelectedNode: &v1.Node{ ObjectMeta: metav1.ObjectMeta{ Name: "some-node", }, }, }) + if err != nil { - t.Errorf("got error from Provision call: %v", err) + t.Fatalf("got error from Provision call: %v", err) } if pv.Spec.NodeAffinity != nil { @@ -1775,9 +1829,11 @@ func TestProvisionWithMountOptions(t *testing.T) { controllerServer.EXPECT().CreateVolume(gomock.Any(), gomock.Any()).Return(out, nil).Times(1) - pv, err := csiProvisioner.Provision(controller.VolumeOptions{ - PVC: createFakePVC(requestBytes), // dummy PVC - MountOptions: expectedOptions, + pv, err := csiProvisioner.Provision(controller.ProvisionOptions{ + StorageClass: &storagev1.StorageClass{ + MountOptions: expectedOptions, + }, + PVC: createFakePVC(requestBytes), // dummy PVC }) if err != nil { t.Fatalf("got error from Provision call: %v", err) diff --git a/vendor/k8s.io/csi-translation-lib/plugins/aws_ebs.go b/vendor/k8s.io/csi-translation-lib/plugins/aws_ebs.go index 9cb6176849..6a9a8f6a6c 100644 --- a/vendor/k8s.io/csi-translation-lib/plugins/aws_ebs.go +++ b/vendor/k8s.io/csi-translation-lib/plugins/aws_ebs.go @@ -24,6 +24,7 @@ import ( "strings" "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" ) const ( @@ -44,8 +45,8 @@ func NewAWSElasticBlockStoreCSITranslator() InTreePlugin { } // TranslateInTreeStorageClassParametersToCSI translates InTree EBS storage class parameters to CSI storage class -func (t *awsElasticBlockStoreCSITranslator) TranslateInTreeStorageClassParametersToCSI(scParameters map[string]string) (map[string]string, error) { - return scParameters, nil +func (t *awsElasticBlockStoreCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { + return sc, nil } // TranslateInTreePVToCSI takes a PV with AWSElasticBlockStore set from in-tree diff --git a/vendor/k8s.io/csi-translation-lib/plugins/gce_pd.go b/vendor/k8s.io/csi-translation-lib/plugins/gce_pd.go index 103a62279d..95ada8d227 100644 --- a/vendor/k8s.io/csi-translation-lib/plugins/gce_pd.go +++ b/vendor/k8s.io/csi-translation-lib/plugins/gce_pd.go @@ -22,6 +22,7 @@ import ( "strings" "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" "k8s.io/apimachinery/pkg/util/sets" cloudvolume "k8s.io/cloud-provider/volume" ) @@ -32,6 +33,9 @@ const ( // GCEPDInTreePluginName is the name of the intree plugin for GCE PD GCEPDInTreePluginName = "kubernetes.io/gce-pd" + // GCEPDTopologyKey is the zonal topology key for GCE PD CSI Driver + GCEPDTopologyKey = "topology.gke.io/zone" + // Volume ID Expected Format // "projects/{projectName}/zones/{zoneName}/disks/{diskName}" volIDZonalFmt = "projects/%s/zones/%s/disks/%s" @@ -55,9 +59,102 @@ func NewGCEPersistentDiskCSITranslator() InTreePlugin { return &gcePersistentDiskCSITranslator{} } +func translateAllowedTopologies(terms []v1.TopologySelectorTerm) ([]v1.TopologySelectorTerm, error) { + if terms == nil { + return nil, nil + } + + newTopologies := []v1.TopologySelectorTerm{} + for _, term := range terms { + newTerm := v1.TopologySelectorTerm{} + for _, exp := range term.MatchLabelExpressions { + var newExp v1.TopologySelectorLabelRequirement + if exp.Key == v1.LabelZoneFailureDomain { + newExp = v1.TopologySelectorLabelRequirement{ + Key: GCEPDTopologyKey, + Values: exp.Values, + } + } else if exp.Key == GCEPDTopologyKey { + newExp = exp + } else { + return nil, fmt.Errorf("unknown topology key: %v", exp.Key) + } + newTerm.MatchLabelExpressions = append(newTerm.MatchLabelExpressions, newExp) + } + newTopologies = append(newTopologies, newTerm) + } + return newTopologies, nil +} + +func generateToplogySelectors(key string, values []string) []v1.TopologySelectorTerm { + return []v1.TopologySelectorTerm{ + { + MatchLabelExpressions: []v1.TopologySelectorLabelRequirement{ + { + Key: key, + Values: values, + }, + }, + }, + } +} + // TranslateInTreeStorageClassParametersToCSI translates InTree GCE storage class parameters to CSI storage class -func (g *gcePersistentDiskCSITranslator) TranslateInTreeStorageClassParametersToCSI(scParameters map[string]string) (map[string]string, error) { - return scParameters, nil +func (g *gcePersistentDiskCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { + var generatedTopologies []v1.TopologySelectorTerm + + np := map[string]string{} + for k, v := range sc.Parameters { + switch strings.ToLower(k) { + case "fstype": + // prefixed fstype parameter is stripped out by external provisioner + np["csi.storage.k8s.io/fstype"] = v + // Strip out zone and zones parameters and translate them into topologies instead + case "zone": + generatedTopologies = generateToplogySelectors(GCEPDTopologyKey, []string{v}) + case "zones": + generatedTopologies = generateToplogySelectors(GCEPDTopologyKey, strings.Split(v, ",")) + default: + np[k] = v + } + } + + if len(generatedTopologies) > 0 && len(sc.AllowedTopologies) > 0 { + return nil, fmt.Errorf("cannot simultaneously set allowed topologies and zone/zones parameters") + } else if len(generatedTopologies) > 0 { + sc.AllowedTopologies = generatedTopologies + } else if len(sc.AllowedTopologies) > 0 { + newTopologies, err := translateAllowedTopologies(sc.AllowedTopologies) + if err != nil { + return nil, fmt.Errorf("failed translating allowed topologies: %v", err) + } + sc.AllowedTopologies = newTopologies + } + + sc.Parameters = np + + return sc, nil +} + +// backwardCompatibleAccessModes translates all instances of ReadWriteMany +// access mode from the in-tree plugin to ReadWriteOnce. This is because in-tree +// plugin never supported ReadWriteMany but also did not validate or enforce +// this access mode for pre-provisioned volumes. The GCE PD CSI Driver validates +// and enforces (fails) ReadWriteMany. Therefore we treat all in-tree +// ReadWriteMany as ReadWriteOnce volumes to not break legacy volumes. +func backwardCompatibleAccessModes(ams []v1.PersistentVolumeAccessMode) []v1.PersistentVolumeAccessMode { + if ams == nil { + return nil + } + newAM := []v1.PersistentVolumeAccessMode{} + for _, am := range ams { + if am == v1.ReadWriteMany { + newAM = append(newAM, v1.ReadWriteOnce) + } else { + newAM = append(newAM, am) + } + } + return newAM } // TranslateInTreePVToCSI takes a PV with GCEPersistentDisk set from in-tree @@ -105,6 +202,7 @@ func (g *gcePersistentDiskCSITranslator) TranslateInTreePVToCSI(pv *v1.Persisten pv.Spec.PersistentVolumeSource.GCEPersistentDisk = nil pv.Spec.PersistentVolumeSource.CSI = csiSource + pv.Spec.AccessModes = backwardCompatibleAccessModes(pv.Spec.AccessModes) return pv, nil } diff --git a/vendor/k8s.io/csi-translation-lib/plugins/in_tree_volume.go b/vendor/k8s.io/csi-translation-lib/plugins/in_tree_volume.go index 6d5afd9f1f..d50316743c 100644 --- a/vendor/k8s.io/csi-translation-lib/plugins/in_tree_volume.go +++ b/vendor/k8s.io/csi-translation-lib/plugins/in_tree_volume.go @@ -16,14 +16,17 @@ limitations under the License. package plugins -import "k8s.io/api/core/v1" +import ( + "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" +) // InTreePlugin handles translations between CSI and in-tree sources in a PV type InTreePlugin interface { - // TranslateInTreeStorageClassParametersToCSI takes in-tree storage class - // parameters and translates them to a set of parameters consumable by CSI plugin - TranslateInTreeStorageClassParametersToCSI(scParameters map[string]string) (map[string]string, error) + // TranslateInTreeStorageClassToCSI takes in-tree volume options + // and translates them to a volume options consumable by CSI plugin + TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) // TranslateInTreePVToCSI takes a persistent volume and will translate // the in-tree source to a CSI Source. The input persistent volume can be modified diff --git a/vendor/k8s.io/csi-translation-lib/plugins/openstack_cinder.go b/vendor/k8s.io/csi-translation-lib/plugins/openstack_cinder.go index abd204a557..de283453a4 100644 --- a/vendor/k8s.io/csi-translation-lib/plugins/openstack_cinder.go +++ b/vendor/k8s.io/csi-translation-lib/plugins/openstack_cinder.go @@ -18,7 +18,9 @@ package plugins import ( "fmt" + "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" ) const ( @@ -39,8 +41,8 @@ func NewOpenStackCinderCSITranslator() InTreePlugin { } // TranslateInTreeStorageClassParametersToCSI translates InTree Cinder storage class parameters to CSI storage class -func (t *osCinderCSITranslator) TranslateInTreeStorageClassParametersToCSI(scParameters map[string]string) (map[string]string, error) { - return scParameters, nil +func (t *osCinderCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { + return sc, nil } // TranslateInTreePVToCSI takes a PV with Cinder set from in-tree diff --git a/vendor/k8s.io/csi-translation-lib/translate.go b/vendor/k8s.io/csi-translation-lib/translate.go index ac1a4dd3d8..a13ac422df 100644 --- a/vendor/k8s.io/csi-translation-lib/translate.go +++ b/vendor/k8s.io/csi-translation-lib/translate.go @@ -21,6 +21,7 @@ import ( "fmt" "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" "k8s.io/csi-translation-lib/plugins" ) @@ -32,12 +33,13 @@ var ( } ) -// TranslateInTreeStorageClassParametersToCSI takes in-tree storage class -// parameters and translates them to a set of parameters consumable by CSI plugin -func TranslateInTreeStorageClassParametersToCSI(inTreePluginName string, scParameters map[string]string) (map[string]string, error) { +// TranslateInTreeStorageClassToCSI takes in-tree Storage Class +// and translates it to a set of parameters consumable by CSI plugin +func TranslateInTreeStorageClassToCSI(inTreePluginName string, sc *storage.StorageClass) (*storage.StorageClass, error) { + newSC := sc.DeepCopy() for _, curPlugin := range inTreePlugins { if inTreePluginName == curPlugin.GetInTreePluginName() { - return curPlugin.TranslateInTreeStorageClassParametersToCSI(scParameters) + return curPlugin.TranslateInTreeStorageClassToCSI(newSC) } } return nil, fmt.Errorf("could not find in-tree storage class parameter translation logic for %#v", inTreePluginName) diff --git a/vendor/sigs.k8s.io/sig-storage-lib-external-provisioner/controller/controller.go b/vendor/sigs.k8s.io/sig-storage-lib-external-provisioner/controller/controller.go index 68c8b0d1b7..2e2c3bba0e 100644 --- a/vendor/sigs.k8s.io/sig-storage-lib-external-provisioner/controller/controller.go +++ b/vendor/sigs.k8s.io/sig-storage-lib-external-provisioner/controller/controller.go @@ -1083,12 +1083,12 @@ func (ctrl *ProvisionController) shouldProvision(claim *v1.PersistentVolumeClaim } else { // Kubernetes 1.4 provisioning, evaluating class.Provisioner claimClass := util.GetPersistentVolumeClaimClass(claim) - provisioner, _, err := ctrl.getStorageClassFields(claimClass) + class, err := ctrl.getStorageClass(claimClass) if err != nil { glog.Errorf("Error getting claim %q's StorageClass's fields: %v", claimToClaimKey(claim), err) return false, err } - if provisioner != ctrl.provisionerName { + if class.Provisioner != ctrl.provisionerName { return false, nil } @@ -1223,34 +1223,20 @@ func (ctrl *ProvisionController) provisionClaimOperation(claim *v1.PersistentVol // For any issues getting fields from StorageClass (including reclaimPolicy & mountOptions), // retry the claim because the storageClass can be fixed/(re)created independently of the claim - provisioner, parameters, err := ctrl.getStorageClassFields(claimClass) + class, err := ctrl.getStorageClass(claimClass) if err != nil { glog.Error(logOperation(operation, "error getting claim's StorageClass's fields: %v", err)) return ProvisioningFinished, err } - if !ctrl.knownProvisioner(provisioner) { + if !ctrl.knownProvisioner(class.Provisioner) { // class.Provisioner has either changed since shouldProvision() or // annDynamicallyProvisioned contains different provisioner than // class.Provisioner. - glog.Error(logOperation(operation, "unknown provisioner %q requested in claim's StorageClass", provisioner)) + glog.Error(logOperation(operation, "unknown provisioner %q requested in claim's StorageClass", class.Provisioner)) return ProvisioningFinished, nil } - reclaimPolicy := v1.PersistentVolumeReclaimDelete - if ctrl.kubeVersion.AtLeast(utilversion.MustParseSemantic("v1.8.0")) { - reclaimPolicy, err = ctrl.fetchReclaimPolicy(claimClass) - if err != nil { - return ProvisioningFinished, err - } - } - - mountOptions, err := ctrl.fetchMountOptions(claimClass) - if err != nil { - return ProvisioningFinished, err - } - var selectedNode *v1.Node - var allowedTopologies []v1.TopologySelectorTerm if ctrl.kubeVersion.AtLeast(utilversion.MustParseSemantic("v1.11.0")) { // Get SelectedNode if nodeName, ok := claim.Annotations[annSelectedNode]; ok { @@ -1261,24 +1247,13 @@ func (ctrl *ProvisionController) provisionClaimOperation(claim *v1.PersistentVol return ProvisioningNoChange, err } } - - // Get AllowedTopologies - allowedTopologies, err = ctrl.fetchAllowedTopologies(claimClass) - if err != nil { - err = fmt.Errorf("failed to get AllowedTopologies from StorageClass: %v", err) - ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, "ProvisioningFailed", err.Error()) - return ProvisioningNoChange, err - } } - options := VolumeOptions{ - PersistentVolumeReclaimPolicy: reclaimPolicy, - PVName: pvName, - PVC: claim, - MountOptions: mountOptions, - Parameters: parameters, - SelectedNode: selectedNode, - AllowedTopologies: allowedTopologies, + options := ProvisionOptions{ + StorageClass: class, + PVName: pvName, + PVC: claim, + SelectedNode: selectedNode, } ctrl.eventRecorder.Event(claim, v1.EventTypeNormal, "Provisioning", fmt.Sprintf("External provisioner is provisioning volume for claim %q", claimToClaimKey(claim))) @@ -1436,86 +1411,36 @@ func (ctrl *ProvisionController) getProvisionedVolumeNameForClaim(claim *v1.Pers return "pvc-" + string(claim.UID) } -func (ctrl *ProvisionController) getStorageClassFields(name string) (string, map[string]string, error) { +// getStorageClass retrives storage class object by name. +func (ctrl *ProvisionController) getStorageClass(name string) (*storage.StorageClass, error) { classObj, found, err := ctrl.classes.GetByKey(name) - if err != nil { - return "", nil, err - } - if !found { - return "", nil, fmt.Errorf("storageClass %q not found", name) - // 3. It tries to find a StorageClass instance referenced by annotation - // `claim.Annotations["volume.beta.kubernetes.io/storage-class"]`. If not - // found, it SHOULD report an error (by sending an event to the claim) and it - // SHOULD retry periodically with step i. - } - switch class := classObj.(type) { - case *storage.StorageClass: - return class.Provisioner, class.Parameters, nil - case *storagebeta.StorageClass: - return class.Provisioner, class.Parameters, nil - } - return "", nil, fmt.Errorf("cannot convert object to StorageClass: %+v", classObj) -} - -func claimToClaimKey(claim *v1.PersistentVolumeClaim) string { - return fmt.Sprintf("%s/%s", claim.Namespace, claim.Name) -} - -func (ctrl *ProvisionController) fetchReclaimPolicy(storageClassName string) (v1.PersistentVolumeReclaimPolicy, error) { - classObj, found, err := ctrl.classes.GetByKey(storageClassName) - if err != nil { - return "", err - } - if !found { - return "", fmt.Errorf("storageClass %q not found", storageClassName) - } - - switch class := classObj.(type) { - case *storage.StorageClass: - return *class.ReclaimPolicy, nil - case *storagebeta.StorageClass: - return *class.ReclaimPolicy, nil - } - - return v1.PersistentVolumeReclaimDelete, fmt.Errorf("cannot convert object to StorageClass: %+v", classObj) -} - -func (ctrl *ProvisionController) fetchMountOptions(storageClassName string) ([]string, error) { - classObj, found, err := ctrl.classes.GetByKey(storageClassName) if err != nil { return nil, err } if !found { - return nil, fmt.Errorf("storageClass %q not found", storageClassName) + return nil, fmt.Errorf("storageClass %q not found", name) } - switch class := classObj.(type) { case *storage.StorageClass: - return class.MountOptions, nil + return class, nil case *storagebeta.StorageClass: - return class.MountOptions, nil + // convert storagebeta.StorageClass to storage.StorageClass + return &storage.StorageClass{ + ObjectMeta: class.ObjectMeta, + Provisioner: class.Provisioner, + Parameters: class.Parameters, + ReclaimPolicy: class.ReclaimPolicy, + MountOptions: class.MountOptions, + AllowVolumeExpansion: class.AllowVolumeExpansion, + VolumeBindingMode: (*storage.VolumeBindingMode)(class.VolumeBindingMode), + AllowedTopologies: class.AllowedTopologies, + }, nil } - return nil, fmt.Errorf("cannot convert object to StorageClass: %+v", classObj) } -func (ctrl *ProvisionController) fetchAllowedTopologies(storageClassName string) ([]v1.TopologySelectorTerm, error) { - classObj, found, err := ctrl.classes.GetByKey(storageClassName) - if err != nil { - return nil, err - } - if !found { - return nil, fmt.Errorf("storageClass %q not found", storageClassName) - } - - switch class := classObj.(type) { - case *storage.StorageClass: - return class.AllowedTopologies, nil - case *storagebeta.StorageClass: - return class.AllowedTopologies, nil - } - - return nil, fmt.Errorf("cannot convert object to StorageClass: %+v", classObj) +func claimToClaimKey(claim *v1.PersistentVolumeClaim) string { + return fmt.Sprintf("%s/%s", claim.Namespace, claim.Name) } // supportsBlock returns whether a provisioner supports block volume. diff --git a/vendor/sigs.k8s.io/sig-storage-lib-external-provisioner/controller/volume.go b/vendor/sigs.k8s.io/sig-storage-lib-external-provisioner/controller/volume.go index 368d0c3f70..ef69550af7 100644 --- a/vendor/sigs.k8s.io/sig-storage-lib-external-provisioner/controller/volume.go +++ b/vendor/sigs.k8s.io/sig-storage-lib-external-provisioner/controller/volume.go @@ -20,6 +20,7 @@ import ( "fmt" "k8s.io/api/core/v1" + storageapis "k8s.io/api/storage/v1" ) // Provisioner is an interface that creates templates for PersistentVolumes @@ -29,7 +30,7 @@ import ( type Provisioner interface { // Provision creates a volume i.e. the storage asset and returns a PV object // for the volume - Provision(VolumeOptions) (*v1.PersistentVolume, error) + Provision(ProvisionOptions) (*v1.PersistentVolume, error) // Delete removes the storage asset that was created by Provision backing the // given PV. Does not delete the PV object itself. // @@ -73,7 +74,7 @@ type ProvisionerExt interface { // provisioning the volume. The provisioner must return either final error (with // ProvisioningFinished) or success eventually, otherwise the controller will try // forever (unless FailedProvisionThreshold is set). - ProvisionExt(options VolumeOptions) (*v1.PersistentVolume, ProvisioningState, error) + ProvisionExt(options ProvisionOptions) (*v1.PersistentVolume, ProvisioningState, error) } // ProvisioningState is state of volume provisioning. It tells the controller if @@ -111,28 +112,22 @@ func (e *IgnoredError) Error() string { return fmt.Sprintf("ignored because %s", e.Reason) } -// VolumeOptions contains option information about a volume -// https://github.com/kubernetes/kubernetes/blob/release-1.4/pkg/volume/plugins.go -type VolumeOptions struct { - // Reclamation policy for a persistent volume - PersistentVolumeReclaimPolicy v1.PersistentVolumeReclaimPolicy +// ProvisionOptions contains all information required to provision a volume +type ProvisionOptions struct { + // StorageClass is a reference to the storage class that is used for + // provisioning for this volume + StorageClass *storageapis.StorageClass + // PV.Name of the appropriate PersistentVolume. Used to generate cloud // volume name. PVName string - // PV mount options. Not validated - mount of the PVs will simply fail if one is invalid. - MountOptions []string - // PVC is reference to the claim that lead to provisioning of a new PV. // Provisioners *must* create a PV that would be matched by this PVC, // i.e. with required capacity, accessMode, labels matching PVC.Selector and // so on. PVC *v1.PersistentVolumeClaim - // Volume provisioning parameters from StorageClass - Parameters map[string]string // Node selected by the scheduler for the volume. SelectedNode *v1.Node - // Topology constraint parameter from StorageClass - AllowedTopologies []v1.TopologySelectorTerm }