Refactored Volume plugins to use InternalVolume instead of API types

pull/6/head
markturansky 2015-04-14 12:29:33 -04:00
parent f7ae442a02
commit e1481fb9c2
22 changed files with 200 additions and 127 deletions

View File

@ -54,7 +54,7 @@ func (vh *volumeHost) GetKubeClient() client.Interface {
return vh.kubelet.kubeClient
}
func (vh *volumeHost) NewWrapperBuilder(spec *api.Volume, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
func (vh *volumeHost) NewWrapperBuilder(spec *volume.Spec, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
b, err := vh.kubelet.newVolumeBuilderFromPlugins(spec, podRef, opts)
if err == nil && b == nil {
return nil, errUnsupportedVolumeType
@ -62,7 +62,7 @@ func (vh *volumeHost) NewWrapperBuilder(spec *api.Volume, podRef *api.ObjectRefe
return b, nil
}
func (vh *volumeHost) NewWrapperCleaner(spec *api.Volume, podUID types.UID) (volume.Cleaner, error) {
func (vh *volumeHost) NewWrapperCleaner(spec *volume.Spec, podUID types.UID) (volume.Cleaner, error) {
plugin, err := vh.kubelet.volumePluginMgr.FindPluginBySpec(spec)
if err != nil {
return nil, err
@ -78,7 +78,7 @@ func (vh *volumeHost) NewWrapperCleaner(spec *api.Volume, podUID types.UID) (vol
return c, nil
}
func (kl *Kubelet) newVolumeBuilderFromPlugins(spec *api.Volume, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
func (kl *Kubelet) newVolumeBuilderFromPlugins(spec *volume.Spec, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
plugin, err := kl.volumePluginMgr.FindPluginBySpec(spec)
if err != nil {
return nil, fmt.Errorf("can't use volume plugins for %s: %v", spew.Sprintf("%#v", *spec), err)
@ -112,7 +112,8 @@ func (kl *Kubelet) mountExternalVolumes(pod *api.Pod) (volumeMap, error) {
}
// Try to use a plugin for this volume.
builder, err := kl.newVolumeBuilderFromPlugins(volSpec, podRef, volume.VolumeOptions{rootContext})
internal := volume.NewSpecFromVolume(volSpec)
builder, err := kl.newVolumeBuilderFromPlugins(internal, podRef, volume.VolumeOptions{rootContext})
if err != nil {
glog.Errorf("Could not create volume builder for pod %s: %v", pod.UID, err)
return nil, err

View File

@ -58,11 +58,8 @@ func (plugin *awsElasticBlockStorePlugin) Name() string {
return awsElasticBlockStorePluginName
}
func (plugin *awsElasticBlockStorePlugin) CanSupport(spec *api.Volume) bool {
if spec.AWSElasticBlockStore != nil {
return true
}
return false
func (plugin *awsElasticBlockStorePlugin) CanSupport(spec *volume.Spec) bool {
return spec.PersistentVolumeSource.AWSElasticBlockStore != nil || spec.VolumeSource.AWSElasticBlockStore != nil
}
func (plugin *awsElasticBlockStorePlugin) GetAccessModes() []api.AccessModeType {
@ -71,19 +68,26 @@ func (plugin *awsElasticBlockStorePlugin) GetAccessModes() []api.AccessModeType
}
}
func (plugin *awsElasticBlockStorePlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference, _ volume.VolumeOptions) (volume.Builder, error) {
func (plugin *awsElasticBlockStorePlugin) NewBuilder(spec *volume.Spec, podRef *api.ObjectReference, _ volume.VolumeOptions) (volume.Builder, error) {
// Inject real implementations here, test through the internal function.
return plugin.newBuilderInternal(spec, podRef.UID, &AWSDiskUtil{}, mount.New())
}
func (plugin *awsElasticBlockStorePlugin) newBuilderInternal(spec *api.Volume, podUID types.UID, manager pdManager, mounter mount.Interface) (volume.Builder, error) {
volumeID := spec.AWSElasticBlockStore.VolumeID
fsType := spec.AWSElasticBlockStore.FSType
partition := ""
if spec.AWSElasticBlockStore.Partition != 0 {
partition = strconv.Itoa(spec.AWSElasticBlockStore.Partition)
func (plugin *awsElasticBlockStorePlugin) newBuilderInternal(spec *volume.Spec, podUID types.UID, manager pdManager, mounter mount.Interface) (volume.Builder, error) {
var ebs *api.AWSElasticBlockStoreVolumeSource
if spec.VolumeSource.AWSElasticBlockStore != nil {
ebs = spec.VolumeSource.AWSElasticBlockStore
} else {
ebs = spec.PersistentVolumeSource.AWSElasticBlockStore
}
readOnly := spec.AWSElasticBlockStore.ReadOnly
volumeID := ebs.VolumeID
fsType := ebs.FSType
partition := ""
if ebs.Partition != 0 {
partition = strconv.Itoa(ebs.Partition)
}
readOnly := ebs.ReadOnly
return &awsElasticBlockStore{
podUID: podUID,

View File

@ -37,7 +37,7 @@ func TestCanSupport(t *testing.T) {
if plug.Name() != "kubernetes.io/aws-ebs" {
t.Errorf("Wrong name: %s", plug.Name())
}
if !plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{AWSElasticBlockStore: &api.AWSElasticBlockStoreVolumeSource{}}}) {
if !plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{AWSElasticBlockStore: &api.AWSElasticBlockStoreVolumeSource{}}}) {
t.Errorf("Expected true")
}
}
@ -106,7 +106,7 @@ func TestPlugin(t *testing.T) {
},
},
}
builder, err := plug.(*awsElasticBlockStorePlugin).newBuilderInternal(spec, types.UID("poduid"), &fakePDManager{}, &mount.FakeMounter{})
builder, err := plug.(*awsElasticBlockStorePlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &fakePDManager{}, &mount.FakeMounter{})
if err != nil {
t.Errorf("Failed to make a new Builder: %v", err)
}

View File

@ -66,34 +66,31 @@ func (plugin *emptyDirPlugin) Name() string {
return emptyDirPluginName
}
func (plugin *emptyDirPlugin) CanSupport(spec *api.Volume) bool {
func (plugin *emptyDirPlugin) CanSupport(spec *volume.Spec) bool {
if plugin.legacyMode {
// Legacy mode instances can be cleaned up but not created anew.
return false
}
if util.AllPtrFieldsNil(&spec.VolumeSource) {
return true
}
if spec.EmptyDir != nil {
if spec.VolumeSource.EmptyDir != nil {
return true
}
return false
}
func (plugin *emptyDirPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
func (plugin *emptyDirPlugin) NewBuilder(spec *volume.Spec, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
// Inject real implementations here, test through the internal function.
return plugin.newBuilderInternal(spec, podRef, plugin.mounter, &realMountDetector{plugin.mounter}, opts)
}
func (plugin *emptyDirPlugin) newBuilderInternal(spec *api.Volume, podRef *api.ObjectReference, mounter mount.Interface, mountDetector mountDetector, opts volume.VolumeOptions) (volume.Builder, error) {
func (plugin *emptyDirPlugin) newBuilderInternal(spec *volume.Spec, podRef *api.ObjectReference, mounter mount.Interface, mountDetector mountDetector, opts volume.VolumeOptions) (volume.Builder, error) {
if plugin.legacyMode {
// Legacy mode instances can be cleaned up but not created anew.
return nil, fmt.Errorf("legacy mode: can not create new instances")
}
medium := api.StorageTypeDefault
if spec.EmptyDir != nil { // Support a non-specified source as EmptyDir.
medium = spec.EmptyDir.Medium
if spec.VolumeSource.EmptyDir != nil { // Support a non-specified source as EmptyDir.
medium = spec.VolumeSource.EmptyDir.Medium
}
return &emptyDir{
podUID: podRef.UID,

View File

@ -48,11 +48,11 @@ func TestCanSupport(t *testing.T) {
if plug.Name() != "kubernetes.io/empty-dir" {
t.Errorf("Wrong name: %s", plug.Name())
}
if !plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}) {
if !plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}) {
t.Errorf("Expected true")
}
if !plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{}}) {
t.Errorf("Expected true")
if plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{}}) {
t.Errorf("Expected false")
}
}
@ -74,7 +74,7 @@ func TestPlugin(t *testing.T) {
}
mounter := mount.FakeMounter{}
mountDetector := fakeMountDetector{}
builder, err := plug.(*emptyDirPlugin).newBuilderInternal(spec, &api.ObjectReference{UID: types.UID("poduid")}, &mounter, &mountDetector, volume.VolumeOptions{""})
builder, err := plug.(*emptyDirPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), &api.ObjectReference{UID: types.UID("poduid")}, &mounter, &mountDetector, volume.VolumeOptions{""})
if err != nil {
t.Errorf("Failed to make a new Builder: %v", err)
}
@ -133,7 +133,7 @@ func TestPluginTmpfs(t *testing.T) {
}
mounter := mount.FakeMounter{}
mountDetector := fakeMountDetector{}
builder, err := plug.(*emptyDirPlugin).newBuilderInternal(spec, &api.ObjectReference{UID: types.UID("poduid")}, &mounter, &mountDetector, volume.VolumeOptions{""})
builder, err := plug.(*emptyDirPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), &api.ObjectReference{UID: types.UID("poduid")}, &mounter, &mountDetector, volume.VolumeOptions{""})
if err != nil {
t.Errorf("Failed to make a new Builder: %v", err)
}
@ -197,7 +197,7 @@ func TestPluginBackCompat(t *testing.T) {
spec := &api.Volume{
Name: "vol1",
}
builder, err := plug.NewBuilder(spec, &api.ObjectReference{UID: types.UID("poduid")}, volume.VolumeOptions{""})
builder, err := plug.NewBuilder(volume.NewSpecFromVolume(spec), &api.ObjectReference{UID: types.UID("poduid")}, volume.VolumeOptions{""})
if err != nil {
t.Errorf("Failed to make a new Builder: %v", err)
}
@ -217,12 +217,12 @@ func TestPluginLegacy(t *testing.T) {
if plug.Name() != "empty" {
t.Errorf("Wrong name: %s", plug.Name())
}
if plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}) {
if plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}) {
t.Errorf("Expected false")
}
spec := api.Volume{VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}
if _, err := plug.(*emptyDirPlugin).newBuilderInternal(&spec, &api.ObjectReference{UID: types.UID("poduid")}, &mount.FakeMounter{}, &fakeMountDetector{}, volume.VolumeOptions{""}); err == nil {
if _, err := plug.(*emptyDirPlugin).newBuilderInternal(volume.NewSpecFromVolume(&spec), &api.ObjectReference{UID: types.UID("poduid")}, &mount.FakeMounter{}, &fakeMountDetector{}, volume.VolumeOptions{""}); err == nil {
t.Errorf("Expected failiure")
}

View File

@ -59,16 +59,13 @@ func (plugin *gcePersistentDiskPlugin) Name() string {
return gcePersistentDiskPluginName
}
func (plugin *gcePersistentDiskPlugin) CanSupport(spec *api.Volume) bool {
func (plugin *gcePersistentDiskPlugin) CanSupport(spec *volume.Spec) bool {
if plugin.legacyMode {
// Legacy mode instances can be cleaned up but not created anew.
return false
}
if spec.GCEPersistentDisk != nil {
return true
}
return false
return spec.VolumeSource.GCEPersistentDisk != nil || spec.PersistentVolumeSource.GCEPersistentDisk != nil
}
func (plugin *gcePersistentDiskPlugin) GetAccessModes() []api.AccessModeType {
@ -78,24 +75,31 @@ func (plugin *gcePersistentDiskPlugin) GetAccessModes() []api.AccessModeType {
}
}
func (plugin *gcePersistentDiskPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference, _ volume.VolumeOptions) (volume.Builder, error) {
func (plugin *gcePersistentDiskPlugin) NewBuilder(spec *volume.Spec, podRef *api.ObjectReference, _ volume.VolumeOptions) (volume.Builder, error) {
// Inject real implementations here, test through the internal function.
return plugin.newBuilderInternal(spec, podRef.UID, &GCEDiskUtil{}, mount.New())
}
func (plugin *gcePersistentDiskPlugin) newBuilderInternal(spec *api.Volume, podUID types.UID, manager pdManager, mounter mount.Interface) (volume.Builder, error) {
func (plugin *gcePersistentDiskPlugin) newBuilderInternal(spec *volume.Spec, podUID types.UID, manager pdManager, mounter mount.Interface) (volume.Builder, error) {
if plugin.legacyMode {
// Legacy mode instances can be cleaned up but not created anew.
return nil, fmt.Errorf("legacy mode: can not create new instances")
}
pdName := spec.GCEPersistentDisk.PDName
fsType := spec.GCEPersistentDisk.FSType
partition := ""
if spec.GCEPersistentDisk.Partition != 0 {
partition = strconv.Itoa(spec.GCEPersistentDisk.Partition)
var gce *api.GCEPersistentDiskVolumeSource
if spec.VolumeSource.GCEPersistentDisk != nil {
gce = spec.VolumeSource.GCEPersistentDisk
} else {
gce = spec.PersistentVolumeSource.GCEPersistentDisk
}
readOnly := spec.GCEPersistentDisk.ReadOnly
pdName := gce.PDName
fsType := gce.FSType
partition := ""
if gce.Partition != 0 {
partition = strconv.Itoa(gce.Partition)
}
readOnly := gce.ReadOnly
return &gcePersistentDisk{
podUID: podUID,

View File

@ -37,7 +37,7 @@ func TestCanSupport(t *testing.T) {
if plug.Name() != "kubernetes.io/gce-pd" {
t.Errorf("Wrong name: %s", plug.Name())
}
if !plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}}}) {
if !plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}}}) {
t.Errorf("Expected true")
}
}
@ -113,7 +113,7 @@ func TestPlugin(t *testing.T) {
}
fakeManager := &fakePDManager{}
fakeMounter := &mount.FakeMounter{}
builder, err := plug.(*gcePersistentDiskPlugin).newBuilderInternal(spec, types.UID("poduid"), fakeManager, fakeMounter)
builder, err := plug.(*gcePersistentDiskPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), fakeManager, fakeMounter)
if err != nil {
t.Errorf("Failed to make a new Builder: %v", err)
}
@ -181,11 +181,12 @@ func TestPluginLegacy(t *testing.T) {
if plug.Name() != "gce-pd" {
t.Errorf("Wrong name: %s", plug.Name())
}
if plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}}}) {
if plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}}}) {
t.Errorf("Expected false")
}
if _, err := plug.NewBuilder(&api.Volume{VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}}}, &api.ObjectReference{UID: types.UID("poduid")}, volume.VolumeOptions{""}); err == nil {
spec := &api.Volume{VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{}}}
if _, err := plug.NewBuilder(volume.NewSpecFromVolume(spec), &api.ObjectReference{UID: types.UID("poduid")}, volume.VolumeOptions{""}); err == nil {
t.Errorf("Expected failiure")
}

