From cb547f4b5c31b81af70489b97a0f1dba167bafb0 Mon Sep 17 00:00:00 2001 From: markturansky Date: Fri, 29 May 2015 16:32:44 -0400 Subject: [PATCH] RecyclableVolumePlugin interfaces --- pkg/volume/plugins.go | 39 +++++++++++++++++++++++++++++++++++++-- pkg/volume/testing.go | 18 ++++++++++++++++++ pkg/volume/volume.go | 12 ++++++++++-- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/pkg/volume/plugins.go b/pkg/volume/plugins.go index 54a5f68a891..d94807fd891 100644 --- a/pkg/volume/plugins.go +++ b/pkg/volume/plugins.go @@ -79,6 +79,15 @@ type PersistentVolumePlugin interface { GetAccessModes() []api.PersistentVolumeAccessMode } +// RecyclableVolumePlugin is an extended interface of VolumePlugin and is used +// by persistent volumes that want to be recycled before being made available again to new claims +type RecyclableVolumePlugin interface { + VolumePlugin + // NewRecycler creates a new volume.Recycler which knows how to reclaim this resource + // after the volume's release from a PersistentVolumeClaim + NewRecycler(spec *Spec) (Recycler, error) +} + // VolumeHost is an interface that plugins can use to access the kubelet. type VolumeHost interface { // GetPluginDir returns the absolute path to a directory under which @@ -217,7 +226,20 @@ func (pm *VolumePluginMgr) FindPluginByName(name string) (VolumePlugin, error) { return pm.plugins[matches[0]], nil } -// FindPluginByName fetches a plugin by name or by legacy name. If no plugin +// FindPersistentPluginBySpec looks for a persistent volume plugin that can support a given volume +// specification. If no plugin is found, return an error +func (pm *VolumePluginMgr) FindPersistentPluginBySpec(spec *Spec) (PersistentVolumePlugin, error) { + volumePlugin, err := pm.FindPluginBySpec(spec) + if err != nil { + return nil, fmt.Errorf("Could not find volume plugin for spec: %+v", spec) + } + if persistentVolumePlugin, ok := volumePlugin.(PersistentVolumePlugin); ok { + return persistentVolumePlugin, nil + } + return nil, fmt.Errorf("no persistent volume plugin matched") +} + +// FindPersistentPluginByName fetches a persistent volume plugin by name. If no plugin // is found, returns error. func (pm *VolumePluginMgr) FindPersistentPluginByName(name string) (PersistentVolumePlugin, error) { volumePlugin, err := pm.FindPluginByName(name) @@ -227,5 +249,18 @@ func (pm *VolumePluginMgr) FindPersistentPluginByName(name string) (PersistentVo if persistentVolumePlugin, ok := volumePlugin.(PersistentVolumePlugin); ok { return persistentVolumePlugin, nil } - return nil, fmt.Errorf("no persistent volume plugin matched") + return nil, fmt.Errorf("no persistent volume plugin matched: %+v") +} + +// FindRecyclablePluginByName fetches a persistent volume plugin by name. If no plugin +// is found, returns error. +func (pm *VolumePluginMgr) FindRecyclablePluginBySpec(spec *Spec) (RecyclableVolumePlugin, error) { + volumePlugin, err := pm.FindPluginBySpec(spec) + if err != nil { + return nil, err + } + if recyclableVolumePlugin, ok := volumePlugin.(RecyclableVolumePlugin); ok { + return recyclableVolumePlugin, nil + } + return nil, fmt.Errorf("no recyclable volume plugin matched") } diff --git a/pkg/volume/testing.go b/pkg/volume/testing.go index 6502b326cfc..3ac6d9736e9 100644 --- a/pkg/volume/testing.go +++ b/pkg/volume/testing.go @@ -82,6 +82,7 @@ type FakeVolumePlugin struct { } var _ VolumePlugin = &FakeVolumePlugin{} +var _ RecyclableVolumePlugin = &FakeVolumePlugin{} func (plugin *FakeVolumePlugin) Init(host VolumeHost) { plugin.Host = host @@ -104,6 +105,10 @@ func (plugin *FakeVolumePlugin) NewCleaner(volName string, podUID types.UID, mou return &FakeVolume{podUID, volName, plugin}, nil } +func (plugin *FakeVolumePlugin) NewRecycler(spec *Spec) (Recycler, error) { + return &FakeRecycler{"/attributesTransferredFromSpec"}, nil +} + func (plugin *FakeVolumePlugin) GetAccessModes() []api.PersistentVolumeAccessMode { return []api.PersistentVolumeAccessMode{} } @@ -133,3 +138,16 @@ func (fv *FakeVolume) TearDown() error { func (fv *FakeVolume) TearDownAt(dir string) error { return os.RemoveAll(dir) } + +type FakeRecycler struct { + path string +} + +func (fr *FakeRecycler) Recycle() error { + // nil is success, else error + return nil +} + +func (fr *FakeRecycler) GetPath() string { + return fr.path +} diff --git a/pkg/volume/volume.go b/pkg/volume/volume.go index e1af5f699fd..ee668400a87 100644 --- a/pkg/volume/volume.go +++ b/pkg/volume/volume.go @@ -29,7 +29,7 @@ type Volume interface { GetPath() string } -// Builder interface provides method to set up/mount the volume. +// Builder interface provides methods to set up/mount the volume. type Builder interface { // Uses Interface to provide the path for Docker binds. Volume @@ -43,7 +43,7 @@ type Builder interface { SetUpAt(dir string) error } -// Cleaner interface provides method to cleanup/unmount the volumes. +// Cleaner interface provides methods to cleanup/unmount the volumes. type Cleaner interface { Volume // TearDown unmounts the volume from a self-determined directory and @@ -54,6 +54,14 @@ type Cleaner interface { TearDownAt(dir string) error } +// Recycler provides methods to reclaim the volume resource. +type Recycler interface { + Volume + // Recycle reclaims the resource. Calls to this method should block until the recycling task is complete. + // Any error returned indicates the volume has failed to be reclaimed. A nil return indicates success. + Recycle() error +} + func RenameDirectory(oldPath, newName string) (string, error) { newPath, err := ioutil.TempDir(path.Dir(oldPath), newName) if err != nil {