diff --git a/pkg/kubelet/volumes.go b/pkg/kubelet/volumes.go index 6bedded4a8d..b530acd352c 100644 --- a/pkg/kubelet/volumes.go +++ b/pkg/kubelet/volumes.go @@ -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 diff --git a/pkg/volume/aws_ebs/aws_ebs.go b/pkg/volume/aws_ebs/aws_ebs.go index 0e8562d6038..43aea435539 100644 --- a/pkg/volume/aws_ebs/aws_ebs.go +++ b/pkg/volume/aws_ebs/aws_ebs.go @@ -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, diff --git a/pkg/volume/aws_ebs/aws_ebs_test.go b/pkg/volume/aws_ebs/aws_ebs_test.go index c6fb7a9a3d2..8b2ccdc806f 100644 --- a/pkg/volume/aws_ebs/aws_ebs_test.go +++ b/pkg/volume/aws_ebs/aws_ebs_test.go @@ -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) } diff --git a/pkg/volume/empty_dir/empty_dir.go b/pkg/volume/empty_dir/empty_dir.go index 7187b9941cd..e28f6872a6d 100644 --- a/pkg/volume/empty_dir/empty_dir.go +++ b/pkg/volume/empty_dir/empty_dir.go @@ -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, diff --git a/pkg/volume/empty_dir/empty_dir_test.go b/pkg/volume/empty_dir/empty_dir_test.go index c7a1b48e266..28e2e4f4ff1 100644 --- a/pkg/volume/empty_dir/empty_dir_test.go +++ b/pkg/volume/empty_dir/empty_dir_test.go @@ -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") } diff --git a/pkg/volume/gce_pd/gce_pd.go b/pkg/volume/gce_pd/gce_pd.go index e2cb7f41911..163f450d876 100644 --- a/pkg/volume/gce_pd/gce_pd.go +++ b/pkg/volume/gce_pd/gce_pd.go @@ -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, diff --git a/pkg/volume/gce_pd/gce_pd_test.go b/pkg/volume/gce_pd/gce_pd_test.go index cfd962f7935..a23f5950f57 100644 --- a/pkg/volume/gce_pd/gce_pd_test.go +++ b/pkg/volume/gce_pd/gce_pd_test.go @@ -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") } diff --git a/pkg/volume/git_repo/git_repo.go b/pkg/volume/git_repo/git_repo.go index 5488d61077f..a55d6b0df12 100644 --- a/pkg/volume/git_repo/git_repo.go +++ b/pkg/volume/git_repo/git_repo.go @@ -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{}}, } diff --git a/pkg/volume/git_repo/git_repo_test.go b/pkg/volume/git_repo/git_repo_test.go index 0ea387a1dff..34e864738ba 100644 --- a/pkg/volume/git_repo/git_repo_test.go +++ b/pkg/volume/git_repo/git_repo_test.go @@ -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") } diff --git a/pkg/volume/glusterfs/glusterfs.go b/pkg/volume/glusterfs/glusterfs.go index 2d44c7c6742..336e9223760 100644 --- a/pkg/volume/glusterfs/glusterfs.go +++ b/pkg/volume/glusterfs/glusterfs.go @@ -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, diff --git a/pkg/volume/glusterfs/glusterfs_test.go b/pkg/volume/glusterfs/glusterfs_test.go index 32e9f1ef2f8..c5eb8edf4fa 100644 --- a/pkg/volume/glusterfs/glusterfs_test.go +++ b/pkg/volume/glusterfs/glusterfs_test.go @@ -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) diff --git a/pkg/volume/host_path/host_path.go b/pkg/volume/host_path/host_path.go index f18e79c53b9..2c63ac3bf80 100644 --- a/pkg/volume/host_path/host_path.go +++ b/pkg/volume/host_path/host_path.go @@ -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) { diff --git a/pkg/volume/host_path/host_path_test.go b/pkg/volume/host_path/host_path_test.go index 8ed9251e97c..e106d323c78 100644 --- a/pkg/volume/host_path/host_path_test.go +++ b/pkg/volume/host_path/host_path_test.go @@ -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) } diff --git a/pkg/volume/iscsi/iscsi.go b/pkg/volume/iscsi/iscsi.go index 4e1aa611d3f..80cf64044c2 100644 --- a/pkg/volume/iscsi/iscsi.go +++ b/pkg/volume/iscsi/iscsi.go @@ -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, diff --git a/pkg/volume/iscsi/iscsi_test.go b/pkg/volume/iscsi/iscsi_test.go index 20e649fda36..8b3b6cc646b 100644 --- a/pkg/volume/iscsi/iscsi_test.go +++ b/pkg/volume/iscsi/iscsi_test.go @@ -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) } diff --git a/pkg/volume/nfs/nfs.go b/pkg/volume/nfs/nfs.go index e2e4baf055c..9d09b33edda 100644 --- a/pkg/volume/nfs/nfs.go +++ b/pkg/volume/nfs/nfs.go @@ -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, diff --git a/pkg/volume/nfs/nfs_test.go b/pkg/volume/nfs/nfs_test.go index abcace79795..a67538fb066 100644 --- a/pkg/volume/nfs/nfs_test.go +++ b/pkg/volume/nfs/nfs_test.go @@ -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) diff --git a/pkg/volume/plugins.go b/pkg/volume/plugins.go index ac98aa25f23..9804df6eae6 100644 --- a/pkg/volume/plugins.go +++ b/pkg/volume/plugins.go @@ -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() diff --git a/pkg/volume/plugins_test.go b/pkg/volume/plugins_test.go new file mode 100644 index 00000000000..a77d93df3c8 --- /dev/null +++ b/pkg/volume/plugins_test.go @@ -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) + } +} diff --git a/pkg/volume/secret/secret.go b/pkg/volume/secret/secret.go index 28a71024571..54b3385012f 100644 --- a/pkg/volume/secret/secret.go +++ b/pkg/volume/secret/secret.go @@ -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}}, } diff --git a/pkg/volume/secret/secret_test.go b/pkg/volume/secret/secret_test.go index 93d42897a46..e1fe0dc60f7 100644 --- a/pkg/volume/secret/secret_test.go +++ b/pkg/volume/secret/secret_test.go @@ -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) } diff --git a/pkg/volume/testing.go b/pkg/volume/testing.go index 790ae0466be..66e20b75e6b 100644 --- a/pkg/volume/testing.go +++ b/pkg/volume/testing.go @@ -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 }