mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 07:20:13 +00:00
Populate InlineVolumeSpec in CSI attacher and translation library
Signed-off-by: Deep Debroy <ddebroy@docker.com>
This commit is contained in:
parent
df196226c4
commit
de7be9d613
@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user