diff --git a/pkg/controller/persistentvolume/persistentvolume_provisioner_controller.go b/pkg/controller/persistentvolume/persistentvolume_provisioner_controller.go index 8fc8e3fce8e..50cf897b327 100644 --- a/pkg/controller/persistentvolume/persistentvolume_provisioner_controller.go +++ b/pkg/controller/persistentvolume/persistentvolume_provisioner_controller.go @@ -473,11 +473,11 @@ func (c *PersistentVolumeProvisionerController) GetKubeClient() client.Interface return c.client.GetKubeClient() } -func (c *PersistentVolumeProvisionerController) NewWrapperBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) { +func (c *PersistentVolumeProvisionerController) NewWrapperBuilder(volName string, spec volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) { return nil, fmt.Errorf("NewWrapperBuilder not supported by PVClaimBinder's VolumeHost implementation") } -func (c *PersistentVolumeProvisionerController) NewWrapperCleaner(spec *volume.Spec, podUID types.UID) (volume.Cleaner, error) { +func (c *PersistentVolumeProvisionerController) NewWrapperCleaner(volName string, spec volume.Spec, podUID types.UID) (volume.Cleaner, error) { return nil, fmt.Errorf("NewWrapperCleaner not supported by PVClaimBinder's VolumeHost implementation") } diff --git a/pkg/controller/persistentvolume/persistentvolume_recycler_controller.go b/pkg/controller/persistentvolume/persistentvolume_recycler_controller.go index e86347ac07f..b902aaab629 100644 --- a/pkg/controller/persistentvolume/persistentvolume_recycler_controller.go +++ b/pkg/controller/persistentvolume/persistentvolume_recycler_controller.go @@ -291,11 +291,11 @@ func (f *PersistentVolumeRecycler) GetKubeClient() client.Interface { return f.kubeClient } -func (f *PersistentVolumeRecycler) NewWrapperBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) { +func (f *PersistentVolumeRecycler) NewWrapperBuilder(volName string, spec volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) { return nil, fmt.Errorf("NewWrapperBuilder not supported by PVClaimBinder's VolumeHost implementation") } -func (f *PersistentVolumeRecycler) NewWrapperCleaner(spec *volume.Spec, podUID types.UID) (volume.Cleaner, error) { +func (f *PersistentVolumeRecycler) NewWrapperCleaner(volName string, spec volume.Spec, podUID types.UID) (volume.Cleaner, error) { return nil, fmt.Errorf("NewWrapperCleaner not supported by PVClaimBinder's VolumeHost implementation") } diff --git a/pkg/kubelet/volumes.go b/pkg/kubelet/volumes.go index c6c5e296892..6e179584063 100644 --- a/pkg/kubelet/volumes.go +++ b/pkg/kubelet/volumes.go @@ -58,16 +58,28 @@ func (vh *volumeHost) GetKubeClient() client.Interface { return vh.kubelet.kubeClient } -func (vh *volumeHost) NewWrapperBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) { - b, err := vh.kubelet.newVolumeBuilderFromPlugins(spec, pod, opts) +func (vh *volumeHost) NewWrapperBuilder(volName string, spec volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) { + // The name of wrapper volume is set to "wrapped_{wrapped_volume_name}" + wrapperVolumeName := "wrapped_" + volName + if spec.Volume != nil { + spec.Volume.Name = wrapperVolumeName + } + + b, err := vh.kubelet.newVolumeBuilderFromPlugins(&spec, pod, opts) if err == nil && b == nil { return nil, errUnsupportedVolumeType } return b, nil } -func (vh *volumeHost) NewWrapperCleaner(spec *volume.Spec, podUID types.UID) (volume.Cleaner, error) { - plugin, err := vh.kubelet.volumePluginMgr.FindPluginBySpec(spec) +func (vh *volumeHost) NewWrapperCleaner(volName string, spec volume.Spec, podUID types.UID) (volume.Cleaner, error) { + // The name of wrapper volume is set to "wrapped_{wrapped_volume_name}" + wrapperVolumeName := "wrapped_" + volName + if spec.Volume != nil { + spec.Volume.Name = wrapperVolumeName + } + + plugin, err := vh.kubelet.volumePluginMgr.FindPluginBySpec(&spec) if err != nil { return nil, err } diff --git a/pkg/volume/downwardapi/downwardapi.go b/pkg/volume/downwardapi/downwardapi.go index 7fc919293e0..014ef07ca4c 100644 --- a/pkg/volume/downwardapi/downwardapi.go +++ b/pkg/volume/downwardapi/downwardapi.go @@ -51,6 +51,10 @@ type downwardAPIPlugin struct { var _ volume.VolumePlugin = &downwardAPIPlugin{} +var wrappedVolumeSpec = volume.Spec{ + Volume: &api.Volume{VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{Medium: api.StorageMediumMemory}}}, +} + func (plugin *downwardAPIPlugin) Init(host volume.VolumeHost) error { plugin.host = host return nil @@ -77,11 +81,18 @@ func (plugin *downwardAPIPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opt } return &downwardAPIVolumeBuilder{ downwardAPIVolume: v, - opts: &opts}, nil + opts: &opts, + }, nil } func (plugin *downwardAPIPlugin) NewCleaner(volName string, podUID types.UID) (volume.Cleaner, error) { - return &downwardAPIVolumeCleaner{&downwardAPIVolume{volName: volName, podUID: podUID, plugin: plugin}}, nil + return &downwardAPIVolumeCleaner{ + &downwardAPIVolume{ + volName: volName, + podUID: podUID, + plugin: plugin, + }, + }, nil } // downwardAPIVolume retrieves downward API data and placing them into the volume on the host. @@ -94,11 +105,6 @@ type downwardAPIVolume struct { volume.MetricsNil } -// This is the spec for the volume that this plugin wraps. -var wrappedVolumeSpec = &volume.Spec{ - Volume: &api.Volume{VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{Medium: api.StorageMediumMemory}}}, -} - // downwardAPIVolumeBuilder fetches info from downward API from the pod // and dumps it in files type downwardAPIVolumeBuilder struct { @@ -130,7 +136,7 @@ func (b *downwardAPIVolumeBuilder) SetUp() error { func (b *downwardAPIVolumeBuilder) SetUpAt(dir string) error { glog.V(3).Infof("Setting up a downwardAPI volume %v for pod %v/%v at %v", b.volName, b.pod.Namespace, b.pod.Name, dir) // Wrap EmptyDir. Here we rely on the idempotency of the wrapped plugin to avoid repeatedly mounting - wrapped, err := b.plugin.host.NewWrapperBuilder(wrappedVolumeSpec, b.pod, *b.opts) + wrapped, err := b.plugin.host.NewWrapperBuilder(b.volName, wrappedVolumeSpec, b.pod, *b.opts) if err != nil { glog.Errorf("Couldn't setup downwardAPI volume %v for pod %v/%v: %s", b.volName, b.pod.Namespace, b.pod.Name, err.Error()) return err @@ -364,7 +370,7 @@ func (c *downwardAPIVolumeCleaner) TearDownAt(dir string) error { glog.V(3).Infof("Tearing down volume %v for pod %v at %v", c.volName, c.podUID, dir) // Wrap EmptyDir, let it do the teardown. - wrapped, err := c.plugin.host.NewWrapperCleaner(wrappedVolumeSpec, c.podUID) + wrapped, err := c.plugin.host.NewWrapperCleaner(c.volName, wrappedVolumeSpec, c.podUID) if err != nil { return err } diff --git a/pkg/volume/downwardapi/downwardapi_test.go b/pkg/volume/downwardapi/downwardapi_test.go index 6c2559e38d4..20432d73e91 100644 --- a/pkg/volume/downwardapi/downwardapi_test.go +++ b/pkg/volume/downwardapi/downwardapi_test.go @@ -39,12 +39,12 @@ func formatMap(m map[string]string) (fmtstr string) { return } -func newTestHost(t *testing.T, client client.Interface, basePath string) volume.VolumeHost { +func newTestHost(t *testing.T, client client.Interface, basePath string) (string, volume.VolumeHost) { tempDir, err := ioutil.TempDir(basePath, "downwardApi_volume_test.") if err != nil { t.Fatalf("can't make a temp rootdir: %v", err) } - return volume.NewFakeVolumeHost(tempDir, client, empty_dir.ProbeVolumePlugins()) + return tempDir, volume.NewFakeVolumeHost(tempDir, client, empty_dir.ProbeVolumePlugins()) } func TestCanSupport(t *testing.T) { @@ -54,7 +54,8 @@ func TestCanSupport(t *testing.T) { } defer os.RemoveAll(tmpDir) pluginMgr := volume.VolumePluginMgr{} - pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, nil, tmpDir)) + _, host := newTestHost(t, nil, tmpDir) + pluginMgr.InitPlugins(ProbeVolumePlugins(), host) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) if err != nil { @@ -110,7 +111,8 @@ func TestLabels(t *testing.T) { } defer os.RemoveAll(tmpDir) pluginMgr := volume.VolumePluginMgr{} - pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) + rootDir, host := newTestHost(t, fake, tmpDir) + pluginMgr.InitPlugins(ProbeVolumePlugins(), host) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) volumeSpec := &api.Volume{ Name: testVolumeName, @@ -141,6 +143,17 @@ func TestLabels(t *testing.T) { t.Errorf("Failed to setup volume: %v", err) } + // downwardAPI volume should create its own empty wrapper path + podWrapperMetadataDir := fmt.Sprintf("%v/pods/%v/plugins/kubernetes.io~empty-dir/wrapped_%v", rootDir, testPodUID, testVolumeName) + + if _, err := os.Stat(podWrapperMetadataDir); err != nil { + if os.IsNotExist(err) { + t.Errorf("SetUp() failed, empty-dir wrapper path was not created: %s", podWrapperMetadataDir) + } else { + t.Errorf("SetUp() failed: %v", err) + } + } + var data []byte data, err = ioutil.ReadFile(path.Join(volumePath, "labels")) if err != nil { @@ -189,7 +202,8 @@ func TestAnnotations(t *testing.T) { } defer os.RemoveAll(tmpDir) pluginMgr := volume.VolumePluginMgr{} - pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) + _, host := newTestHost(t, fake, tmpDir) + pluginMgr.InitPlugins(ProbeVolumePlugins(), host) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) if err != nil { t.Errorf("Can't find the plugin by name") @@ -254,7 +268,8 @@ func TestName(t *testing.T) { } defer os.RemoveAll(tmpDir) pluginMgr := volume.VolumePluginMgr{} - pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) + _, host := newTestHost(t, fake, tmpDir) + pluginMgr.InitPlugins(ProbeVolumePlugins(), host) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) if err != nil { t.Errorf("Can't find the plugin by name") @@ -320,7 +335,8 @@ func TestNamespace(t *testing.T) { } defer os.RemoveAll(tmpDir) pluginMgr := volume.VolumePluginMgr{} - pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) + _, host := newTestHost(t, fake, tmpDir) + pluginMgr.InitPlugins(ProbeVolumePlugins(), host) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) if err != nil { t.Errorf("Can't find the plugin by name") @@ -379,7 +395,8 @@ func TestWriteTwiceNoUpdate(t *testing.T) { } defer os.RemoveAll(tmpDir) pluginMgr := volume.VolumePluginMgr{} - pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) + _, host := newTestHost(t, fake, tmpDir) + pluginMgr.InitPlugins(ProbeVolumePlugins(), host) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) volumeSpec := &api.Volume{ Name: testVolumeName, @@ -468,7 +485,8 @@ func TestWriteTwiceWithUpdate(t *testing.T) { } defer os.RemoveAll(tmpDir) pluginMgr := volume.VolumePluginMgr{} - pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) + _, host := newTestHost(t, fake, tmpDir) + pluginMgr.InitPlugins(ProbeVolumePlugins(), host) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) volumeSpec := &api.Volume{ Name: testVolumeName, @@ -577,7 +595,8 @@ func TestWriteWithUnixPath(t *testing.T) { } defer os.RemoveAll(tmpDir) pluginMgr := volume.VolumePluginMgr{} - pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) + _, host := newTestHost(t, fake, tmpDir) + pluginMgr.InitPlugins(ProbeVolumePlugins(), host) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) volumeSpec := &api.Volume{ Name: testVolumeName, @@ -656,7 +675,8 @@ func TestWriteWithUnixPathBadPath(t *testing.T) { } defer os.RemoveAll(tmpDir) pluginMgr := volume.VolumePluginMgr{} - pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) + _, host := newTestHost(t, fake, tmpDir) + pluginMgr.InitPlugins(ProbeVolumePlugins(), host) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) if err != nil { t.Errorf("Can't find the plugin by name") diff --git a/pkg/volume/git_repo/git_repo.go b/pkg/volume/git_repo/git_repo.go index 689ab8c4c9b..b27203af266 100644 --- a/pkg/volume/git_repo/git_repo.go +++ b/pkg/volume/git_repo/git_repo.go @@ -41,6 +41,10 @@ type gitRepoPlugin struct { var _ volume.VolumePlugin = &gitRepoPlugin{} +var wrappedVolumeSpec = volume.Spec{ + Volume: &api.Volume{VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}, +} + const ( gitRepoPluginName = "kubernetes.io/git-repo" ) @@ -128,11 +132,6 @@ func (b *gitRepoVolumeBuilder) SetUp() error { return b.SetUpAt(b.GetPath()) } -// This is the spec for the volume that this plugin wraps. -var wrappedVolumeSpec = &volume.Spec{ - Volume: &api.Volume{VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}, -} - // SetUpAt creates new directory and clones a git repo. func (b *gitRepoVolumeBuilder) SetUpAt(dir string) error { if volumeutil.IsReady(b.getMetaDir()) { @@ -140,7 +139,7 @@ func (b *gitRepoVolumeBuilder) SetUpAt(dir string) error { } // Wrap EmptyDir, let it do the setup. - wrapped, err := b.plugin.host.NewWrapperBuilder(wrappedVolumeSpec, &b.pod, b.opts) + wrapped, err := b.plugin.host.NewWrapperBuilder(b.volName, wrappedVolumeSpec, &b.pod, b.opts) if err != nil { return err } @@ -218,8 +217,9 @@ func (c *gitRepoVolumeCleaner) TearDown() error { // TearDownAt simply deletes everything in the directory. func (c *gitRepoVolumeCleaner) TearDownAt(dir string) error { + // Wrap EmptyDir, let it do the teardown. - wrapped, err := c.plugin.host.NewWrapperCleaner(wrappedVolumeSpec, c.podUID) + wrapped, err := c.plugin.host.NewWrapperCleaner(c.volName, wrappedVolumeSpec, c.podUID) if err != nil { return err } diff --git a/pkg/volume/git_repo/git_repo_test.go b/pkg/volume/git_repo/git_repo_test.go index 5686aee3e59..5c4140ed9c3 100644 --- a/pkg/volume/git_repo/git_repo_test.go +++ b/pkg/volume/git_repo/git_repo_test.go @@ -32,17 +32,18 @@ import ( "k8s.io/kubernetes/pkg/volume/empty_dir" ) -func newTestHost(t *testing.T) volume.VolumeHost { +func newTestHost(t *testing.T) (string, volume.VolumeHost) { tempDir, err := ioutil.TempDir("/tmp", "git_repo_test.") if err != nil { t.Fatalf("can't make a temp rootdir: %v", err) } - return volume.NewFakeVolumeHost(tempDir, nil, empty_dir.ProbeVolumePlugins()) + return tempDir, volume.NewFakeVolumeHost(tempDir, nil, empty_dir.ProbeVolumePlugins()) } func TestCanSupport(t *testing.T) { plugMgr := volume.VolumePluginMgr{} - plugMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t)) + _, host := newTestHost(t) + plugMgr.InitPlugins(ProbeVolumePlugins(), host) plug, err := plugMgr.FindPluginByName("kubernetes.io/git-repo") if err != nil { @@ -218,7 +219,8 @@ func doTestPlugin(scenario struct { allErrs := []error{} plugMgr := volume.VolumePluginMgr{} - plugMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t)) + rootDir, host := newTestHost(t) + plugMgr.InitPlugins(ProbeVolumePlugins(), host) plug, err := plugMgr.FindPluginByName("kubernetes.io/git-repo") if err != nil { @@ -241,7 +243,8 @@ func doTestPlugin(scenario struct { } path := builder.GetPath() - if !strings.HasSuffix(path, "pods/poduid/volumes/kubernetes.io~git-repo/vol1") { + suffix := fmt.Sprintf("pods/poduid/volumes/kubernetes.io~git-repo/%v", scenario.vol.Name) + if !strings.HasSuffix(path, suffix) { allErrs = append(allErrs, fmt.Errorf("Got unexpected path: %s", path)) return allErrs @@ -263,6 +266,19 @@ func doTestPlugin(scenario struct { } } + // gitRepo volume should create its own empty wrapper path + podWrapperMetadataDir := fmt.Sprintf("%v/pods/poduid/plugins/kubernetes.io~empty-dir/wrapped_%v", rootDir, scenario.vol.Name) + + if _, err := os.Stat(podWrapperMetadataDir); err != nil { + if os.IsNotExist(err) { + allErrs = append(allErrs, + fmt.Errorf("SetUp() failed, empty-dir wrapper path is not created: %s", podWrapperMetadataDir)) + } else { + allErrs = append(allErrs, + fmt.Errorf("SetUp() failed: %v", err)) + } + } + cleaner, err := plug.NewCleaner("vol1", types.UID("poduid")) if err != nil { allErrs = append(allErrs, diff --git a/pkg/volume/persistent_claim/persistent_claim.go b/pkg/volume/persistent_claim/persistent_claim.go index 219b9c5cb47..0807358e96b 100644 --- a/pkg/volume/persistent_claim/persistent_claim.go +++ b/pkg/volume/persistent_claim/persistent_claim.go @@ -80,7 +80,7 @@ func (plugin *persistentClaimPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, return nil, err } - builder, err := plugin.host.NewWrapperBuilder(volume.NewSpecFromPersistentVolume(pv, spec.ReadOnly), pod, opts) + builder, err := plugin.host.NewWrapperBuilder(claim.Spec.VolumeName, *volume.NewSpecFromPersistentVolume(pv, spec.ReadOnly), pod, opts) if err != nil { glog.Errorf("Error creating builder for claim: %+v\n", claim.Name) return nil, err diff --git a/pkg/volume/plugins.go b/pkg/volume/plugins.go index 80af44e298e..9398859b64a 100644 --- a/pkg/volume/plugins.go +++ b/pkg/volume/plugins.go @@ -144,12 +144,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 *Spec, pod *api.Pod, opts VolumeOptions) (Builder, error) + NewWrapperBuilder(volName string, spec Spec, pod *api.Pod, 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 *Spec, podUID types.UID) (Cleaner, error) + NewWrapperCleaner(volName string, spec Spec, podUID types.UID) (Cleaner, error) // Get cloud provider from kubelet. GetCloudProvider() cloudprovider.Interface diff --git a/pkg/volume/secret/secret.go b/pkg/volume/secret/secret.go index aa91a743a73..5f6d2d3e767 100644 --- a/pkg/volume/secret/secret.go +++ b/pkg/volume/secret/secret.go @@ -47,6 +47,10 @@ type secretPlugin struct { var _ volume.VolumePlugin = &secretPlugin{} +var wrappedVolumeSpec = volume.Spec{ + Volume: &api.Volume{VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{Medium: api.StorageMediumMemory}}}, +} + func (plugin *secretPlugin) Init(host volume.VolumeHost) error { plugin.host = host return nil @@ -62,14 +66,31 @@ func (plugin *secretPlugin) CanSupport(spec *volume.Spec) bool { func (plugin *secretPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) { return &secretVolumeBuilder{ - secretVolume: &secretVolume{spec.Name(), pod.UID, plugin, plugin.host.GetMounter(), plugin.host.GetWriter(), volume.MetricsNil{}}, - secretName: spec.Volume.Secret.SecretName, - pod: *pod, - opts: &opts}, nil + secretVolume: &secretVolume{ + spec.Name(), + pod.UID, + plugin, + plugin.host.GetMounter(), + plugin.host.GetWriter(), + volume.MetricsNil{}, + }, + secretName: spec.Volume.Secret.SecretName, + pod: *pod, + opts: &opts, + }, nil } func (plugin *secretPlugin) NewCleaner(volName string, podUID types.UID) (volume.Cleaner, error) { - return &secretVolumeCleaner{&secretVolume{volName, podUID, plugin, plugin.host.GetMounter(), plugin.host.GetWriter(), volume.MetricsNil{}}}, nil + return &secretVolumeCleaner{ + &secretVolume{ + volName, + podUID, + plugin, + plugin.host.GetMounter(), + plugin.host.GetWriter(), + volume.MetricsNil{}, + }, + }, nil } type secretVolume struct { @@ -111,11 +132,6 @@ func (b *secretVolumeBuilder) SetUp() error { return b.SetUpAt(b.GetPath()) } -// This is the spec for the volume that this plugin wraps. -var wrappedVolumeSpec = &volume.Spec{ - Volume: &api.Volume{VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{Medium: api.StorageMediumMemory}}}, -} - func (b *secretVolumeBuilder) getMetaDir() string { return path.Join(b.plugin.host.GetPodPluginDir(b.podUID, strings.EscapeQualifiedNameForDisk(secretPluginName)), b.volName) } @@ -137,7 +153,7 @@ func (b *secretVolumeBuilder) SetUpAt(dir string) error { glog.V(3).Infof("Setting up volume %v for pod %v at %v", b.volName, b.pod.UID, dir) // Wrap EmptyDir, let it do the setup. - wrapped, err := b.plugin.host.NewWrapperBuilder(wrappedVolumeSpec, &b.pod, *b.opts) + wrapped, err := b.plugin.host.NewWrapperBuilder(b.volName, wrappedVolumeSpec, &b.pod, *b.opts) if err != nil { return err } @@ -202,7 +218,7 @@ func (c *secretVolumeCleaner) TearDownAt(dir string) error { glog.V(3).Infof("Tearing down volume %v for pod %v at %v", c.volName, c.podUID, dir) // Wrap EmptyDir, let it do the teardown. - wrapped, err := c.plugin.host.NewWrapperCleaner(wrappedVolumeSpec, c.podUID) + wrapped, err := c.plugin.host.NewWrapperCleaner(c.volName, wrappedVolumeSpec, c.podUID) if err != nil { return err } diff --git a/pkg/volume/secret/secret_test.go b/pkg/volume/secret/secret_test.go index 5ccc6aa7654..654f3782fb8 100644 --- a/pkg/volume/secret/secret_test.go +++ b/pkg/volume/secret/secret_test.go @@ -70,11 +70,11 @@ func TestPlugin(t *testing.T) { testNamespace = "test_secret_namespace" testName = "test_secret_name" - volumeSpec = volumeSpec(testVolumeName, testName) - secret = secret(testNamespace, testName) - client = testclient.NewSimpleFake(&secret) - pluginMgr = volume.VolumePluginMgr{} - _, host = newTestHost(t, client) + volumeSpec = volumeSpec(testVolumeName, testName) + secret = secret(testNamespace, testName) + client = testclient.NewSimpleFake(&secret) + pluginMgr = volume.VolumePluginMgr{} + rootDir, host = newTestHost(t, client) ) pluginMgr.InitPlugins(ProbeVolumePlugins(), host) @@ -110,6 +110,16 @@ func TestPlugin(t *testing.T) { } } + // secret volume should create its own empty wrapper path + podWrapperMetadataDir := fmt.Sprintf("%v/pods/test_pod_uid/plugins/kubernetes.io~empty-dir/wrapped_test_volume_name", rootDir) + + if _, err := os.Stat(podWrapperMetadataDir); err != nil { + if os.IsNotExist(err) { + t.Errorf("SetUp() failed, empty-dir wrapper path is not created: %s", podWrapperMetadataDir) + } else { + t.Errorf("SetUp() failed: %v", err) + } + } doTestSecretDataInVolume(volumePath, secret, t) doTestCleanAndTeardown(plugin, testPodUID, testVolumeName, volumePath, t) } diff --git a/pkg/volume/testing.go b/pkg/volume/testing.go index 4a5dcd64423..d9d1f175a9b 100644 --- a/pkg/volume/testing.go +++ b/pkg/volume/testing.go @@ -81,16 +81,26 @@ func (f *fakeVolumeHost) GetWriter() io.Writer { return f.writer } -func (f *fakeVolumeHost) NewWrapperBuilder(spec *Spec, pod *api.Pod, opts VolumeOptions) (Builder, error) { - plug, err := f.pluginMgr.FindPluginBySpec(spec) +func (f *fakeVolumeHost) NewWrapperBuilder(volName string, spec Spec, pod *api.Pod, opts VolumeOptions) (Builder, error) { + // The name of wrapper volume is set to "wrapped_{wrapped_volume_name}" + wrapperVolumeName := "wrapped_" + volName + if spec.Volume != nil { + spec.Volume.Name = wrapperVolumeName + } + plug, err := f.pluginMgr.FindPluginBySpec(&spec) if err != nil { return nil, err } - return plug.NewBuilder(spec, pod, opts) + return plug.NewBuilder(&spec, pod, opts) } -func (f *fakeVolumeHost) NewWrapperCleaner(spec *Spec, podUID types.UID) (Cleaner, error) { - plug, err := f.pluginMgr.FindPluginBySpec(spec) +func (f *fakeVolumeHost) NewWrapperCleaner(volName string, spec Spec, podUID types.UID) (Cleaner, error) { + // The name of wrapper volume is set to "wrapped_{wrapped_volume_name}" + wrapperVolumeName := "wrapped_" + volName + if spec.Volume != nil { + spec.Volume.Name = wrapperVolumeName + } + plug, err := f.pluginMgr.FindPluginBySpec(&spec) if err != nil { return nil, err } diff --git a/test/e2e/empty_dir_wrapper.go b/test/e2e/empty_dir_wrapper.go new file mode 100644 index 00000000000..9a2208c19a1 --- /dev/null +++ b/test/e2e/empty_dir_wrapper.go @@ -0,0 +1,179 @@ +/* +Copyright 2015 The Kubernetes Authors 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 e2e + +import ( + "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/util" + "k8s.io/kubernetes/pkg/util/intstr" + + "strconv" + + . "github.com/onsi/ginkgo" +) + +// This test will create a pod with a secret volume and gitRepo volume +// Thus requests a secret, a git server pod, and a git server service +var _ = Describe("EmptyDir wrapper volumes", func() { + f := NewFramework("secrets") + + It("should becomes running [Conformance]", func() { + name := "secret-test-" + string(util.NewUUID()) + volumeName := "secret-volume" + volumeMountPath := "/etc/secret-volume" + + secret := &api.Secret{ + ObjectMeta: api.ObjectMeta{ + Namespace: f.Namespace.Name, + Name: name, + }, + Data: map[string][]byte{ + "data-1": []byte("value-1\n"), + }, + } + + var err error + if secret, err = f.Client.Secrets(f.Namespace.Name).Create(secret); err != nil { + Failf("unable to create test secret %s: %v", secret.Name, err) + } + + gitServerPodName := "git-server-" + string(util.NewUUID()) + containerPort := 8000 + + labels := map[string]string{"name": gitServerPodName} + + gitServerPod := &api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: gitServerPodName, + Labels: labels, + }, + Spec: api.PodSpec{ + Containers: []api.Container{ + { + Name: "git-repo", + Image: "gcr.io/google_containers/fakegitserver:0.1", + ImagePullPolicy: "IfNotPresent", + Ports: []api.ContainerPort{ + {ContainerPort: containerPort}, + }, + }, + }, + }, + } + + if gitServerPod, err = f.Client.Pods(f.Namespace.Name).Create(gitServerPod); err != nil { + Failf("unable to create test git server pod %s: %v", gitServerPod.Name, err) + } + + // Portal IP and port + httpPort := 2345 + + gitServerSvc := &api.Service{ + ObjectMeta: api.ObjectMeta{ + Name: "git-server-svc", + }, + Spec: api.ServiceSpec{ + Selector: labels, + Ports: []api.ServicePort{ + { + Name: "http-portal", + Port: httpPort, + TargetPort: intstr.FromInt(containerPort), + }, + }, + }, + } + + if gitServerSvc, err = f.Client.Services(f.Namespace.Name).Create(gitServerSvc); err != nil { + Failf("unable to create test git server service %s: %v", gitServerSvc.Name, err) + } + + gitVolumeName := "git-volume" + gitVolumeMountPath := "/etc/git-volume" + gitURL := "http://" + gitServerSvc.Spec.ClusterIP + ":" + strconv.Itoa(httpPort) + gitRepo := "test" + + pod := &api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: "pod-secrets-" + string(util.NewUUID()), + }, + Spec: api.PodSpec{ + Volumes: []api.Volume{ + { + Name: volumeName, + VolumeSource: api.VolumeSource{ + Secret: &api.SecretVolumeSource{ + SecretName: name, + }, + }, + }, + { + Name: gitVolumeName, + VolumeSource: api.VolumeSource{ + GitRepo: &api.GitRepoVolumeSource{ + Repository: gitURL, + Directory: gitRepo, + }, + }, + }, + }, + Containers: []api.Container{ + { + Name: "secret-test", + Image: "gcr.io/google_containers/test-webserver", + VolumeMounts: []api.VolumeMount{ + { + Name: volumeName, + MountPath: volumeMountPath, + ReadOnly: true, + }, + { + Name: gitVolumeName, + MountPath: gitVolumeMountPath, + }, + }, + }, + }, + }, + } + + if pod, err = f.Client.Pods(f.Namespace.Name).Create(pod); err != nil { + Failf("unable to create pod %v: %v", pod.Name, err) + } + + defer func() { + By("Cleaning up the secret") + if err := f.Client.Secrets(f.Namespace.Name).Delete(secret.Name); err != nil { + Failf("unable to delete secret %v: %v", secret.Name, err) + } + By("Cleaning up the git server pod") + if err = f.Client.Pods(f.Namespace.Name).Delete(gitServerPod.Name, api.NewDeleteOptions(0)); err != nil { + Failf("unable to delete git server pod %v: %v", gitServerPod.Name, err) + } + By("Cleaning up the git server svc") + if err = f.Client.Services(f.Namespace.Name).Delete(gitServerSvc.Name); err != nil { + Failf("unable to delete git server svc %v: %v", gitServerSvc.Name, err) + } + By("Cleaning up the git vol pod") + if err = f.Client.Pods(f.Namespace.Name).Delete(pod.Name, api.NewDeleteOptions(0)); err != nil { + Failf("unable to delete git vol pod %v: %v", pod.Name, err) + } + }() + + expectNoError(waitForPodRunningInNamespace(f.Client, pod.Name, f.Namespace.Name)) + }) +})