View File

@ -58,19 +58,16 @@ func (plugin *gitRepoPlugin) Name() string {
return gitRepoPluginName
}
func (plugin *gitRepoPlugin) CanSupport(spec *api.Volume) bool {
func (plugin *gitRepoPlugin) CanSupport(spec *volume.Spec) bool {
if plugin.legacyMode {
// Legacy mode instances can be cleaned up but not created anew.
return false
}
if spec.GitRepo != nil {
return true
}
return false
return spec.VolumeSource.GitRepo != nil
}
func (plugin *gitRepoPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
func (plugin *gitRepoPlugin) NewBuilder(spec *volume.Spec, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
if plugin.legacyMode {
// Legacy mode instances can be cleaned up but not created anew.
return nil, fmt.Errorf("legacy mode: can not create new instances")
@ -78,8 +75,8 @@ func (plugin *gitRepoPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectRefe
return &gitRepo{
podRef: *podRef,
volName: spec.Name,
source: spec.GitRepo.Repository,
revision: spec.GitRepo.Revision,
source: spec.VolumeSource.GitRepo.Repository,
revision: spec.VolumeSource.GitRepo.Revision,
exec: exec.New(),
plugin: plugin,
legacyMode: false,
@ -119,7 +116,7 @@ func (gr *gitRepo) SetUp() error {
}
// This is the spec for the volume that this plugin wraps.
var wrappedVolumeSpec = &api.Volume{
var wrappedVolumeSpec = &volume.Spec{
Name: "not-used",
VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}},
}

View File

@ -50,7 +50,7 @@ func TestCanSupport(t *testing.T) {
if plug.Name() != "kubernetes.io/git-repo" {
t.Errorf("Wrong name: %s", plug.Name())
}
if !plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{}}}) {
if !plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{}}}) {
t.Errorf("Expected true")
}
}
@ -118,7 +118,7 @@ func TestPlugin(t *testing.T) {
},
},
}
builder, err := plug.NewBuilder(spec, &api.ObjectReference{UID: types.UID("poduid")}, volume.VolumeOptions{""})
builder, err := plug.NewBuilder(volume.NewSpecFromVolume(spec), &api.ObjectReference{UID: types.UID("poduid")}, volume.VolumeOptions{""})
if err != nil {
t.Errorf("Failed to make a new Builder: %v", err)
}
@ -169,11 +169,12 @@ func TestPluginLegacy(t *testing.T) {
if plug.Name() != "git" {
t.Errorf("Wrong name: %s", plug.Name())
}
if plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{}}}) {
if plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{}}}) {
t.Errorf("Expected false")
}
if _, err := plug.NewBuilder(&api.Volume{VolumeSource: api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{}}}, &api.ObjectReference{UID: types.UID("poduid")}, volume.VolumeOptions{""}); err == nil {
spec := &api.Volume{VolumeSource: api.VolumeSource{GitRepo: &api.GitRepoVolumeSource{}}}
if _, err := plug.NewBuilder(volume.NewSpecFromVolume(spec), &api.ObjectReference{UID: types.UID("poduid")}, volume.VolumeOptions{""}); err == nil {
t.Errorf("Expected failiure")
}

View File

@ -53,11 +53,8 @@ func (plugin *glusterfsPlugin) Name() string {
return glusterfsPluginName
}
func (plugin *glusterfsPlugin) CanSupport(spec *api.Volume) bool {
if spec.VolumeSource.Glusterfs != nil {
return true
}
return false
func (plugin *glusterfsPlugin) CanSupport(spec *volume.Spec) bool {
return spec.VolumeSource.Glusterfs != nil || spec.PersistentVolumeSource.Glusterfs != nil
}
func (plugin *glusterfsPlugin) GetAccessModes() []api.AccessModeType {
@ -68,7 +65,7 @@ func (plugin *glusterfsPlugin) GetAccessModes() []api.AccessModeType {
}
}
func (plugin *glusterfsPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference, _ volume.VolumeOptions) (volume.Builder, error) {
func (plugin *glusterfsPlugin) NewBuilder(spec *volume.Spec, podRef *api.ObjectReference, _ volume.VolumeOptions) (volume.Builder, error) {
ep_name := spec.VolumeSource.Glusterfs.EndpointsName
ns := api.NamespaceDefault
ep, err := plugin.host.GetKubeClient().Endpoints(ns).Get(ep_name)
@ -80,7 +77,7 @@ func (plugin *glusterfsPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectRe
return plugin.newBuilderInternal(spec, ep, podRef, mount.New(), exec.New())
}
func (plugin *glusterfsPlugin) newBuilderInternal(spec *api.Volume, ep *api.Endpoints, podRef *api.ObjectReference, mounter mount.Interface, exe exec.Interface) (volume.Builder, error) {
func (plugin *glusterfsPlugin) newBuilderInternal(spec *volume.Spec, ep *api.Endpoints, podRef *api.ObjectReference, mounter mount.Interface, exe exec.Interface) (volume.Builder, error) {
return &glusterfs{
volName: spec.Name,
hosts: ep,

View File

@ -37,10 +37,10 @@ func TestCanSupport(t *testing.T) {
if plug.Name() != "kubernetes.io/glusterfs" {
t.Errorf("Wrong name: %s", plug.Name())
}
if !plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{Glusterfs: &api.GlusterfsVolumeSource{}}}) {
if !plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{Glusterfs: &api.GlusterfsVolumeSource{}}}) {
t.Errorf("Expected true")
}
if plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{}}) {
if plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{}}) {
t.Errorf("Expected false")
}
}
@ -94,7 +94,7 @@ func TestPlugin(t *testing.T) {
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
},
}
builder, err := plug.(*glusterfsPlugin).newBuilderInternal(spec, ep, &api.ObjectReference{UID: types.UID("poduid")}, &mount.FakeMounter{}, &fake)
builder, err := plug.(*glusterfsPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), ep, &api.ObjectReference{UID: types.UID("poduid")}, &mount.FakeMounter{}, &fake)
volumePath := builder.GetPath()
if err != nil {
t.Errorf("Failed to make a new Builder: %v", err)

View File

@ -47,11 +47,8 @@ func (plugin *hostPathPlugin) Name() string {
return hostPathPluginName
}
func (plugin *hostPathPlugin) CanSupport(spec *api.Volume) bool {
if spec.HostPath != nil {
return true
}
return false
func (plugin *hostPathPlugin) CanSupport(spec *volume.Spec) bool {
return spec.VolumeSource.HostPath != nil || spec.PersistentVolumeSource.HostPath != nil
}
func (plugin *hostPathPlugin) GetAccessModes() []api.AccessModeType {
@ -60,8 +57,12 @@ func (plugin *hostPathPlugin) GetAccessModes() []api.AccessModeType {
}
}
func (plugin *hostPathPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference, _ volume.VolumeOptions) (volume.Builder, error) {
return &hostPath{spec.HostPath.Path}, nil
func (plugin *hostPathPlugin) NewBuilder(spec *volume.Spec, podRef *api.ObjectReference, _ volume.VolumeOptions) (volume.Builder, error) {
if spec.VolumeSource.HostPath != nil {
return &hostPath{spec.VolumeSource.HostPath.Path}, nil
} else {
return &hostPath{spec.PersistentVolumeSource.HostPath.Path}, nil
}
}
func (plugin *hostPathPlugin) NewCleaner(volName string, podUID types.UID) (volume.Cleaner, error) {

View File

@ -35,10 +35,10 @@ func TestCanSupport(t *testing.T) {
if plug.Name() != "kubernetes.io/host-path" {
t.Errorf("Wrong name: %s", plug.Name())
}
if !plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{HostPath: &api.HostPathVolumeSource{}}}) {
if !plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{HostPath: &api.HostPathVolumeSource{}}}) {
t.Errorf("Expected true")
}
if plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{}}) {
if plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{}}) {
t.Errorf("Expected false")
}
}
@ -68,7 +68,7 @@ func TestPlugin(t *testing.T) {
Name: "vol1",
VolumeSource: api.VolumeSource{HostPath: &api.HostPathVolumeSource{"/vol1"}},
}
builder, err := plug.NewBuilder(spec, &api.ObjectReference{UID: types.UID("poduid")}, volume.VolumeOptions{})
builder, err := plug.NewBuilder(volume.NewSpecFromVolume(spec), &api.ObjectReference{UID: types.UID("poduid")}, volume.VolumeOptions{})
if err != nil {
t.Errorf("Failed to make a new Builder: %v", err)
}

