From a3ef1ff292e80a2683d8fc6f92670d34966fc56f Mon Sep 17 00:00:00 2001 From: David Zhu Date: Mon, 17 Jun 2019 10:29:51 -0700 Subject: [PATCH] Bump version of csi-translation-lib for CSI Migration support for Azure Disk/File, as well as fixes for GCE PD --- Gopkg.lock | 4 +- .../csi-translation-lib/plugins/aws_ebs.go | 35 ++- .../csi-translation-lib/plugins/azure_disk.go | 208 ++++++++++++++++++ .../csi-translation-lib/plugins/azure_file.go | 183 +++++++++++++++ .../csi-translation-lib/plugins/gce_pd.go | 75 ++++++- .../plugins/in_tree_volume.go | 13 +- .../plugins/openstack_cinder.go | 34 ++- .../k8s.io/csi-translation-lib/translate.go | 28 ++- 8 files changed, 566 insertions(+), 14 deletions(-) create mode 100644 vendor/k8s.io/csi-translation-lib/plugins/azure_disk.go create mode 100644 vendor/k8s.io/csi-translation-lib/plugins/azure_file.go diff --git a/Gopkg.lock b/Gopkg.lock index 6f358b3513..1ffd2accf7 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -753,14 +753,14 @@ [[projects]] branch = "master" - digest = "1:3579cdaf49281ad05bf2679d5a2740476c1618649a3db724e7f519f25d55ba1f" + digest = "1:026d302ec8c8f568cb6805891133e749e2f8b6b94068cd7375a3bbba232c9f38" name = "k8s.io/csi-translation-lib" packages = [ ".", "plugins", ] pruneopts = "NUT" - revision = "e1b42b89656a9ff97090d1e72559aec3b33c9dee" + revision = "9ff632302e7ee3b0b6118cd21569ce8b51f7f0f2" [[projects]] digest = "1:c263611800c3a97991dbcf9d3bc4de390f6224aaa8ca0a7226a9d734f65a416a" 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 6a9a8f6a6c..97c264f965 100644 --- a/vendor/k8s.io/csi-translation-lib/plugins/aws_ebs.go +++ b/vendor/k8s.io/csi-translation-lib/plugins/aws_ebs.go @@ -49,6 +49,32 @@ func (t *awsElasticBlockStoreCSITranslator) TranslateInTreeStorageClassToCSI(sc return sc, nil } +// TranslateInTreeInlineVolumeToCSI takes a Volume with AWSElasticBlockStore set from in-tree +// and converts the AWSElasticBlockStore source to a CSIPersistentVolumeSource +func (t *awsElasticBlockStoreCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume, error) { + if volume == nil || volume.AWSElasticBlockStore == nil { + return nil, fmt.Errorf("volume is nil or AWS EBS not defined on volume") + } + ebsSource := volume.AWSElasticBlockStore + pv := &v1.PersistentVolume{ + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: AWSEBSDriverName, + VolumeHandle: ebsSource.VolumeID, + ReadOnly: ebsSource.ReadOnly, + FSType: ebsSource.FSType, + VolumeAttributes: map[string]string{ + "partition": strconv.FormatInt(int64(ebsSource.Partition), 10), + }, + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, + }, + } + return pv, nil +} + // TranslateInTreePVToCSI takes a PV with AWSElasticBlockStore set from in-tree // and converts the AWSElasticBlockStore source to a CSIPersistentVolumeSource func (t *awsElasticBlockStoreCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { @@ -106,13 +132,20 @@ func (t *awsElasticBlockStoreCSITranslator) TranslateCSIPVToInTree(pv *v1.Persis return pv, nil } -// CanSupport tests whether the plugin supports a given volume +// CanSupport tests whether the plugin supports a given persistent volume // specification from the API. The spec pointer should be considered // const. func (t *awsElasticBlockStoreCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { return pv != nil && pv.Spec.AWSElasticBlockStore != nil } +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. The spec pointer should be considered +// const. +func (t *awsElasticBlockStoreCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.AWSElasticBlockStore != nil +} + // GetInTreePluginName returns the name of the intree plugin driver func (t *awsElasticBlockStoreCSITranslator) GetInTreePluginName() string { return AWSEBSInTreePluginName diff --git a/vendor/k8s.io/csi-translation-lib/plugins/azure_disk.go b/vendor/k8s.io/csi-translation-lib/plugins/azure_disk.go new file mode 100644 index 0000000000..7b44c658b5 --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/plugins/azure_disk.go @@ -0,0 +1,208 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugins + +import ( + "fmt" + "regexp" + "strings" + + "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" +) + +const ( + // AzureDiskDriverName is the name of the CSI driver for Azure Disk + AzureDiskDriverName = "disk.csi.azure.com" + // AzureDiskInTreePluginName is the name of the intree plugin for Azure Disk + AzureDiskInTreePluginName = "kubernetes.io/azure-disk" + + // Parameter names defined in azure disk CSI driver, refer to + // https://github.com/kubernetes-sigs/azuredisk-csi-driver/blob/master/docs/driver-parameters.md + azureDiskCachingMode = "cachingMode" + azureDiskFSType = "fsType" +) + +var ( + managedDiskPathRE = regexp.MustCompile(`.*/subscriptions/(?:.*)/resourceGroups/(?:.*)/providers/Microsoft.Compute/disks/(.+)`) + unmanagedDiskPathRE = regexp.MustCompile(`http(?:.*)://(?:.*)/vhds/(.+)`) +) + +var _ InTreePlugin = &azureDiskCSITranslator{} + +// azureDiskCSITranslator handles translation of PV spec from In-tree +// Azure Disk to CSI Azure Disk and vice versa +type azureDiskCSITranslator struct{} + +// NewAzureDiskCSITranslator returns a new instance of azureDiskTranslator +func NewAzureDiskCSITranslator() InTreePlugin { + return &azureDiskCSITranslator{} +} + +// TranslateInTreeStorageClassParametersToCSI translates InTree Azure Disk storage class parameters to CSI storage class +func (t *azureDiskCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { + return sc, nil +} + +// TranslateInTreeInlineVolumeToCSI takes a Volume with AzureDisk set from in-tree +// and converts the AzureDisk source to a CSIPersistentVolumeSource +func (t *azureDiskCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume, error) { + if volume == nil || volume.AzureDisk == nil { + return nil, fmt.Errorf("volume is nil or Azure Disk not defined on volume") + } + + azureSource := volume.AzureDisk + pv := &v1.PersistentVolume{ + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: AzureDiskDriverName, + VolumeHandle: azureSource.DataDiskURI, + ReadOnly: *azureSource.ReadOnly, + FSType: *azureSource.FSType, + VolumeAttributes: map[string]string{}, + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, + }, + } + + if *azureSource.CachingMode != "" { + pv.Spec.PersistentVolumeSource.CSI.VolumeAttributes[azureDiskCachingMode] = string(*azureSource.CachingMode) + } + if *azureSource.FSType != "" { + pv.Spec.PersistentVolumeSource.CSI.VolumeAttributes[azureDiskFSType] = *azureSource.FSType + } + + return pv, nil +} + +// TranslateInTreePVToCSI takes a PV with AzureDisk set from in-tree +// and converts the AzureDisk source to a CSIPersistentVolumeSource +func (t *azureDiskCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.AzureDisk == nil { + return nil, fmt.Errorf("pv is nil or Azure Disk source not defined on pv") + } + + azureSource := pv.Spec.PersistentVolumeSource.AzureDisk + + // refer to https://github.com/kubernetes-sigs/azuredisk-csi-driver/blob/master/docs/driver-parameters.md + csiSource := &v1.CSIPersistentVolumeSource{ + Driver: AzureDiskDriverName, + VolumeHandle: azureSource.DataDiskURI, + ReadOnly: *azureSource.ReadOnly, + FSType: *azureSource.FSType, + VolumeAttributes: map[string]string{}, + } + + if *azureSource.CachingMode != "" { + csiSource.VolumeAttributes[azureDiskCachingMode] = string(*azureSource.CachingMode) + } + + if *azureSource.FSType != "" { + csiSource.VolumeAttributes[azureDiskFSType] = *azureSource.FSType + } + + pv.Spec.PersistentVolumeSource.AzureDisk = nil + pv.Spec.PersistentVolumeSource.CSI = csiSource + pv.Spec.AccessModes = backwardCompatibleAccessModes(pv.Spec.AccessModes) + + return pv, nil +} + +// TranslateCSIPVToInTree takes a PV with CSIPersistentVolumeSource set and +// translates the Azure Disk CSI source to a AzureDisk source. +func (t *azureDiskCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.CSI == nil { + return nil, fmt.Errorf("pv is nil or CSI source not defined on pv") + } + csiSource := pv.Spec.CSI + + diskURI := csiSource.VolumeHandle + diskName, err := getDiskName(diskURI) + if err != nil { + return nil, err + } + + // refer to https://github.com/kubernetes-sigs/azuredisk-csi-driver/blob/master/docs/driver-parameters.md + azureSource := &v1.AzureDiskVolumeSource{ + DiskName: diskName, + DataDiskURI: diskURI, + FSType: &csiSource.FSType, + ReadOnly: &csiSource.ReadOnly, + } + + if csiSource.VolumeAttributes != nil { + if cachingMode, ok := csiSource.VolumeAttributes[azureDiskCachingMode]; ok { + mode := v1.AzureDataDiskCachingMode(cachingMode) + azureSource.CachingMode = &mode + } + + if fsType, ok := csiSource.VolumeAttributes[azureDiskFSType]; ok && fsType != "" { + azureSource.FSType = &fsType + } + } + + pv.Spec.CSI = nil + pv.Spec.AzureDisk = azureSource + + return pv, nil +} + +// CanSupport tests whether the plugin supports a given volume +// specification from the API. The spec pointer should be considered +// const. +func (t *azureDiskCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { + return pv != nil && pv.Spec.AzureDisk != nil +} + +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. The spec pointer should be considered +// const. +func (t *azureDiskCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.AzureDisk != nil +} + +// GetInTreePluginName returns the name of the intree plugin driver +func (t *azureDiskCSITranslator) GetInTreePluginName() string { + return AzureDiskInTreePluginName +} + +// GetCSIPluginName returns the name of the CSI plugin +func (t *azureDiskCSITranslator) GetCSIPluginName() string { + return AzureDiskDriverName +} + +func isManagedDisk(diskURI string) bool { + if len(diskURI) > 4 && strings.ToLower(diskURI[:4]) == "http" { + return false + } + return true +} + +func getDiskName(diskURI string) (string, error) { + diskPathRE := managedDiskPathRE + if !isManagedDisk(diskURI) { + diskPathRE = unmanagedDiskPathRE + } + + matches := diskPathRE.FindStringSubmatch(diskURI) + if len(matches) != 2 { + return "", fmt.Errorf("could not get disk name from %s, correct format: %s", diskURI, diskPathRE) + } + return matches[1], nil +} diff --git a/vendor/k8s.io/csi-translation-lib/plugins/azure_file.go b/vendor/k8s.io/csi-translation-lib/plugins/azure_file.go new file mode 100644 index 0000000000..2b58dbda76 --- /dev/null +++ b/vendor/k8s.io/csi-translation-lib/plugins/azure_file.go @@ -0,0 +1,183 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugins + +import ( + "fmt" + "strings" + + "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" +) + +const ( + // AzureFileDriverName is the name of the CSI driver for Azure File + AzureFileDriverName = "file.csi.azure.com" + // AzureFileInTreePluginName is the name of the intree plugin for Azure file + AzureFileInTreePluginName = "kubernetes.io/azure-file" + + separator = "#" + volumeIDTemplate = "%s#%s#%s" + // Parameter names defined in azure file CSI driver, refer to + // https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/driver-parameters.md + azureFileShareName = "shareName" +) + +var _ InTreePlugin = &azureFileCSITranslator{} + +// azureFileCSITranslator handles translation of PV spec from In-tree +// Azure File to CSI Azure File and vice versa +type azureFileCSITranslator struct{} + +// NewAzureFileCSITranslator returns a new instance of azureFileTranslator +func NewAzureFileCSITranslator() InTreePlugin { + return &azureFileCSITranslator{} +} + +// TranslateInTreeStorageClassParametersToCSI translates InTree Azure File storage class parameters to CSI storage class +func (t *azureFileCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) { + return sc, nil +} + +// TranslateInTreeInlineVolumeToCSI takes a Volume with AzureFile set from in-tree +// and converts the AzureFile source to a CSIPersistentVolumeSource +func (t *azureFileCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume, error) { + if volume == nil || volume.AzureFile == nil { + return nil, fmt.Errorf("volume is nil or AWS EBS not defined on volume") + } + + azureSource := volume.AzureFile + + pv := &v1.PersistentVolume{ + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + VolumeHandle: fmt.Sprintf(volumeIDTemplate, "", azureSource.SecretName, azureSource.ShareName), + ReadOnly: azureSource.ReadOnly, + VolumeAttributes: map[string]string{azureFileShareName: azureSource.ShareName}, + NodePublishSecretRef: &v1.SecretReference{ + Name: azureSource.ShareName, + Namespace: "default", + }, + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteMany}, + }, + } + return pv, nil +} + +// TranslateInTreePVToCSI takes a PV with AzureFile set from in-tree +// and converts the AzureFile source to a CSIPersistentVolumeSource +func (t *azureFileCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.AzureFile == nil { + return nil, fmt.Errorf("pv is nil or Azure File source not defined on pv") + } + + azureSource := pv.Spec.PersistentVolumeSource.AzureFile + + volumeID := fmt.Sprintf(volumeIDTemplate, "", azureSource.SecretName, azureSource.ShareName) + // refer to https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/driver-parameters.md + csiSource := &v1.CSIPersistentVolumeSource{ + VolumeHandle: volumeID, + ReadOnly: azureSource.ReadOnly, + VolumeAttributes: map[string]string{azureFileShareName: azureSource.ShareName}, + } + + csiSource.NodePublishSecretRef = &v1.SecretReference{ + Name: azureSource.ShareName, + Namespace: *azureSource.SecretNamespace, + } + + pv.Spec.PersistentVolumeSource.AzureFile = nil + pv.Spec.PersistentVolumeSource.CSI = csiSource + pv.Spec.AccessModes = backwardCompatibleAccessModes(pv.Spec.AccessModes) + + return pv, nil +} + +// TranslateCSIPVToInTree takes a PV with CSIPersistentVolumeSource set and +// translates the Azure File CSI source to a AzureFile source. +func (t *azureFileCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { + if pv == nil || pv.Spec.CSI == nil { + return nil, fmt.Errorf("pv is nil or CSI source not defined on pv") + } + csiSource := pv.Spec.CSI + + // refer to https://github.com/kubernetes-sigs/azurefile-csi-driver/blob/master/docs/driver-parameters.md + azureSource := &v1.AzureFilePersistentVolumeSource{ + ReadOnly: csiSource.ReadOnly, + } + + if csiSource.NodePublishSecretRef != nil && csiSource.NodePublishSecretRef.Name != "" { + azureSource.SecretName = csiSource.NodePublishSecretRef.Name + azureSource.SecretNamespace = &csiSource.NodePublishSecretRef.Namespace + if csiSource.VolumeAttributes != nil { + if shareName, ok := csiSource.VolumeAttributes[azureFileShareName]; ok { + azureSource.ShareName = shareName + } + } + } else { + _, _, fileShareName, err := getFileShareInfo(csiSource.VolumeHandle) + if err != nil { + return nil, err + } + azureSource.ShareName = fileShareName + // to-do: for dynamic provision scenario in CSI, it uses cluster's identity to get storage account key + // secret for the file share is not created, we may create a serect here + } + + pv.Spec.CSI = nil + pv.Spec.AzureFile = azureSource + + return pv, nil +} + +// CanSupport tests whether the plugin supports a given volume +// specification from the API. The spec pointer should be considered +// const. +func (t *azureFileCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { + return pv != nil && pv.Spec.AzureFile != nil +} + +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. The spec pointer should be considered +// const. +func (t *azureFileCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.AzureFile != nil +} + +// GetInTreePluginName returns the name of the intree plugin driver +func (t *azureFileCSITranslator) GetInTreePluginName() string { + return AzureFileInTreePluginName +} + +// GetCSIPluginName returns the name of the CSI plugin +func (t *azureFileCSITranslator) GetCSIPluginName() string { + return AzureFileDriverName +} + +// get file share info according to volume id, e.g. +// input: "rg#f5713de20cde511e8ba4900#pvc-file-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41" +// output: rg, f5713de20cde511e8ba4900, pvc-file-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41 +func getFileShareInfo(id string) (string, string, string, error) { + segments := strings.Split(id, separator) + if len(segments) < 3 { + return "", "", "", fmt.Errorf("error parsing volume id: %q, should at least contain two #", id) + } + return segments[0], segments[1], segments[2], nil +} 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 95ada8d227..4dee96ef9f 100644 --- a/vendor/k8s.io/csi-translation-lib/plugins/gce_pd.go +++ b/vendor/k8s.io/csi-translation-lib/plugins/gce_pd.go @@ -141,22 +141,80 @@ func (g *gcePersistentDiskCSITranslator) TranslateInTreeStorageClassToCSI(sc *st // 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. +// ReadWriteMany as ReadWriteOnce volumes to not break legacy volumes. It also +// takes [ReadWriteOnce, ReadOnlyMany] and makes it ReadWriteOnce. This is +// because the in-tree plugin does not enforce access modes and just attaches +// the disk in ReadWriteOnce mode; however, the CSI external-attacher will fail +// this combination because technically [ReadWriteOnce, ReadOnlyMany] is not +// supportable on an attached volume +// See: https://github.com/kubernetes-csi/external-attacher/issues/153 func backwardCompatibleAccessModes(ams []v1.PersistentVolumeAccessMode) []v1.PersistentVolumeAccessMode { if ams == nil { return nil } - newAM := []v1.PersistentVolumeAccessMode{} + + s := map[v1.PersistentVolumeAccessMode]bool{} + var newAM []v1.PersistentVolumeAccessMode + for _, am := range ams { if am == v1.ReadWriteMany { - newAM = append(newAM, v1.ReadWriteOnce) + // ReadWriteMany is unsupported in CSI, but in-tree did no + // validation and treated it as ReadWriteOnce + s[v1.ReadWriteOnce] = true } else { - newAM = append(newAM, am) + s[am] = true } } + + switch { + case s[v1.ReadOnlyMany] && s[v1.ReadWriteOnce]: + // ROX,RWO is unsupported in CSI, but in-tree did not validation and + // treated it as ReadWriteOnce + newAM = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce} + case s[v1.ReadWriteOnce]: + newAM = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce} + case s[v1.ReadOnlyMany]: + newAM = []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany} + default: + newAM = []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce} + } + return newAM } +// TranslateInTreeInlineVolumeToCSI takes a Volume with GCEPersistentDisk set from in-tree +// and converts the GCEPersistentDisk source to a CSIPersistentVolumeSource +func (g *gcePersistentDiskCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume, error) { + if volume == nil || volume.GCEPersistentDisk == nil { + return nil, fmt.Errorf("volume is nil or GCE PD not defined on volume") + } + + pdSource := volume.GCEPersistentDisk + + partition := "" + if pdSource.Partition != 0 { + partition = strconv.Itoa(int(pdSource.Partition)) + } + + pv := &v1.PersistentVolume{ + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: GCEPDDriverName, + VolumeHandle: fmt.Sprintf(volIDZonalFmt, UnspecifiedValue, UnspecifiedValue, pdSource.PDName), + ReadOnly: pdSource.ReadOnly, + FSType: pdSource.FSType, + VolumeAttributes: map[string]string{ + "partition": partition, + }, + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, + }, + } + return pv, nil +} + // TranslateInTreePVToCSI takes a PV with GCEPersistentDisk set from in-tree // and converts the GCEPersistentDisk source to a CSIPersistentVolumeSource func (g *gcePersistentDiskCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { @@ -241,13 +299,20 @@ func (g *gcePersistentDiskCSITranslator) TranslateCSIPVToInTree(pv *v1.Persisten return pv, nil } -// CanSupport tests whether the plugin supports a given volume +// CanSupport tests whether the plugin supports a given persistent volume // specification from the API. The spec pointer should be considered // const. func (g *gcePersistentDiskCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { return pv != nil && pv.Spec.GCEPersistentDisk != nil } +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. The spec pointer should be considered +// const. +func (g *gcePersistentDiskCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.GCEPersistentDisk != nil +} + // GetInTreePluginName returns the name of the intree plugin driver func (g *gcePersistentDiskCSITranslator) GetInTreePluginName() string { return GCEPDInTreePluginName 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 d50316743c..2095084d82 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 @@ -28,8 +28,13 @@ type InTreePlugin interface { // and translates them to a volume options consumable by CSI plugin TranslateInTreeStorageClassToCSI(sc *storage.StorageClass) (*storage.StorageClass, error) + // TranslateInTreeInlineVolumeToCSI takes a inline volume and will translate + // the in-tree inline volume source to a CSIPersistentVolumeSource + // A PV object containing the CSIPersistentVolumeSource in it's spec is returned + TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume, error) + // TranslateInTreePVToCSI takes a persistent volume and will translate - // the in-tree source to a CSI Source. The input persistent volume can be modified + // the in-tree pv source to a CSI Source. The input persistent volume can be modified TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) // TranslateCSIPVToInTree takes a PV with a CSI PersistentVolume Source and will translate @@ -37,10 +42,14 @@ type InTreePlugin interface { // by the `Driver` field in the CSI Source. The input PV object can be modified TranslateCSIPVToInTree(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) - // CanSupport tests whether the plugin supports a given volume + // CanSupport tests whether the plugin supports a given persistent volume // specification from the API. CanSupport(pv *v1.PersistentVolume) bool + // CanSupportInline tests whether the plugin supports a given inline volume + // specification from the API. + CanSupportInline(vol *v1.Volume) bool + // GetInTreePluginName returns the in-tree plugin name this migrates GetInTreePluginName() string 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 de283453a4..0573ebc052 100644 --- a/vendor/k8s.io/csi-translation-lib/plugins/openstack_cinder.go +++ b/vendor/k8s.io/csi-translation-lib/plugins/openstack_cinder.go @@ -45,6 +45,31 @@ func (t *osCinderCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.Sto return sc, nil } +// TranslateInTreeInlineVolumeToCSI takes a Volume with Cinder set from in-tree +// and converts the Cinder source to a CSIPersistentVolumeSource +func (t *osCinderCSITranslator) TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume, error) { + if volume == nil || volume.Cinder == nil { + return nil, fmt.Errorf("volume is nil or Cinder not defined on volume") + } + + cinderSource := volume.Cinder + pv := &v1.PersistentVolume{ + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: CinderDriverName, + VolumeHandle: cinderSource.VolumeID, + ReadOnly: cinderSource.ReadOnly, + FSType: cinderSource.FSType, + VolumeAttributes: map[string]string{}, + }, + }, + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteOnce}, + }, + } + return pv, nil +} + // TranslateInTreePVToCSI takes a PV with Cinder set from in-tree // and converts the Cinder source to a CSIPersistentVolumeSource func (t *osCinderCSITranslator) TranslateInTreePVToCSI(pv *v1.PersistentVolume) (*v1.PersistentVolume, error) { @@ -87,13 +112,20 @@ func (t *osCinderCSITranslator) TranslateCSIPVToInTree(pv *v1.PersistentVolume) return pv, nil } -// CanSupport tests whether the plugin supports a given volume +// CanSupport tests whether the plugin supports a given persistent volume // specification from the API. The spec pointer should be considered // const. func (t *osCinderCSITranslator) CanSupport(pv *v1.PersistentVolume) bool { return pv != nil && pv.Spec.Cinder != nil } +// CanSupportInline tests whether the plugin supports a given inline volume +// specification from the API. The spec pointer should be considered +// const. +func (t *osCinderCSITranslator) CanSupportInline(volume *v1.Volume) bool { + return volume != nil && volume.Cinder != nil +} + // GetInTreePluginName returns the name of the intree plugin driver func (t *osCinderCSITranslator) GetInTreePluginName() string { return CinderInTreePluginName diff --git a/vendor/k8s.io/csi-translation-lib/translate.go b/vendor/k8s.io/csi-translation-lib/translate.go index a13ac422df..46ae1cbbfd 100644 --- a/vendor/k8s.io/csi-translation-lib/translate.go +++ b/vendor/k8s.io/csi-translation-lib/translate.go @@ -27,9 +27,11 @@ import ( var ( inTreePlugins = map[string]plugins.InTreePlugin{ - plugins.GCEPDDriverName: plugins.NewGCEPersistentDiskCSITranslator(), - plugins.AWSEBSDriverName: plugins.NewAWSElasticBlockStoreCSITranslator(), - plugins.CinderDriverName: plugins.NewOpenStackCinderCSITranslator(), + plugins.GCEPDDriverName: plugins.NewGCEPersistentDiskCSITranslator(), + plugins.AWSEBSDriverName: plugins.NewAWSElasticBlockStoreCSITranslator(), + plugins.CinderDriverName: plugins.NewOpenStackCinderCSITranslator(), + plugins.AzureDiskDriverName: plugins.NewAzureDiskCSITranslator(), + plugins.AzureFileDriverName: plugins.NewAzureFileCSITranslator(), } ) @@ -45,6 +47,21 @@ func TranslateInTreeStorageClassToCSI(inTreePluginName string, sc *storage.Stora return nil, fmt.Errorf("could not find in-tree storage class parameter translation logic for %#v", inTreePluginName) } +// TranslateInTreeInlineVolumeToCSI takes a inline volume and will translate +// the in-tree volume source to a CSIPersistentVolumeSource (wrapped in a PV) +// if the translation logic has been implemented. +func TranslateInTreeInlineVolumeToCSI(volume *v1.Volume) (*v1.PersistentVolume, error) { + if volume == nil { + return nil, fmt.Errorf("persistent volume was nil") + } + for _, curPlugin := range inTreePlugins { + if curPlugin.CanSupportInline(volume) { + return curPlugin.TranslateInTreeInlineVolumeToCSI(volume) + } + } + return nil, fmt.Errorf("could not find in-tree plugin translation logic for %#v", volume.Name) +} + // TranslateInTreePVToCSI takes a persistent volume and will translate // the in-tree source to a CSI Source if the translation logic // has been implemented. The input persistent volume will not @@ -147,5 +164,10 @@ func IsPVMigratable(pv *v1.PersistentVolume) bool { // IsInlineMigratable tests whether there is Migration logic for the given Inline Volume func IsInlineMigratable(vol *v1.Volume) bool { + for _, curPlugin := range inTreePlugins { + if curPlugin.CanSupportInline(vol) { + return true + } + } return false }