Add GetAccessModes to volume plugin interface

This commit is contained in:
markturansky 2015-03-12 15:37:02 -04:00
parent ed68c8e82b
commit 111f3d5120
12 changed files with 216 additions and 1 deletions

View File

@ -195,6 +195,32 @@ type VolumeSource struct {
NFS *NFSVolumeSource `json:"nfs"`
}
// PersistentVolumeSource is similar to VolumeSource but meant for the administrator who creates PVs.
// Exactly one of its members must be set.
type PersistentVolumeSource struct {
// GCEPersistentDisk represents a GCE Disk resource that is attached to a
// kubelet's host machine and then exposed to the pod.
GCEPersistentDisk *GCEPersistentDiskVolumeSource `json:"persistentDisk"`
// HostPath represents a directory on the host.
// This is useful for development and testing only.
// on-host storage is not supported in any way
HostPath *HostPathVolumeSource `json:"hostPath"`
// NFS represents an NFS mount on the host that shares a pod's lifetime
NFS *NFSVolumeSource `json:"nfs"`
}
// used by VolumeSources to describe their mounting/access modes
type AccessModeType string
const (
// can be mounted read/write mode to exactly 1 host
ReadWriteOnce AccessModeType = "ReadWriteOnce"
// can be mounted in read-only mode to many hosts
ReadOnlyMany AccessModeType = "ReadOnlyMany"
// can be mounted in read/write mode to many hosts
ReadWriteMany AccessModeType = "ReadWriteMany"
)
// HostPathVolumeSource represents a host directory mapped into a pod.
type HostPathVolumeSource struct {
Path string `json:"path"`

View File

@ -109,6 +109,32 @@ type VolumeSource struct {
NFS *NFSVolumeSource `json:"nfs" description:"NFS volume that will be mounted in the host machine "`
}
// PersistentVolumeSource is similar to VolumeSource but meant for the administrator who creates PVs.
// Exactly one of its members must be set.
type PersistentVolumeSource struct {
// GCEPersistentDisk represents a GCE Disk resource that is attached to a
// kubelet's host machine and then exposed to the pod.
GCEPersistentDisk *GCEPersistentDiskVolumeSource `json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"`
// HostPath represents a directory on the host.
// This is useful for development and testing only.
// on-host storage is not supported in any way
HostPath *HostPathVolumeSource `json:"hostPath" description:"Persistent hostPath volume useful for development and testing"`
// NFS represents an NFS mount on the host that shares a pod's lifetime
NFS *NFSVolumeSource `json:"nfs" description:"Persistent NFS volume that will be mounted in the host machine"`
}
// used by VolumeSources to describe their mounting/access modes
type AccessModeType string
const (
// can be mounted read/write mode to exactly 1 host
ReadWriteOnce AccessModeType = "ReadWriteOnce"
// can be mounted in read-only mode to many hosts
ReadOnlyMany AccessModeType = "ReadOnlyMany"
// can be mounted in read/write mode to many hosts
ReadWriteMany AccessModeType = "ReadWriteMany"
)
// HostPathVolumeSource represents bare host directory volume.
type HostPathVolumeSource struct {
Path string `json:"path" description:"path of the directory on the host"`

View File

@ -82,6 +82,32 @@ type VolumeSource struct {
NFS *NFSVolumeSource `json:"nfs" description:"NFS volume that will be mounted in the host machine"`
}
// PersistentVolumeSource is similar to VolumeSource but meant for the administrator who creates PVs.
// Exactly one of its members must be set.
type PersistentVolumeSource struct {
// GCEPersistentDisk represents a GCE Disk resource that is attached to a
// kubelet's host machine and then exposed to the pod.
GCEPersistentDisk *GCEPersistentDiskVolumeSource `json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"`
// HostPath represents a directory on the host.
// This is useful for development and testing only.
// on-host storage is not supported in any way
HostPath *HostPathVolumeSource `json:"hostPath" description:"Persistent hostPath volume useful for development and testing"`
// NFS represents an NFS mount on the host that shares a pod's lifetime
NFS *NFSVolumeSource `json:"nfs" description:"Persistent NFS volume that will be mounted in the host machine"`
}
// used by VolumeSources to describe their mounting/access modes
type AccessModeType string
const (
// can be mounted read/write mode to exactly 1 host
ReadWriteOnce AccessModeType = "ReadWriteOnce"
// can be mounted in read-only mode to many hosts
ReadOnlyMany AccessModeType = "ReadOnlyMany"
// can be mounted in read/write mode to many hosts
ReadWriteMany AccessModeType = "ReadWriteMany"
)
// HostPathVolumeSource represents bare host directory volume.
//
// https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/volumes.md#hostdir

View File

@ -214,6 +214,32 @@ type VolumeSource struct {
NFS *NFSVolumeSource `json:"nfs" description:"NFS volume that will be mounted in the host machine"`
}
// PersistentVolumeSource is similar to VolumeSource but meant for the administrator who creates PVs.
// Exactly one of its members must be set.
type PersistentVolumeSource struct {
// GCEPersistentDisk represents a GCE Disk resource that is attached to a
// kubelet's host machine and then exposed to the pod.
GCEPersistentDisk *GCEPersistentDiskVolumeSource `json:"persistentDisk" description:"GCE disk resource attached to the host machine on demand"`
// HostPath represents a directory on the host.
// This is useful for development and testing only.
// on-host storage is not supported in any way
HostPath *HostPathVolumeSource `json:"hostPath" description:"Persistent hostPath volume useful for development and testing"`
// NFS represents an NFS mount on the host that shares a pod's lifetime
NFS *NFSVolumeSource `json:"nfs" description:"Persistent NFS volume that will be mounted in the host machine"`
}
// used by VolumeSources to describe their mounting/access modes
type AccessModeType string
const (
// can be mounted read/write mode to exactly 1 host
ReadWriteOnce AccessModeType = "ReadWriteOnce"
// can be mounted in read-only mode to many hosts
ReadOnlyMany AccessModeType = "ReadOnlyMany"
// can be mounted in read/write mode to many hosts
ReadWriteMany AccessModeType = "ReadWriteMany"
)
// HostPathVolumeSource represents bare host directory volume.
type HostPathVolumeSource struct {
Path string `json:"path" description:"path of the directory on the host"`

View File

@ -71,6 +71,13 @@ func (plugin *gcePersistentDiskPlugin) CanSupport(spec *api.Volume) bool {
return false
}
func (plugin *gcePersistentDiskPlugin) GetAccessModes() []api.AccessModeType {
return []api.AccessModeType{
api.ReadWriteOnce,
api.ReadOnlyMany,
}
}
func (plugin *gcePersistentDiskPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference) (volume.Builder, error) {
// Inject real implementations here, test through the internal function.
return plugin.newBuilderInternal(spec, podRef.UID, &GCEDiskUtil{}, mount.New())

View File

@ -42,6 +42,28 @@ func TestCanSupport(t *testing.T) {
}
}
func TestGetAccessModes(t *testing.T) {
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("/tmp/fake", nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/gce-pd")
if err != nil {
t.Errorf("Can't find the plugin by name")
}
if !contains(plug.GetAccessModes(), api.ReadWriteOnce) || !contains(plug.GetAccessModes(), api.ReadOnlyMany) {
t.Errorf("Expected two AccessModeTypes: %s and %s", api.ReadWriteOnce, api.ReadOnlyMany)
}
}
func contains(modes []api.AccessModeType, mode api.AccessModeType) bool {
for _, m := range modes {
if m == mode {
return true
}
}
return false
}
type fakePDManager struct{}
// TODO(jonesdl) To fully test this, we could create a loopback device

View File

@ -54,6 +54,12 @@ func (plugin *hostPathPlugin) CanSupport(spec *api.Volume) bool {
return false
}
func (plugin *hostPathPlugin) GetAccessModes() []api.AccessModeType {
return []api.AccessModeType{
api.ReadWriteOnce,
}
}
func (plugin *hostPathPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference) (volume.Builder, error) {
return &hostPath{spec.HostPath.Path}, nil
}

View File

@ -43,6 +43,19 @@ func TestCanSupport(t *testing.T) {
}
}
func TestGetAccessModes(t *testing.T) {
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("/tmp/fake", nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/host-path")
if err != nil {
t.Errorf("Can't find the plugin by name")
}
if len(plug.GetAccessModes()) != 1 || plug.GetAccessModes()[0] != api.ReadWriteOnce {
t.Errorf("Expected %s AccessModeType", api.ReadWriteOnce)
}
}
func TestPlugin(t *testing.T) {
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("fake", nil, nil))

View File

@ -57,6 +57,14 @@ func (plugin *nfsPlugin) CanSupport(spec *api.Volume) bool {
return false
}
func (plugin *nfsPlugin) GetAccessModes() []api.AccessModeType {
return []api.AccessModeType{
api.ReadWriteOnce,
api.ReadOnlyMany,
api.ReadWriteMany,
}
}
func (plugin *nfsPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference) (volume.Builder, error) {
return plugin.newBuilderInternal(spec, podRef, plugin.mounter)
}

View File

@ -45,6 +45,28 @@ func TestCanSupport(t *testing.T) {
}
}
func TestGetAccessModes(t *testing.T) {
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("/tmp/fake", nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/nfs")
if err != nil {
t.Errorf("Can't find the plugin by name")
}
if !contains(plug.GetAccessModes(), api.ReadWriteOnce) || !contains(plug.GetAccessModes(), api.ReadOnlyMany) || !contains(plug.GetAccessModes(), api.ReadWriteMany) {
t.Errorf("Expected three AccessModeTypes: %s, %s, and %s", api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany)
}
}
func contains(modes []api.AccessModeType, mode api.AccessModeType) bool {
for _, m := range modes {
if m == mode {
return true
}
}
return false
}
type fakeNFSMounter struct {
FakeMounter mount.FakeMounter
}

View File

@ -59,6 +59,14 @@ type VolumePlugin interface {
NewCleaner(name string, podUID types.UID) (Cleaner, error)
}
// PersistentVolumePlugin is an extended interface of VolumePlugin and is used
// by volumes that want to provide long term persistence of data
type PersistentVolumePlugin interface {
VolumePlugin
// GetAccessModes describes the ways a given volume can be accessed/mounted.
GetAccessModes() []api.AccessModeType
}
// 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
@ -173,3 +181,24 @@ func (pm *VolumePluginMgr) FindPluginByName(name string) (VolumePlugin, error) {
}
return pm.plugins[matches[0]], nil
}
// FindPersistentPluginBySpec looks for a plugin that can support a given volume
// specification. If no plugins can support or more than one plugin can
// support it, return error.
func (pm *VolumePluginMgr) FindPersistentPluginBySpec(spec *api.Volume) (PersistentVolumePlugin, error) {
volumePlugin, err := pm.FindPluginBySpec(spec)
if err != nil {
return nil, err
}
return volumePlugin.(PersistentVolumePlugin), nil
}
// FindPluginByName fetches a plugin by name or by legacy name. If no plugin
// is found, returns error.
func (pm *VolumePluginMgr) FindPersistentPluginByName(name string) (PersistentVolumePlugin, error) {
volumePlugin, err := pm.FindPluginByName(name)
if err != nil {
return nil, err
}
return volumePlugin.(PersistentVolumePlugin), nil
}

View File

@ -71,7 +71,7 @@ func (f *fakeVolumeHost) NewWrapperCleaner(spec *api.Volume, podUID types.UID) (
return plug.NewCleaner(spec.Name, podUID)
}
// FakeVolumePlugin is useful for for testing. It tries to be a fully compliant
// FakeVolumePlugin is useful for testing. It tries to be a fully compliant
// plugin, but all it does is make empty directories.
// Use as:
// volume.RegisterPlugin(&FakePlugin{"fake-name"})
@ -103,6 +103,10 @@ func (plugin *FakeVolumePlugin) NewCleaner(volName string, podUID types.UID) (Cl
return &FakeVolume{podUID, volName, plugin}, nil
}
func (plugin *FakeVolumePlugin) GetAccessModes() []api.AccessModeType {
return []api.AccessModeType{}
}
type FakeVolume struct {
PodUID types.UID
VolName string