Populate InlineVolumeSpec in CSI attacher and translation library

Signed-off-by: Deep Debroy <ddebroy@docker.com>
This commit is contained in:
Deep Debroy 2019-05-30 09:35:22 +00:00
parent df196226c4
commit de7be9d613
10 changed files with 253 additions and 18 deletions

View File

@ -71,9 +71,27 @@ func (c *csiAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string
}
node := string(nodeName)
pvName := spec.PersistentVolume.GetName()
attachID := getAttachmentName(pvSrc.VolumeHandle, pvSrc.Driver, node)
var vaSrc storage.VolumeAttachmentSource
if spec.InlineVolumeSpecForCSIMigration {
// inline PV scenario - use PV spec to populate VA source.
// The volume spec will be populated by CSI translation API
// for inline volumes. This allows fields required by the CSI
// attacher such as AccessMode and MountOptions (in addition to
// fields in the CSI persistent volume source) to be populated
// as part of CSI translation for inline volumes.
vaSrc = storage.VolumeAttachmentSource{
InlineVolumeSpec: &spec.PersistentVolume.Spec,
}
} else {
// regular PV scenario - use PV name to populate VA source
pvName := spec.PersistentVolume.GetName()
vaSrc = storage.VolumeAttachmentSource{
PersistentVolumeName: &pvName,
}
}
attachment := &storage.VolumeAttachment{
ObjectMeta: meta.ObjectMeta{
Name: attachID,
@ -81,9 +99,7 @@ func (c *csiAttacher) Attach(spec *volume.Spec, nodeName types.NodeName) (string
Spec: storage.VolumeAttachmentSpec{
NodeName: node,
Attacher: pvSrc.Driver,
Source: storage.VolumeAttachmentSource{
PersistentVolumeName: &pvName,
},
Source: vaSrc,
},
}

View File

@ -452,9 +452,10 @@ type VolumePluginMgr struct {
// Spec is an internal representation of a volume. All API volume types translate to Spec.
type Spec struct {
Volume *v1.Volume
PersistentVolume *v1.PersistentVolume
ReadOnly bool
Volume *v1.Volume
PersistentVolume *v1.PersistentVolume
ReadOnly bool
InlineVolumeSpecForCSIMigration bool
}
// Name returns the name of either Volume or PersistentVolume, one of which must not be nil.

View File

@ -1855,19 +1855,28 @@ func nodeUsingCSIPlugin(og *operationGenerator, spec *volume.Spec, nodeName type
}
func translateSpec(spec *volume.Spec) (*volume.Spec, error) {
var csiPV *v1.PersistentVolume
var err error
inlineVolume := false
if spec.PersistentVolume != nil {
// TranslateInTreePVToCSI will create a new PV
csiPV, err := csilib.TranslateInTreePVToCSI(spec.PersistentVolume)
csiPV, err = csilib.TranslateInTreePVToCSI(spec.PersistentVolume)
if err != nil {
return nil, fmt.Errorf("failed to translate in tree pv to CSI: %v", err)
}
return &volume.Spec{
PersistentVolume: csiPV,
ReadOnly: spec.ReadOnly,
}, nil
} else if spec.Volume != nil {
return &volume.Spec{}, goerrors.New("translation is not supported for in-line volumes yet")
// TranslateInTreeInlineVolumeToCSI will create a new PV
csiPV, err = csilib.TranslateInTreeInlineVolumeToCSI(spec.Volume)
if err != nil {
return nil, fmt.Errorf("failed to translate in tree inline volume to CSI: %v", err)
}
inlineVolume = true
} else {
return &volume.Spec{}, goerrors.New("not a valid volume spec")
}
return &volume.Spec{
PersistentVolume: csiPV,
ReadOnly: spec.ReadOnly,
InlineVolumeSpecForCSIMigration: inlineVolume,
}, nil
}

View File

@ -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

View File

@ -58,6 +58,39 @@ func (t *azureDiskCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.St
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) {
@ -137,6 +170,13 @@ 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

View File

@ -53,6 +53,34 @@ func (t *azureFileCSITranslator) TranslateInTreeStorageClassToCSI(sc *storage.St
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) {
@ -126,6 +154,13 @@ 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

View File

@ -157,6 +157,39 @@ func backwardCompatibleAccessModes(ams []v1.PersistentVolumeAccessMode) []v1.Per
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 +274,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

View File

@ -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

View File

@ -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

View File

@ -47,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
@ -149,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
}