Refactor ConstructVolumeSpec

Return a struct from ConstructVolumeSpec to be able to add more fields to
it later.
This commit is contained in:
Jan Safranek 2022-10-19 14:52:08 +02:00
parent 2dc8cc13a4
commit fc245b339b
35 changed files with 202 additions and 141 deletions

View File

@ -424,7 +424,7 @@ func (plugin *TestPlugin) NewUnmounter(name string, podUID types.UID) (volume.Un
return nil, nil return nil, nil
} }
func (plugin *TestPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *TestPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
fakeVolume := &v1.Volume{ fakeVolume := &v1.Volume{
Name: volumeName, Name: volumeName,
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -435,7 +435,9 @@ func (plugin *TestPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*vo
}, },
}, },
} }
return volume.NewSpecFromVolume(fakeVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(fakeVolume),
}, nil
} }
func (plugin *TestPlugin) NewAttacher() (volume.Attacher, error) { func (plugin *TestPlugin) NewAttacher() (volume.Attacher, error) {

View File

@ -967,8 +967,8 @@ func (plugin *mockVolumePlugin) SupportsBulkVolumeVerification() bool {
return false return false
} }
func (plugin *mockVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *mockVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
return nil, nil return volume.ReconstructedVolume{}, nil
} }
func (plugin *mockVolumePlugin) SupportsSELinuxContextMount(spec *volume.Spec) (bool, error) { func (plugin *mockVolumePlugin) SupportsSELinuxContextMount(spec *volume.Spec) (bool, error) {

View File

@ -1,9 +1,12 @@
/* /*
Copyright 2022 The Kubernetes Authors. Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -136,7 +139,7 @@ func (rc *reconciler) reconstructVolume(volume podVolume) (*reconstructedVolume,
return nil, fmt.Errorf("could not find block volume plugin %q (spec.Name: %q) pod %q (UID: %q)", volume.pluginName, volume.volumeSpecName, volume.podName, pod.UID) return nil, fmt.Errorf("could not find block volume plugin %q (spec.Name: %q) pod %q (UID: %q)", volume.pluginName, volume.volumeSpecName, volume.podName, pod.UID)
} }
volumeSpec, err := rc.operationExecutor.ReconstructVolumeOperation( reconstructed, err := rc.operationExecutor.ReconstructVolumeOperation(
volume.volumeMode, volume.volumeMode,
plugin, plugin,
mapperPlugin, mapperPlugin,
@ -148,6 +151,7 @@ func (rc *reconciler) reconstructVolume(volume podVolume) (*reconstructedVolume,
if err != nil { if err != nil {
return nil, err return nil, err
} }
volumeSpec := reconstructed.Spec
// We have to find the plugins by volume spec (NOT by plugin name) here // We have to find the plugins by volume spec (NOT by plugin name) here
// in order to correctly reconstruct ephemeral volume types. // in order to correctly reconstruct ephemeral volume types.

View File

@ -1,9 +1,12 @@
/* /*
Copyright 2022 The Kubernetes Authors. Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -249,25 +249,27 @@ func getVolumeSource(
return nil, false, fmt.Errorf("Spec does not reference an AWS EBS volume type") return nil, false, fmt.Errorf("Spec does not reference an AWS EBS volume type")
} }
func (plugin *awsElasticBlockStorePlugin) ConstructVolumeSpec(volName, mountPath string) (*volume.Spec, error) { func (plugin *awsElasticBlockStorePlugin) ConstructVolumeSpec(volName, mountPath string) (volume.ReconstructedVolume, error) {
mounter := plugin.host.GetMounter(plugin.GetPluginName()) mounter := plugin.host.GetMounter(plugin.GetPluginName())
kvh, ok := plugin.host.(volume.KubeletVolumeHost) kvh, ok := plugin.host.(volume.KubeletVolumeHost)
if !ok { if !ok {
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface") return volume.ReconstructedVolume{}, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
} }
hu := kvh.GetHostUtil() hu := kvh.GetHostUtil()
pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName()) pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName())
volumeID, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir) volumeID, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
volumeID, err = formatVolumeID(volumeID) volumeID, err = formatVolumeID(volumeID)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get AWS volume id from mount path %q: %v", mountPath, err) return volume.ReconstructedVolume{}, fmt.Errorf("failed to get AWS volume id from mount path %q: %v", mountPath, err)
} }
file := v1.PersistentVolumeFilesystem file := v1.PersistentVolumeFilesystem
return newAWSVolumeSpec(volName, volumeID, file), nil return volume.ReconstructedVolume{
Spec: newAWSVolumeSpec(volName, volumeID, file),
}, nil
} }
func (plugin *awsElasticBlockStorePlugin) RequiresFSResize() bool { func (plugin *awsElasticBlockStorePlugin) RequiresFSResize() bool {

View File

@ -202,7 +202,7 @@ func (plugin *azureFilePlugin) ExpandVolumeDevice(
return newSize, nil return newSize, nil
} }
func (plugin *azureFilePlugin) ConstructVolumeSpec(volName, mountPath string) (*volume.Spec, error) { func (plugin *azureFilePlugin) ConstructVolumeSpec(volName, mountPath string) (volume.ReconstructedVolume, error) {
azureVolume := &v1.Volume{ azureVolume := &v1.Volume{
Name: volName, Name: volName,
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -212,7 +212,9 @@ func (plugin *azureFilePlugin) ConstructVolumeSpec(volName, mountPath string) (*
}, },
}, },
} }
return volume.NewSpecFromVolume(azureVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(azureVolume),
}, nil
} }
// azureFile volumes represent mount of an AzureFile share. // azureFile volumes represent mount of an AzureFile share.

View File

@ -316,18 +316,18 @@ func (plugin *azureDataDiskPlugin) NodeExpand(resizeOptions volume.NodeResizeOpt
var _ volume.NodeExpandableVolumePlugin = &azureDataDiskPlugin{} var _ volume.NodeExpandableVolumePlugin = &azureDataDiskPlugin{}
func (plugin *azureDataDiskPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *azureDataDiskPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
mounter := plugin.host.GetMounter(plugin.GetPluginName()) mounter := plugin.host.GetMounter(plugin.GetPluginName())
kvh, ok := plugin.host.(volume.KubeletVolumeHost) kvh, ok := plugin.host.(volume.KubeletVolumeHost)
if !ok { if !ok {
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface") return volume.ReconstructedVolume{}, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
} }
hu := kvh.GetHostUtil() hu := kvh.GetHostUtil()
pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName()) pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName())
sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir) sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
azureVolume := &v1.Volume{ azureVolume := &v1.Volume{
@ -338,7 +338,9 @@ func (plugin *azureDataDiskPlugin) ConstructVolumeSpec(volumeName, mountPath str
}, },
}, },
} }
return volume.NewSpecFromVolume(azureVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(azureVolume),
}, nil
} }
func (plugin *azureDataDiskPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) { func (plugin *azureDataDiskPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {

View File

@ -173,7 +173,7 @@ func (plugin *cephfsPlugin) newUnmounterInternal(volName string, podUID types.UI
}, nil }, nil
} }
func (plugin *cephfsPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *cephfsPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
cephfsVolume := &v1.Volume{ cephfsVolume := &v1.Volume{
Name: volumeName, Name: volumeName,
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -183,7 +183,9 @@ func (plugin *cephfsPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*
}, },
}, },
} }
return volume.NewSpecFromVolume(cephfsVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(cephfsVolume),
}, nil
} }
// CephFS volumes represent a bare host file or directory mount of an CephFS export. // CephFS volumes represent a bare host file or directory mount of an CephFS export.

View File

@ -128,13 +128,13 @@ func TestConstructVolumeSpec(t *testing.T) {
t.Errorf("can't find cephfs plugin by name") t.Errorf("can't find cephfs plugin by name")
} }
cephfsSpec, err := plug.(*cephfsPlugin).ConstructVolumeSpec("cephfsVolume", "/cephfsVolume/") cephfsVol, err := plug.(*cephfsPlugin).ConstructVolumeSpec("cephfsVolume", "/cephfsVolume/")
if err != nil { if err != nil {
t.Errorf("ConstructVolumeSpec() failed: %v", err) t.Errorf("ConstructVolumeSpec() failed: %v", err)
} }
if cephfsSpec.Name() != "cephfsVolume" { if cephfsVol.Spec.Name() != "cephfsVolume" {
t.Errorf("Get wrong cephfs spec name, got: %s", cephfsSpec.Name()) t.Errorf("Get wrong cephfs spec name, got: %s", cephfsVol.Spec.Name())
} }
} }

View File

@ -122,14 +122,16 @@ func (plugin *configMapPlugin) NewUnmounter(volName string, podUID types.UID) (v
}, nil }, nil
} }
func (plugin *configMapPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *configMapPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
configMapVolume := &v1.Volume{ configMapVolume := &v1.Volume{
Name: volumeName, Name: volumeName,
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
ConfigMap: &v1.ConfigMapVolumeSource{}, ConfigMap: &v1.ConfigMapVolumeSource{},
}, },
} }
return volume.NewSpecFromVolume(configMapVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(configMapVolume),
}, nil
} }
type configMapVolume struct { type configMapVolume struct {

View File

@ -448,12 +448,12 @@ func (p *csiPlugin) NewUnmounter(specName string, podUID types.UID) (volume.Unmo
return unmounter, nil return unmounter, nil
} }
func (p *csiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (p *csiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
klog.V(4).Info(log("plugin.ConstructVolumeSpec [pv.Name=%v, path=%v]", volumeName, mountPath)) klog.V(4).Info(log("plugin.ConstructVolumeSpec [pv.Name=%v, path=%v]", volumeName, mountPath))
volData, err := loadVolumeData(mountPath, volDataFileName) volData, err := loadVolumeData(mountPath, volDataFileName)
if err != nil { if err != nil {
return nil, errors.New(log("plugin.ConstructVolumeSpec failed loading volume data using [%s]: %v", mountPath, err)) return volume.ReconstructedVolume{}, errors.New(log("plugin.ConstructVolumeSpec failed loading volume data using [%s]: %v", mountPath, err))
} }
klog.V(4).Info(log("plugin.ConstructVolumeSpec extracted [%#v]", volData)) klog.V(4).Info(log("plugin.ConstructVolumeSpec extracted [%#v]", volData))
@ -464,11 +464,13 @@ func (p *csiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.S
// use constructPVSourceSpec to construct volume construct pv source spec. // use constructPVSourceSpec to construct volume construct pv source spec.
if storage.VolumeLifecycleMode(volData[volDataKey.volumeLifecycleMode]) == storage.VolumeLifecycleEphemeral { if storage.VolumeLifecycleMode(volData[volDataKey.volumeLifecycleMode]) == storage.VolumeLifecycleEphemeral {
spec = p.constructVolSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName]) spec = p.constructVolSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName])
return spec, nil return volume.ReconstructedVolume{Spec: spec}, nil
} }
spec = p.constructPVSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName], volData[volDataKey.volHandle])
return spec, nil spec = p.constructPVSourceSpec(volData[volDataKey.specVolID], volData[volDataKey.driverName], volData[volDataKey.volHandle])
return volume.ReconstructedVolume{
Spec: spec,
}, nil
} }
// constructVolSourceSpec constructs volume.Spec with CSIVolumeSource // constructVolSourceSpec constructs volume.Spec with CSIVolumeSource

View File

@ -362,38 +362,38 @@ func TestPluginConstructVolumeSpec(t *testing.T) {
} }
// rebuild spec // rebuild spec
spec, err := plug.ConstructVolumeSpec("test-pv", filepath.Dir(csiMounter.GetPath())) rec, err := plug.ConstructVolumeSpec("test-pv", filepath.Dir(csiMounter.GetPath()))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if spec == nil { if rec.Spec == nil {
t.Fatal("nil volume.Spec constructed") t.Fatal("nil volume.Spec constructed")
} }
// inspect spec // inspect spec
if spec.PersistentVolume == nil || spec.PersistentVolume.Spec.CSI == nil { if rec.Spec.PersistentVolume == nil || rec.Spec.PersistentVolume.Spec.CSI == nil {
t.Fatal("CSIPersistentVolume not found in constructed spec ") t.Fatal("CSIPersistentVolume not found in constructed spec ")
} }
volHandle := spec.PersistentVolume.Spec.CSI.VolumeHandle volHandle := rec.Spec.PersistentVolume.Spec.CSI.VolumeHandle
if volHandle != tc.originSpec.PersistentVolume.Spec.CSI.VolumeHandle { if volHandle != tc.originSpec.PersistentVolume.Spec.CSI.VolumeHandle {
t.Error("unexpected volumeHandle constructed:", volHandle) t.Error("unexpected volumeHandle constructed:", volHandle)
} }
driverName := spec.PersistentVolume.Spec.CSI.Driver driverName := rec.Spec.PersistentVolume.Spec.CSI.Driver
if driverName != tc.originSpec.PersistentVolume.Spec.CSI.Driver { if driverName != tc.originSpec.PersistentVolume.Spec.CSI.Driver {
t.Error("unexpected driverName constructed:", driverName) t.Error("unexpected driverName constructed:", driverName)
} }
if spec.PersistentVolume.Spec.VolumeMode == nil { if rec.Spec.PersistentVolume.Spec.VolumeMode == nil {
t.Fatalf("Volume mode has not been set.") t.Fatalf("Volume mode has not been set.")
} }
if *spec.PersistentVolume.Spec.VolumeMode != api.PersistentVolumeFilesystem { if *rec.Spec.PersistentVolume.Spec.VolumeMode != api.PersistentVolumeFilesystem {
t.Errorf("Unexpected volume mode %q", *spec.PersistentVolume.Spec.VolumeMode) t.Errorf("Unexpected volume mode %q", *rec.Spec.PersistentVolume.Spec.VolumeMode)
} }
if spec.Name() != tc.specVolID { if rec.Spec.Name() != tc.specVolID {
t.Errorf("Unexpected spec name constructed %s", spec.Name()) t.Errorf("Unexpected spec name constructed %s", rec.Spec.Name())
} }
}) })
} }
@ -496,44 +496,44 @@ func TestPluginConstructVolumeSpecWithInline(t *testing.T) {
} }
// rebuild spec // rebuild spec
spec, err := plug.ConstructVolumeSpec("test-pv", filepath.Dir(csiMounter.GetPath())) rec, err := plug.ConstructVolumeSpec("test-pv", filepath.Dir(csiMounter.GetPath()))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if spec == nil { if rec.Spec == nil {
t.Fatal("nil volume.Spec constructed") t.Fatal("nil volume.Spec constructed")
} }
if spec.Name() != tc.specVolID { if rec.Spec.Name() != tc.specVolID {
t.Errorf("unexpected spec name constructed volume.Spec: %s", spec.Name()) t.Errorf("unexpected spec name constructed volume.Spec: %s", rec.Spec.Name())
} }
switch { switch {
case spec.Volume != nil: case rec.Spec.Volume != nil:
if spec.Volume.CSI == nil { if rec.Spec.Volume.CSI == nil {
t.Error("missing CSIVolumeSource in constructed volume.Spec") t.Error("missing CSIVolumeSource in constructed volume.Spec")
} }
if spec.Volume.CSI.Driver != tc.originSpec.Volume.CSI.Driver { if rec.Spec.Volume.CSI.Driver != tc.originSpec.Volume.CSI.Driver {
t.Error("unexpected driver in constructed volume source:", spec.Volume.CSI.Driver) t.Error("unexpected driver in constructed volume source:", rec.Spec.Volume.CSI.Driver)
} }
case spec.PersistentVolume != nil: case rec.Spec.PersistentVolume != nil:
if spec.PersistentVolume.Spec.CSI == nil { if rec.Spec.PersistentVolume.Spec.CSI == nil {
t.Fatal("missing CSIPersistentVolumeSource in constructed volume.spec") t.Fatal("missing CSIPersistentVolumeSource in constructed volume.spec")
} }
volHandle := spec.PersistentVolume.Spec.CSI.VolumeHandle volHandle := rec.Spec.PersistentVolume.Spec.CSI.VolumeHandle
if volHandle != tc.originSpec.PersistentVolume.Spec.CSI.VolumeHandle { if volHandle != tc.originSpec.PersistentVolume.Spec.CSI.VolumeHandle {
t.Error("unexpected volumeHandle constructed in persistent volume source:", volHandle) t.Error("unexpected volumeHandle constructed in persistent volume source:", volHandle)
} }
driverName := spec.PersistentVolume.Spec.CSI.Driver driverName := rec.Spec.PersistentVolume.Spec.CSI.Driver
if driverName != tc.originSpec.PersistentVolume.Spec.CSI.Driver { if driverName != tc.originSpec.PersistentVolume.Spec.CSI.Driver {
t.Error("unexpected driverName constructed in persistent volume source:", driverName) t.Error("unexpected driverName constructed in persistent volume source:", driverName)
} }
if spec.PersistentVolume.Spec.VolumeMode == nil { if rec.Spec.PersistentVolume.Spec.VolumeMode == nil {
t.Fatalf("Volume mode has not been set.") t.Fatalf("Volume mode has not been set.")
} }
if *spec.PersistentVolume.Spec.VolumeMode != api.PersistentVolumeFilesystem { if *rec.Spec.PersistentVolume.Spec.VolumeMode != api.PersistentVolumeFilesystem {
t.Errorf("Unexpected volume mode %q", *spec.PersistentVolume.Spec.VolumeMode) t.Errorf("Unexpected volume mode %q", *rec.Spec.PersistentVolume.Spec.VolumeMode)
} }
default: default:
t.Fatal("invalid volume.Spec constructed") t.Fatal("invalid volume.Spec constructed")

View File

@ -443,14 +443,14 @@ func TestCSI_VolumeAll(t *testing.T) {
// ******** Volume Reconstruction ************* // // ******** Volume Reconstruction ************* //
volPath := filepath.Dir(csiMounter.GetPath()) volPath := filepath.Dir(csiMounter.GetPath())
t.Log("csiTest.VolumeAll entering plugin.ConstructVolumeSpec for path", volPath) t.Log("csiTest.VolumeAll entering plugin.ConstructVolumeSpec for path", volPath)
spec, err := volPlug.ConstructVolumeSpec(test.volName, volPath) rec, err := volPlug.ConstructVolumeSpec(test.volName, volPath)
if err != nil { if err != nil {
t.Fatalf("csiTest.VolumeAll plugin.ConstructVolumeSpec failed: %s", err) t.Fatalf("csiTest.VolumeAll plugin.ConstructVolumeSpec failed: %s", err)
} else { } else {
if spec == nil { if rec.Spec == nil {
t.Fatalf("csiTest.VolumeAll plugin.ConstructVolumeSpec returned nil spec") t.Fatalf("csiTest.VolumeAll plugin.ConstructVolumeSpec returned nil spec")
} else { } else {
volSpec = spec volSpec = rec.Spec
if test.isInline { if test.isInline {
if volSpec.Volume == nil || volSpec.Volume.CSI == nil { if volSpec.Volume == nil || volSpec.Volume.CSI == nil {

View File

@ -123,14 +123,16 @@ func (plugin *downwardAPIPlugin) NewUnmounter(volName string, podUID types.UID)
}, nil }, nil
} }
func (plugin *downwardAPIPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *downwardAPIPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
downwardAPIVolume := &v1.Volume{ downwardAPIVolume := &v1.Volume{
Name: volumeName, Name: volumeName,
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
DownwardAPI: &v1.DownwardAPIVolumeSource{}, DownwardAPI: &v1.DownwardAPIVolumeSource{},
}, },
} }
return volume.NewSpecFromVolume(downwardAPIVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(downwardAPIVolume),
}, nil
} }
// downwardAPIVolume retrieves downward API data and placing them into the volume on the host. // downwardAPIVolume retrieves downward API data and placing them into the volume on the host.

View File

@ -188,14 +188,16 @@ func (plugin *emptyDirPlugin) newUnmounterInternal(volName string, podUID types.
return ed, nil return ed, nil
} }
func (plugin *emptyDirPlugin) ConstructVolumeSpec(volName, mountPath string) (*volume.Spec, error) { func (plugin *emptyDirPlugin) ConstructVolumeSpec(volName, mountPath string) (volume.ReconstructedVolume, error) {
emptyDirVolume := &v1.Volume{ emptyDirVolume := &v1.Volume{
Name: volName, Name: volName,
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
EmptyDir: &v1.EmptyDirVolumeSource{}, EmptyDir: &v1.EmptyDirVolumeSource{},
}, },
} }
return volume.NewSpecFromVolume(emptyDirVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(emptyDirVolume),
}, nil
} }
// mountDetector abstracts how to find what kind of mount a path is backed by. // mountDetector abstracts how to find what kind of mount a path is backed by.

View File

@ -240,7 +240,7 @@ func (plugin *fcPlugin) newUnmapperInternal(volName string, podUID types.UID, ma
}, nil }, nil
} }
func (plugin *fcPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *fcPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
// Find globalPDPath from pod volume directory(mountPath) // Find globalPDPath from pod volume directory(mountPath)
// examples: // examples:
// mountPath: pods/{podUid}/volumes/kubernetes.io~fc/{volumeName} // mountPath: pods/{podUid}/volumes/kubernetes.io~fc/{volumeName}
@ -256,10 +256,10 @@ func (plugin *fcPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volu
if io.IsInconsistentReadError(err) { if io.IsInconsistentReadError(err) {
klog.Errorf("Failed to read mount refs from /proc/mounts for %s: %s", mountPath, err) klog.Errorf("Failed to read mount refs from /proc/mounts for %s: %s", mountPath, err)
klog.Errorf("Kubelet cannot unmount volume at %s, please unmount it manually", mountPath) klog.Errorf("Kubelet cannot unmount volume at %s, please unmount it manually", mountPath)
return nil, err return volume.ReconstructedVolume{}, err
} }
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
for _, path := range paths { for _, path := range paths {
if strings.Contains(path, plugin.host.GetPluginDir(fcPluginName)) { if strings.Contains(path, plugin.host.GetPluginDir(fcPluginName)) {
@ -269,12 +269,12 @@ func (plugin *fcPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volu
} }
// Couldn't fetch globalPDPath // Couldn't fetch globalPDPath
if len(globalPDPath) == 0 { if len(globalPDPath) == 0 {
return nil, fmt.Errorf("couldn't fetch globalPDPath. failed to obtain volume spec") return volume.ReconstructedVolume{}, fmt.Errorf("couldn't fetch globalPDPath. failed to obtain volume spec")
} }
wwns, lun, wwids, err := parsePDName(globalPDPath) wwns, lun, wwids, err := parsePDName(globalPDPath)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to retrieve volume plugin information from globalPDPath: %s", err) return volume.ReconstructedVolume{}, fmt.Errorf("failed to retrieve volume plugin information from globalPDPath: %s", err)
} }
// Create volume from wwn+lun or wwid // Create volume from wwn+lun or wwid
fcVolume := &v1.Volume{ fcVolume := &v1.Volume{
@ -285,7 +285,9 @@ func (plugin *fcPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volu
} }
klog.V(5).Infof("ConstructVolumeSpec: TargetWWNs: %v, Lun: %v, WWIDs: %v", klog.V(5).Infof("ConstructVolumeSpec: TargetWWNs: %v, Lun: %v, WWIDs: %v",
fcVolume.VolumeSource.FC.TargetWWNs, *fcVolume.VolumeSource.FC.Lun, fcVolume.VolumeSource.FC.WWIDs) fcVolume.VolumeSource.FC.TargetWWNs, *fcVolume.VolumeSource.FC.Lun, fcVolume.VolumeSource.FC.WWIDs)
return volume.NewSpecFromVolume(fcVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(fcVolume),
}, nil
} }
// ConstructBlockVolumeSpec creates a new volume.Spec with following steps. // ConstructBlockVolumeSpec creates a new volume.Spec with following steps.

View File

@ -260,7 +260,7 @@ func (plugin *flexVolumeAttachablePlugin) CanDeviceMount(spec *volume.Spec) (boo
} }
// ConstructVolumeSpec is part of the volume.AttachableVolumePlugin interface. // ConstructVolumeSpec is part of the volume.AttachableVolumePlugin interface.
func (plugin *flexVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *flexVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
flexVolume := &api.Volume{ flexVolume := &api.Volume{
Name: volumeName, Name: volumeName,
VolumeSource: api.VolumeSource{ VolumeSource: api.VolumeSource{
@ -269,7 +269,9 @@ func (plugin *flexVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string
}, },
}, },
} }
return volume.NewSpecFromVolume(flexVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(flexVolume),
}, nil
} }
func (plugin *flexVolumePlugin) SupportsMountOption() bool { func (plugin *flexVolumePlugin) SupportsMountOption() bool {

View File

@ -299,17 +299,17 @@ func (plugin *gcePersistentDiskPlugin) NodeExpand(resizeOptions volume.NodeResiz
var _ volume.NodeExpandableVolumePlugin = &gcePersistentDiskPlugin{} var _ volume.NodeExpandableVolumePlugin = &gcePersistentDiskPlugin{}
func (plugin *gcePersistentDiskPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *gcePersistentDiskPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
mounter := plugin.host.GetMounter(plugin.GetPluginName()) mounter := plugin.host.GetMounter(plugin.GetPluginName())
kvh, ok := plugin.host.(volume.KubeletVolumeHost) kvh, ok := plugin.host.(volume.KubeletVolumeHost)
if !ok { if !ok {
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface") return volume.ReconstructedVolume{}, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
} }
hu := kvh.GetHostUtil() hu := kvh.GetHostUtil()
pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName()) pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName())
sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir) sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
gceVolume := &v1.Volume{ gceVolume := &v1.Volume{
Name: volumeName, Name: volumeName,
@ -319,7 +319,9 @@ func (plugin *gcePersistentDiskPlugin) ConstructVolumeSpec(volumeName, mountPath
}, },
}, },
} }
return volume.NewSpecFromVolume(gceVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(gceVolume),
}, nil
} }
// Abstract interface to PD operations. // Abstract interface to PD operations.

View File

@ -123,14 +123,16 @@ func (plugin *gitRepoPlugin) NewUnmounter(volName string, podUID types.UID) (vol
}, nil }, nil
} }
func (plugin *gitRepoPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *gitRepoPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
gitVolume := &v1.Volume{ gitVolume := &v1.Volume{
Name: volumeName, Name: volumeName,
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
GitRepo: &v1.GitRepoVolumeSource{}, GitRepo: &v1.GitRepoVolumeSource{},
}, },
} }
return volume.NewSpecFromVolume(gitVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(gitVolume),
}, nil
} }
// gitRepo volumes are directories which are pre-filled from a git repository. // gitRepo volumes are directories which are pre-filled from a git repository.

View File

@ -181,7 +181,7 @@ func (plugin *hostPathPlugin) NewProvisioner(options volume.VolumeOptions) (volu
return newProvisioner(options, plugin.host, plugin) return newProvisioner(options, plugin.host, plugin)
} }
func (plugin *hostPathPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *hostPathPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
hostPathVolume := &v1.Volume{ hostPathVolume := &v1.Volume{
Name: volumeName, Name: volumeName,
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -190,7 +190,9 @@ func (plugin *hostPathPlugin) ConstructVolumeSpec(volumeName, mountPath string)
}, },
}, },
} }
return volume.NewSpecFromVolume(hostPathVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(hostPathVolume),
}, nil
} }
func newDeleter(spec *volume.Spec, host volume.VolumeHost) (volume.Deleter, error) { func newDeleter(spec *volume.Spec, host volume.VolumeHost) (volume.Deleter, error) {

View File

@ -221,7 +221,7 @@ func (plugin *iscsiPlugin) newUnmapperInternal(volName string, podUID types.UID,
}, nil }, nil
} }
func (plugin *iscsiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *iscsiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
// Find globalPDPath from pod volume directory(mountPath) // Find globalPDPath from pod volume directory(mountPath)
var globalPDPath string var globalPDPath string
mounter := plugin.host.GetMounter(plugin.GetPluginName()) mounter := plugin.host.GetMounter(plugin.GetPluginName())
@ -233,10 +233,10 @@ func (plugin *iscsiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*v
if io.IsInconsistentReadError(err) { if io.IsInconsistentReadError(err) {
klog.Errorf("Failed to read mount refs from /proc/mounts for %s: %s", mountPath, err) klog.Errorf("Failed to read mount refs from /proc/mounts for %s: %s", mountPath, err)
klog.Errorf("Kubelet cannot unmount volume at %s, please unmount it and all mounts of the same device manually.", mountPath) klog.Errorf("Kubelet cannot unmount volume at %s, please unmount it and all mounts of the same device manually.", mountPath)
return nil, err return volume.ReconstructedVolume{}, err
} }
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
for _, path := range paths { for _, path := range paths {
@ -247,25 +247,25 @@ func (plugin *iscsiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*v
} }
// Couldn't fetch globalPDPath // Couldn't fetch globalPDPath
if len(globalPDPath) == 0 { if len(globalPDPath) == 0 {
return nil, fmt.Errorf("couldn't fetch globalPDPath. failed to obtain volume spec") return volume.ReconstructedVolume{}, fmt.Errorf("couldn't fetch globalPDPath. failed to obtain volume spec")
} }
// Obtain iscsi disk configurations from globalPDPath // Obtain iscsi disk configurations from globalPDPath
device, _, err := extractDeviceAndPrefix(globalPDPath) device, _, err := extractDeviceAndPrefix(globalPDPath)
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
bkpPortal, iqn, err := extractPortalAndIqn(device) bkpPortal, iqn, err := extractPortalAndIqn(device)
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
arr := strings.Split(device, "-lun-") arr := strings.Split(device, "-lun-")
if len(arr) < 2 { if len(arr) < 2 {
return nil, fmt.Errorf("failed to retrieve lun from globalPDPath: %v", globalPDPath) return volume.ReconstructedVolume{}, fmt.Errorf("failed to retrieve lun from globalPDPath: %v", globalPDPath)
} }
lun, err := strconv.Atoi(arr[1]) lun, err := strconv.Atoi(arr[1])
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
iface, _ := extractIface(globalPDPath) iface, _ := extractIface(globalPDPath)
iscsiVolume := &v1.Volume{ iscsiVolume := &v1.Volume{
@ -279,7 +279,9 @@ func (plugin *iscsiPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*v
}, },
}, },
} }
return volume.NewSpecFromVolume(iscsiVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(iscsiVolume),
}, nil
} }
func (plugin *iscsiPlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, mapPath string) (*volume.Spec, error) { func (plugin *iscsiPlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, mapPath string) (*volume.Spec, error) {

View File

@ -197,7 +197,7 @@ func (plugin *localVolumePlugin) NewBlockVolumeUnmapper(volName string,
} }
// TODO: check if no path and no topology constraints are ok // TODO: check if no path and no topology constraints are ok
func (plugin *localVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *localVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
fs := v1.PersistentVolumeFilesystem fs := v1.PersistentVolumeFilesystem
// The main purpose of reconstructed volume is to clean unused mount points // The main purpose of reconstructed volume is to clean unused mount points
// and directories. // and directories.
@ -209,7 +209,7 @@ func (plugin *localVolumePlugin) ConstructVolumeSpec(volumeName, mountPath strin
mounter := plugin.host.GetMounter(plugin.GetPluginName()) mounter := plugin.host.GetMounter(plugin.GetPluginName())
refs, err := mounter.GetMountRefs(mountPath) refs, err := mounter.GetMountRefs(mountPath)
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
baseMountPath := plugin.generateBlockDeviceBaseGlobalPath() baseMountPath := plugin.generateBlockDeviceBaseGlobalPath()
for _, ref := range refs { for _, ref := range refs {
@ -221,7 +221,7 @@ func (plugin *localVolumePlugin) ConstructVolumeSpec(volumeName, mountPath strin
// source and can be used in reconstructed volume. // source and can be used in reconstructed volume.
path, _, err = mount.GetDeviceNameFromMount(mounter, ref) path, _, err = mount.GetDeviceNameFromMount(mounter, ref)
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
klog.V(4).Infof("local: reconstructing volume %q (pod volume mount: %q) with device %q", volumeName, mountPath, path) klog.V(4).Infof("local: reconstructing volume %q (pod volume mount: %q) with device %q", volumeName, mountPath, path)
break break
@ -240,7 +240,9 @@ func (plugin *localVolumePlugin) ConstructVolumeSpec(volumeName, mountPath strin
VolumeMode: &fs, VolumeMode: &fs,
}, },
} }
return volume.NewSpecFromPersistentVolume(localVolume, false), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromPersistentVolume(localVolume, false),
}, nil
} }
func (plugin *localVolumePlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, func (plugin *localVolumePlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName,

View File

@ -543,34 +543,34 @@ func TestConstructVolumeSpec(t *testing.T) {
} }
mounter.(*mount.FakeMounter).MountPoints = fakeMountPoints mounter.(*mount.FakeMounter).MountPoints = fakeMountPoints
volPath := filepath.Join(tmpDir, testMountPath) volPath := filepath.Join(tmpDir, testMountPath)
spec, err := plug.ConstructVolumeSpec(testPVName, volPath) rec, err := plug.ConstructVolumeSpec(testPVName, volPath)
if err != nil { if err != nil {
t.Errorf("ConstructVolumeSpec() failed: %v", err) t.Errorf("ConstructVolumeSpec() failed: %v", err)
} }
if spec == nil { if rec.Spec == nil {
t.Fatalf("ConstructVolumeSpec() returned nil") t.Fatalf("ConstructVolumeSpec() returned nil")
} }
volName := spec.Name() volName := rec.Spec.Name()
if volName != testPVName { if volName != testPVName {
t.Errorf("Expected volume name %q, got %q", testPVName, volName) t.Errorf("Expected volume name %q, got %q", testPVName, volName)
} }
if spec.Volume != nil { if rec.Spec.Volume != nil {
t.Errorf("Volume object returned, expected nil") t.Errorf("Volume object returned, expected nil")
} }
pv := spec.PersistentVolume pv := rec.Spec.PersistentVolume
if pv == nil { if pv == nil {
t.Fatalf("PersistentVolume object nil") t.Fatalf("PersistentVolume object nil")
} }
if spec.PersistentVolume.Spec.VolumeMode == nil { if rec.Spec.PersistentVolume.Spec.VolumeMode == nil {
t.Fatalf("Volume mode has not been set.") t.Fatalf("Volume mode has not been set.")
} }
if *spec.PersistentVolume.Spec.VolumeMode != v1.PersistentVolumeFilesystem { if *rec.Spec.PersistentVolume.Spec.VolumeMode != v1.PersistentVolumeFilesystem {
t.Errorf("Unexpected volume mode %q", *spec.PersistentVolume.Spec.VolumeMode) t.Errorf("Unexpected volume mode %q", *rec.Spec.PersistentVolume.Spec.VolumeMode)
} }
ls := pv.Spec.PersistentVolumeSource.Local ls := pv.Spec.PersistentVolumeSource.Local

View File

@ -176,7 +176,7 @@ func (plugin *nfsPlugin) Recycle(pvName string, spec *volume.Spec, eventRecorder
return recyclerclient.RecycleVolumeByWatchingPodUntilCompletion(pvName, pod, plugin.host.GetKubeClient(), eventRecorder) return recyclerclient.RecycleVolumeByWatchingPodUntilCompletion(pvName, pod, plugin.host.GetKubeClient(), eventRecorder)
} }
func (plugin *nfsPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *nfsPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
nfsVolume := &v1.Volume{ nfsVolume := &v1.Volume{
Name: volumeName, Name: volumeName,
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -185,7 +185,9 @@ func (plugin *nfsPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*vol
}, },
}, },
} }
return volume.NewSpecFromVolume(nfsVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(nfsVolume),
}, nil
} }
// NFS volumes represent a bare host file or directory mount of an NFS export. // NFS volumes represent a bare host file or directory mount of an NFS export.

View File

@ -60,8 +60,8 @@ func (n *noopExpandableVolumePluginInstance) NewUnmounter(name string, podUID ty
return nil, nil return nil, nil
} }
func (n *noopExpandableVolumePluginInstance) ConstructVolumeSpec(volumeName, mountPath string) (*Spec, error) { func (n *noopExpandableVolumePluginInstance) ConstructVolumeSpec(volumeName, mountPath string) (ReconstructedVolume, error) {
return n.spec, nil return ReconstructedVolume{Spec: n.spec}, nil
} }
func (n *noopExpandableVolumePluginInstance) SupportsMountOption() bool { func (n *noopExpandableVolumePluginInstance) SupportsMountOption() bool {

View File

@ -166,7 +166,7 @@ type VolumePlugin interface {
// and volumePath. The spec may have incomplete information due to limited // and volumePath. The spec may have incomplete information due to limited
// information from input. This function is used by volume manager to reconstruct // information from input. This function is used by volume manager to reconstruct
// volume spec by reading the volume directories from disk // volume spec by reading the volume directories from disk
ConstructVolumeSpec(volumeName, volumePath string) (*Spec, error) ConstructVolumeSpec(volumeName, volumePath string) (ReconstructedVolume, error)
// SupportsMountOption returns true if volume plugins supports Mount options // SupportsMountOption returns true if volume plugins supports Mount options
// Specifying mount options in a volume plugin that doesn't support // Specifying mount options in a volume plugin that doesn't support
@ -570,6 +570,12 @@ type VolumeConfig struct {
ProvisioningEnabled bool ProvisioningEnabled bool
} }
// ReconstructedVolume contains information about a volume reconstructed by
// ConstructVolumeSpec().
type ReconstructedVolume struct {
Spec *Spec
}
// NewSpecFromVolume creates an Spec from an v1.Volume // NewSpecFromVolume creates an Spec from an v1.Volume
func NewSpecFromVolume(vs *v1.Volume) *Spec { func NewSpecFromVolume(vs *v1.Volume) *Spec {
return &Spec{ return &Spec{

View File

@ -99,8 +99,8 @@ func (plugin *testPlugins) NewUnmounter(name string, podUID types.UID) (Unmounte
return nil, nil return nil, nil
} }
func (plugin *testPlugins) ConstructVolumeSpec(volumeName, mountPath string) (*Spec, error) { func (plugin *testPlugins) ConstructVolumeSpec(volumeName, mountPath string) (ReconstructedVolume, error) {
return nil, nil return ReconstructedVolume{}, nil
} }
func newTestPlugin() []VolumePlugin { func newTestPlugin() []VolumePlugin {

View File

@ -210,7 +210,7 @@ func (plugin *portworxVolumePlugin) ExpandVolumeDevice(
return newSize, nil return newSize, nil
} }
func (plugin *portworxVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *portworxVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
portworxVolume := &v1.Volume{ portworxVolume := &v1.Volume{
Name: volumeName, Name: volumeName,
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -219,7 +219,9 @@ func (plugin *portworxVolumePlugin) ConstructVolumeSpec(volumeName, mountPath st
}, },
}, },
} }
return volume.NewSpecFromVolume(portworxVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(portworxVolume),
}, nil
} }
func (plugin *portworxVolumePlugin) SupportsMountOption() bool { func (plugin *portworxVolumePlugin) SupportsMountOption() bool {

View File

@ -135,7 +135,7 @@ func (plugin *projectedPlugin) NewUnmounter(volName string, podUID types.UID) (v
}, nil }, nil
} }
func (plugin *projectedPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *projectedPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
projectedVolume := &v1.Volume{ projectedVolume := &v1.Volume{
Name: volumeName, Name: volumeName,
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -143,7 +143,9 @@ func (plugin *projectedPlugin) ConstructVolumeSpec(volumeName, mountPath string)
}, },
} }
return volume.NewSpecFromVolume(projectedVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(projectedVolume),
}, nil
} }
type projectedVolume struct { type projectedVolume struct {

View File

@ -386,17 +386,17 @@ func (plugin *rbdPlugin) newUnmounterInternal(volName string, podUID types.UID,
}, nil }, nil
} }
func (plugin *rbdPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *rbdPlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
mounter := plugin.host.GetMounter(plugin.GetPluginName()) mounter := plugin.host.GetMounter(plugin.GetPluginName())
kvh, ok := plugin.host.(volume.KubeletVolumeHost) kvh, ok := plugin.host.(volume.KubeletVolumeHost)
if !ok { if !ok {
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface") return volume.ReconstructedVolume{}, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
} }
hu := kvh.GetHostUtil() hu := kvh.GetHostUtil()
pluginMntDir := volutil.GetPluginMountDir(plugin.host, plugin.GetPluginName()) pluginMntDir := volutil.GetPluginMountDir(plugin.host, plugin.GetPluginName())
sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir) sourceName, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
s := dstrings.Split(sourceName, "-image-") s := dstrings.Split(sourceName, "-image-")
if len(s) != 2 { if len(s) != 2 {
@ -414,11 +414,11 @@ func (plugin *rbdPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*vol
klog.V(3).Infof("SourceName %s wrong, fallback to old format", sourceName) klog.V(3).Infof("SourceName %s wrong, fallback to old format", sourceName)
sourceName, err = plugin.getDeviceNameFromOldMountPath(mounter, mountPath) sourceName, err = plugin.getDeviceNameFromOldMountPath(mounter, mountPath)
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
s = dstrings.Split(sourceName, "-image-") s = dstrings.Split(sourceName, "-image-")
if len(s) != 2 { if len(s) != 2 {
return nil, fmt.Errorf("sourceName %s wrong, should be pool+\"-image-\"+imageName", sourceName) return volume.ReconstructedVolume{}, fmt.Errorf("sourceName %s wrong, should be pool+\"-image-\"+imageName", sourceName)
} }
} }
rbdVolume := &v1.Volume{ rbdVolume := &v1.Volume{
@ -430,7 +430,9 @@ func (plugin *rbdPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*vol
}, },
}, },
} }
return volume.NewSpecFromVolume(rbdVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(rbdVolume),
}, nil
} }
func (plugin *rbdPlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, mapPath string) (*volume.Spec, error) { func (plugin *rbdPlugin) ConstructBlockVolumeSpec(podUID types.UID, volumeName, mapPath string) (*volume.Spec, error) {

View File

@ -631,15 +631,15 @@ func TestConstructVolumeSpec(t *testing.T) {
if err = fakeMounter.Mount(c.targetPath, podMountPath, "fake", []string{"bind"}); err != nil { if err = fakeMounter.Mount(c.targetPath, podMountPath, "fake", []string{"bind"}); err != nil {
t.Fatalf("Mount %s to %s failed: %v", c.targetPath, podMountPath, err) t.Fatalf("Mount %s to %s failed: %v", c.targetPath, podMountPath, err)
} }
spec, err := plug.ConstructVolumeSpec(c.volumeName, podMountPath) rec, err := plug.ConstructVolumeSpec(c.volumeName, podMountPath)
if err != nil { if err != nil {
t.Errorf("ConstructVolumeSpec failed: %v", err) t.Errorf("ConstructVolumeSpec failed: %v", err)
} else { } else {
if spec.Volume.RBD.RBDPool != pool { if rec.Spec.Volume.RBD.RBDPool != pool {
t.Errorf("Mismatch rbd pool: wanted %s, got %s", pool, spec.Volume.RBD.RBDPool) t.Errorf("Mismatch rbd pool: wanted %s, got %s", pool, rec.Spec.Volume.RBD.RBDPool)
} }
if spec.Volume.RBD.RBDImage != image { if rec.Spec.Volume.RBD.RBDImage != image {
t.Fatalf("Mismatch rbd image: wanted %s, got %s", image, spec.Volume.RBD.RBDImage) t.Fatalf("Mismatch rbd image: wanted %s, got %s", image, rec.Spec.Volume.RBD.RBDImage)
} }
} }
if err = fakeMounter.Unmount(podMountPath); err != nil { if err = fakeMounter.Unmount(podMountPath); err != nil {

View File

@ -125,7 +125,7 @@ func (plugin *secretPlugin) NewUnmounter(volName string, podUID types.UID) (volu
}, nil }, nil
} }
func (plugin *secretPlugin) ConstructVolumeSpec(volName, mountPath string) (*volume.Spec, error) { func (plugin *secretPlugin) ConstructVolumeSpec(volName, mountPath string) (volume.ReconstructedVolume, error) {
secretVolume := &v1.Volume{ secretVolume := &v1.Volume{
Name: volName, Name: volName,
VolumeSource: v1.VolumeSource{ VolumeSource: v1.VolumeSource{
@ -134,7 +134,9 @@ func (plugin *secretPlugin) ConstructVolumeSpec(volName, mountPath string) (*vol
}, },
}, },
} }
return volume.NewSpecFromVolume(secretVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(secretVolume),
}, nil
} }
type secretVolume struct { type secretVolume struct {

View File

@ -451,10 +451,12 @@ func (plugin *FakeVolumePlugin) GetAccessModes() []v1.PersistentVolumeAccessMode
return []v1.PersistentVolumeAccessMode{} return []v1.PersistentVolumeAccessMode{}
} }
func (plugin *FakeVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *FakeVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
return &volume.Spec{ return volume.ReconstructedVolume{
Volume: &v1.Volume{ Spec: &volume.Spec{
Name: volumeName, Volume: &v1.Volume{
Name: volumeName,
},
}, },
}, nil }, nil
} }
@ -526,7 +528,7 @@ func (f *FakeBasicVolumePlugin) CanSupport(spec *volume.Spec) bool {
return strings.HasPrefix(spec.Name(), f.GetPluginName()) return strings.HasPrefix(spec.Name(), f.GetPluginName())
} }
func (f *FakeBasicVolumePlugin) ConstructVolumeSpec(ame, mountPath string) (*volume.Spec, error) { func (f *FakeBasicVolumePlugin) ConstructVolumeSpec(ame, mountPath string) (volume.ReconstructedVolume, error) {
return f.Plugin.ConstructVolumeSpec(ame, mountPath) return f.Plugin.ConstructVolumeSpec(ame, mountPath)
} }
@ -647,8 +649,8 @@ func (plugin *FakeFileVolumePlugin) NewUnmounter(name string, podUID types.UID)
return nil, nil return nil, nil
} }
func (plugin *FakeFileVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *FakeFileVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
return nil, nil return volume.ReconstructedVolume{}, nil
} }
func NewFakeFileVolumePlugin() []volume.VolumePlugin { func NewFakeFileVolumePlugin() []volume.VolumePlugin {

View File

@ -150,7 +150,7 @@ type OperationExecutor interface {
// ExpandInUseVolume will resize volume's file system to expected size without unmounting the volume. // ExpandInUseVolume will resize volume's file system to expected size without unmounting the volume.
ExpandInUseVolume(volumeToMount VolumeToMount, actualStateOfWorld ActualStateOfWorldMounterUpdater, currentSize resource.Quantity) error ExpandInUseVolume(volumeToMount VolumeToMount, actualStateOfWorld ActualStateOfWorldMounterUpdater, currentSize resource.Quantity) error
// ReconstructVolumeOperation construct a new volumeSpec and returns it created by plugin // ReconstructVolumeOperation construct a new volumeSpec and returns it created by plugin
ReconstructVolumeOperation(volumeMode v1.PersistentVolumeMode, plugin volume.VolumePlugin, mapperPlugin volume.BlockVolumePlugin, uid types.UID, podName volumetypes.UniquePodName, volumeSpecName string, volumePath string, pluginName string) (*volume.Spec, error) ReconstructVolumeOperation(volumeMode v1.PersistentVolumeMode, plugin volume.VolumePlugin, mapperPlugin volume.BlockVolumePlugin, uid types.UID, podName volumetypes.UniquePodName, volumeSpecName string, volumePath string, pluginName string) (volume.ReconstructedVolume, error)
// CheckVolumeExistenceOperation checks volume existence // CheckVolumeExistenceOperation checks volume existence
CheckVolumeExistenceOperation(volumeSpec *volume.Spec, mountPath, volumeName string, mounter mount.Interface, uniqueVolumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName, podUID types.UID, attachable volume.AttachableVolumePlugin) (bool, error) CheckVolumeExistenceOperation(volumeSpec *volume.Spec, mountPath, volumeName string, mounter mount.Interface, uniqueVolumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName, podUID types.UID, attachable volume.AttachableVolumePlugin) (bool, error)
} }
@ -1061,17 +1061,17 @@ func (oe *operationExecutor) ReconstructVolumeOperation(
podName volumetypes.UniquePodName, podName volumetypes.UniquePodName,
volumeSpecName string, volumeSpecName string,
volumePath string, volumePath string,
pluginName string) (*volume.Spec, error) { pluginName string) (volume.ReconstructedVolume, error) {
// Filesystem Volume case // Filesystem Volume case
if volumeMode == v1.PersistentVolumeFilesystem { if volumeMode == v1.PersistentVolumeFilesystem {
// Create volumeSpec from mount path // Create volumeSpec from mount path
klog.V(5).Infof("Starting operationExecutor.ReconstructVolume for file volume on pod %q", podName) klog.V(5).Infof("Starting operationExecutor.ReconstructVolume for file volume on pod %q", podName)
volumeSpec, err := plugin.ConstructVolumeSpec(volumeSpecName, volumePath) reconstructed, err := plugin.ConstructVolumeSpec(volumeSpecName, volumePath)
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
return volumeSpec, nil return reconstructed, nil
} }
// Block Volume case // Block Volume case
@ -1083,9 +1083,11 @@ func (oe *operationExecutor) ReconstructVolumeOperation(
// ex. volumePath: pods/{podUid}}/{DefaultKubeletVolumeDevicesDirName}/{escapeQualifiedPluginName}/{volumeName} // ex. volumePath: pods/{podUid}}/{DefaultKubeletVolumeDevicesDirName}/{escapeQualifiedPluginName}/{volumeName}
volumeSpec, err := mapperPlugin.ConstructBlockVolumeSpec(uid, volumeSpecName, volumePath) volumeSpec, err := mapperPlugin.ConstructBlockVolumeSpec(uid, volumeSpecName, volumePath)
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
return volumeSpec, nil return volume.ReconstructedVolume{
Spec: volumeSpec,
}, nil
} }
// CheckVolumeExistenceOperation checks mount path directory if volume still exists // CheckVolumeExistenceOperation checks mount path directory if volume still exists

View File

@ -153,17 +153,17 @@ func (plugin *vsphereVolumePlugin) newUnmounterInternal(volName string, podUID t
}}, nil }}, nil
} }
func (plugin *vsphereVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) { func (plugin *vsphereVolumePlugin) ConstructVolumeSpec(volumeName, mountPath string) (volume.ReconstructedVolume, error) {
mounter := plugin.host.GetMounter(plugin.GetPluginName()) mounter := plugin.host.GetMounter(plugin.GetPluginName())
kvh, ok := plugin.host.(volume.KubeletVolumeHost) kvh, ok := plugin.host.(volume.KubeletVolumeHost)
if !ok { if !ok {
return nil, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface") return volume.ReconstructedVolume{}, fmt.Errorf("plugin volume host does not implement KubeletVolumeHost interface")
} }
hu := kvh.GetHostUtil() hu := kvh.GetHostUtil()
pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName()) pluginMntDir := util.GetPluginMountDir(plugin.host, plugin.GetPluginName())
volumePath, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir) volumePath, err := hu.GetDeviceNameFromMount(mounter, mountPath, pluginMntDir)
if err != nil { if err != nil {
return nil, err return volume.ReconstructedVolume{}, err
} }
volumePath = strings.Replace(volumePath, "\\040", " ", -1) volumePath = strings.Replace(volumePath, "\\040", " ", -1)
klog.V(5).Infof("vSphere volume path is %q", volumePath) klog.V(5).Infof("vSphere volume path is %q", volumePath)
@ -175,7 +175,9 @@ func (plugin *vsphereVolumePlugin) ConstructVolumeSpec(volumeName, mountPath str
}, },
}, },
} }
return volume.NewSpecFromVolume(vsphereVolume), nil return volume.ReconstructedVolume{
Spec: volume.NewSpecFromVolume(vsphereVolume),
}, nil
} }
// Abstract interface to disk operations. // Abstract interface to disk operations.