View File

@ -52,8 +52,8 @@ func (plugin *ISCSIPlugin) Name() string {
return ISCSIPluginName
}
func (plugin *ISCSIPlugin) CanSupport(spec *api.Volume) bool {
if spec.ISCSI == nil {
func (plugin *ISCSIPlugin) CanSupport(spec *volume.Spec) bool {
if spec.VolumeSource.ISCSI == nil {
return false
}
// see if iscsiadm is there
@ -72,22 +72,23 @@ func (plugin *ISCSIPlugin) GetAccessModes() []api.AccessModeType {
}
}
func (plugin *ISCSIPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference, _ volume.VolumeOptions) (volume.Builder, error) {
func (plugin *ISCSIPlugin) NewBuilder(spec *volume.Spec, podRef *api.ObjectReference, _ volume.VolumeOptions) (volume.Builder, error) {
// Inject real implementations here, test through the internal function.
return plugin.newBuilderInternal(spec, podRef.UID, &ISCSIUtil{}, mount.New())
}
func (plugin *ISCSIPlugin) newBuilderInternal(spec *api.Volume, podUID types.UID, manager diskManager, mounter mount.Interface) (volume.Builder, error) {
lun := strconv.Itoa(spec.ISCSI.Lun)
func (plugin *ISCSIPlugin) newBuilderInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface) (volume.Builder, error) {
iscsi := spec.VolumeSource.ISCSI
lun := strconv.Itoa(iscsi.Lun)
return &iscsiDisk{
podUID: podUID,
volName: spec.Name,
portal: spec.ISCSI.TargetPortal,
iqn: spec.ISCSI.IQN,
portal: iscsi.TargetPortal,
iqn: iscsi.IQN,
lun: lun,
fsType: spec.ISCSI.FSType,
readOnly: spec.ISCSI.ReadOnly,
fsType: iscsi.FSType,
readOnly: iscsi.ReadOnly,
manager: manager,
mounter: mounter,
plugin: plugin,

View File

@ -81,7 +81,7 @@ func TestPlugin(t *testing.T) {
},
},
}
builder, err := plug.(*ISCSIPlugin).newBuilderInternal(spec, types.UID("poduid"), &fakeDiskManager{}, &mount.FakeMounter{})
builder, err := plug.(*ISCSIPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &fakeDiskManager{}, &mount.FakeMounter{})
if err != nil {
t.Errorf("Failed to make a new Builder: %v", err)
}

View File

@ -50,11 +50,8 @@ func (plugin *nfsPlugin) Name() string {
return nfsPluginName
}
func (plugin *nfsPlugin) CanSupport(spec *api.Volume) bool {
if spec.VolumeSource.NFS != nil {
return true
}
return false
func (plugin *nfsPlugin) CanSupport(spec *volume.Spec) bool {
return spec.VolumeSource.NFS != nil
}
func (plugin *nfsPlugin) GetAccessModes() []api.AccessModeType {
@ -65,11 +62,11 @@ func (plugin *nfsPlugin) GetAccessModes() []api.AccessModeType {
}
}
func (plugin *nfsPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference, _ volume.VolumeOptions) (volume.Builder, error) {
func (plugin *nfsPlugin) NewBuilder(spec *volume.Spec, podRef *api.ObjectReference, _ volume.VolumeOptions) (volume.Builder, error) {
return plugin.newBuilderInternal(spec, podRef, plugin.mounter)
}
func (plugin *nfsPlugin) newBuilderInternal(spec *api.Volume, podRef *api.ObjectReference, mounter nfsMountInterface) (volume.Builder, error) {
func (plugin *nfsPlugin) newBuilderInternal(spec *volume.Spec, podRef *api.ObjectReference, mounter nfsMountInterface) (volume.Builder, error) {
return &nfs{
volName: spec.Name,
server: spec.VolumeSource.NFS.Server,

View File

@ -37,10 +37,10 @@ func TestCanSupport(t *testing.T) {
if plug.Name() != "kubernetes.io/nfs" {
t.Errorf("Wrong name: %s", plug.Name())
}
if !plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{NFS: &api.NFSVolumeSource{}}}) {
if !plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{NFS: &api.NFSVolumeSource{}}}) {
t.Errorf("Expected true")
}
if plug.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{}}) {
if plug.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{}}) {
t.Errorf("Expected false")
}
}
@ -108,7 +108,7 @@ func TestPlugin(t *testing.T) {
VolumeSource: api.VolumeSource{NFS: &api.NFSVolumeSource{"localhost", "/tmp", false}},
}
fake := &fakeNFSMounter{}
builder, err := plug.(*nfsPlugin).newBuilderInternal(spec, &api.ObjectReference{UID: types.UID("poduid")}, fake)
builder, err := plug.(*nfsPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), &api.ObjectReference{UID: types.UID("poduid")}, fake)
volumePath := builder.GetPath()
if err != nil {
t.Errorf("Failed to make a new Builder: %v", err)

View File

@ -56,13 +56,13 @@ type VolumePlugin interface {
// CanSupport tests whether the plugin supports a given volume
// specification from the API. The spec pointer should be considered
// const.
CanSupport(spec *api.Volume) bool
CanSupport(spec *Spec) bool
// NewBuilder creates a new volume.Builder from an API specification.
// Ownership of the spec pointer in *not* transferred.
// - spec: The api.Volume spec
// - podRef: a reference to the enclosing pod
NewBuilder(spec *api.Volume, podRef *api.ObjectReference, opts VolumeOptions) (Builder, error)
NewBuilder(spec *Spec, podRef *api.ObjectReference, opts VolumeOptions) (Builder, error)
// NewCleaner creates a new volume.Cleaner from recoverable state.
// - name: The volume name, as per the api.Volume spec.
@ -105,12 +105,12 @@ type VolumeHost interface {
// the provided spec. This is used to implement volume plugins which
// "wrap" other plugins. For example, the "secret" volume is
// implemented in terms of the "emptyDir" volume.
NewWrapperBuilder(spec *api.Volume, podRef *api.ObjectReference, opts VolumeOptions) (Builder, error)
NewWrapperBuilder(spec *Spec, podRef *api.ObjectReference, opts VolumeOptions) (Builder, error)
// NewWrapperCleaner finds an appropriate plugin with which to handle
// the provided spec. See comments on NewWrapperBuilder for more
// context.
NewWrapperCleaner(spec *api.Volume, podUID types.UID) (Cleaner, error)
NewWrapperCleaner(spec *Spec, podUID types.UID) (Cleaner, error)
}
// VolumePluginMgr tracks registered plugins.
@ -119,6 +119,29 @@ type VolumePluginMgr struct {
plugins map[string]VolumePlugin
}
// Spec is an internal representation of a volume. All API volume types translate to Spec.
type Spec struct {
Name string
VolumeSource api.VolumeSource
PersistentVolumeSource api.PersistentVolumeSource
}
// NewSpecFromVolume creates an Spec from an api.Volume
func NewSpecFromVolume(vs *api.Volume) *Spec {
return &Spec{
Name: vs.Name,
VolumeSource: vs.VolumeSource,
}
}
// NewSpecFromPersistentVolume creates an Spec from an api.PersistentVolume
func NewSpecFromPersistentVolume(pv *api.PersistentVolume) *Spec {
return &Spec{
Name: pv.Name,
PersistentVolumeSource: pv.Spec.PersistentVolumeSource,
}
}
// InitPlugins initializes each plugin. All plugins must have unique names.
// This must be called exactly once before any New* methods are called on any
// plugins.
@ -152,7 +175,7 @@ func (pm *VolumePluginMgr) InitPlugins(plugins []VolumePlugin, host VolumeHost)
// FindPluginBySpec 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) FindPluginBySpec(spec *api.Volume) (VolumePlugin, error) {
func (pm *VolumePluginMgr) FindPluginBySpec(spec *Spec) (VolumePlugin, error) {
pm.mutex.Lock()
defer pm.mutex.Unlock()

View File

@ -0,0 +1,53 @@
/*
Copyright 2015 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package volume
import (
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
)
func TestSpecSourceConverters(t *testing.T) {
v := &api.Volume{
Name: "foo",
VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}},
}
converted := NewSpecFromVolume(v)
if converted.VolumeSource.EmptyDir == nil {
t.Errorf("Unexpected nil EmptyDir: %+v", converted)
}
if v.Name != converted.Name {
t.Errorf("Expected %v but got %v", v.Name, converted.Name)
}
pv := &api.PersistentVolume{
ObjectMeta: api.ObjectMeta{Name: "bar"},
Spec: api.PersistentVolumeSpec{
PersistentVolumeSource: api.PersistentVolumeSource{AWSElasticBlockStore: &api.AWSElasticBlockStoreVolumeSource{}},
},
}
converted = NewSpecFromPersistentVolume(pv)
if converted.PersistentVolumeSource.AWSElasticBlockStore == nil {
t.Errorf("Unexpected nil AWSElasticBlockStore: %+v", converted)
}
if pv.Name != converted.Name {
t.Errorf("Expected %v but got %v", pv.Name, converted.Name)
}
}

View File

@ -50,20 +50,16 @@ func (plugin *secretPlugin) Name() string {
return secretPluginName
}
func (plugin *secretPlugin) CanSupport(spec *api.Volume) bool {
if spec.Secret != nil {
return true
}
return false
func (plugin *secretPlugin) CanSupport(spec *volume.Spec) bool {
return spec.VolumeSource.Secret != nil
}
func (plugin *secretPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
func (plugin *secretPlugin) NewBuilder(spec *volume.Spec, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
return plugin.newBuilderInternal(spec, podRef, opts)
}
func (plugin *secretPlugin) newBuilderInternal(spec *api.Volume, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
return &secretVolume{spec.Name, *podRef, plugin, spec.Secret.SecretName, &opts}, nil
func (plugin *secretPlugin) newBuilderInternal(spec *volume.Spec, podRef *api.ObjectReference, opts volume.VolumeOptions) (volume.Builder, error) {
return &secretVolume{spec.Name, *podRef, plugin, spec.VolumeSource.Secret.SecretName, &opts}, nil
}
func (plugin *secretPlugin) NewCleaner(volName string, podUID types.UID) (volume.Cleaner, error) {
@ -89,7 +85,7 @@ func (sv *secretVolume) SetUp() error {
}
// This is the spec for the volume that this plugin wraps.
var wrappedVolumeSpec = &api.Volume{
var wrappedVolumeSpec = &volume.Spec{
Name: "not-used",
VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{Medium: api.StorageTypeMemory}},
}

View File

@ -53,7 +53,7 @@ func TestCanSupport(t *testing.T) {
if plugin.Name() != secretPluginName {
t.Errorf("Wrong name: %s", plugin.Name())
}
if !plugin.CanSupport(&api.Volume{VolumeSource: api.VolumeSource{Secret: &api.SecretVolumeSource{SecretName: ""}}}) {
if !plugin.CanSupport(&volume.Spec{Name: "foo", VolumeSource: api.VolumeSource{Secret: &api.SecretVolumeSource{SecretName: ""}}}) {
t.Errorf("Expected true")
}
}
@ -97,7 +97,7 @@ func TestPlugin(t *testing.T) {
t.Errorf("Can't find the plugin by name")
}
builder, err := plugin.NewBuilder(volumeSpec, &api.ObjectReference{UID: types.UID(testPodUID)}, volume.VolumeOptions{})
builder, err := plugin.NewBuilder(volume.NewSpecFromVolume(volumeSpec), &api.ObjectReference{UID: types.UID(testPodUID)}, volume.VolumeOptions{})
if err != nil {
t.Errorf("Failed to make a new Builder: %v", err)
}

View File

@ -55,7 +55,7 @@ func (f *fakeVolumeHost) GetKubeClient() client.Interface {
return f.kubeClient
}
func (f *fakeVolumeHost) NewWrapperBuilder(spec *api.Volume, podRef *api.ObjectReference, opts VolumeOptions) (Builder, error) {
func (f *fakeVolumeHost) NewWrapperBuilder(spec *Spec, podRef *api.ObjectReference, opts VolumeOptions) (Builder, error) {
plug, err := f.pluginMgr.FindPluginBySpec(spec)
if err != nil {
return nil, err
@ -63,7 +63,7 @@ func (f *fakeVolumeHost) NewWrapperBuilder(spec *api.Volume, podRef *api.ObjectR
return plug.NewBuilder(spec, podRef, opts)
}
func (f *fakeVolumeHost) NewWrapperCleaner(spec *api.Volume, podUID types.UID) (Cleaner, error) {
func (f *fakeVolumeHost) NewWrapperCleaner(spec *Spec, podUID types.UID) (Cleaner, error) {
plug, err := f.pluginMgr.FindPluginBySpec(spec)
if err != nil {
return nil, err
@ -90,12 +90,12 @@ func (plugin *FakeVolumePlugin) Name() string {
return plugin.PluginName
}
func (plugin *FakeVolumePlugin) CanSupport(spec *api.Volume) bool {
func (plugin *FakeVolumePlugin) CanSupport(spec *Spec) bool {
// TODO: maybe pattern-match on spec.Name to decide?
return true
}
func (plugin *FakeVolumePlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference, opts VolumeOptions) (Builder, error) {
func (plugin *FakeVolumePlugin) NewBuilder(spec *Spec, podRef *api.ObjectReference, opts VolumeOptions) (Builder, error) {
return &FakeVolume{podRef.UID, spec.Name, plugin}, nil
}