Merge pull request #18445 from resouer/fix-emptydir

Auto commit by PR queue bot
This commit is contained in:
k8s-merge-robot 2016-01-26 02:45:54 -08:00
commit 52cb4c1d9d
13 changed files with 334 additions and 65 deletions

View File

@ -473,11 +473,11 @@ func (c *PersistentVolumeProvisionerController) GetKubeClient() client.Interface
return c.client.GetKubeClient() 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") 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") return nil, fmt.Errorf("NewWrapperCleaner not supported by PVClaimBinder's VolumeHost implementation")
} }

View File

@ -291,11 +291,11 @@ func (f *PersistentVolumeRecycler) GetKubeClient() client.Interface {
return f.kubeClient 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") 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") return nil, fmt.Errorf("NewWrapperCleaner not supported by PVClaimBinder's VolumeHost implementation")
} }

View File

@ -58,16 +58,28 @@ func (vh *volumeHost) GetKubeClient() client.Interface {
return vh.kubelet.kubeClient return vh.kubelet.kubeClient
} }
func (vh *volumeHost) NewWrapperBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) { func (vh *volumeHost) NewWrapperBuilder(volName string, spec volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) {
b, err := vh.kubelet.newVolumeBuilderFromPlugins(spec, pod, opts) // 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 { if err == nil && b == nil {
return nil, errUnsupportedVolumeType return nil, errUnsupportedVolumeType
} }
return b, nil return b, nil
} }
func (vh *volumeHost) NewWrapperCleaner(spec *volume.Spec, podUID types.UID) (volume.Cleaner, error) { func (vh *volumeHost) NewWrapperCleaner(volName string, spec volume.Spec, podUID types.UID) (volume.Cleaner, error) {
plugin, err := vh.kubelet.volumePluginMgr.FindPluginBySpec(spec) // 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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -51,6 +51,10 @@ type downwardAPIPlugin struct {
var _ volume.VolumePlugin = &downwardAPIPlugin{} 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 { func (plugin *downwardAPIPlugin) Init(host volume.VolumeHost) error {
plugin.host = host plugin.host = host
return nil return nil
@ -77,11 +81,18 @@ func (plugin *downwardAPIPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opt
} }
return &downwardAPIVolumeBuilder{ return &downwardAPIVolumeBuilder{
downwardAPIVolume: v, downwardAPIVolume: v,
opts: &opts}, nil opts: &opts,
}, nil
} }
func (plugin *downwardAPIPlugin) NewCleaner(volName string, podUID types.UID) (volume.Cleaner, error) { 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. // downwardAPIVolume retrieves downward API data and placing them into the volume on the host.
@ -94,11 +105,6 @@ type downwardAPIVolume struct {
volume.MetricsNil 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 // downwardAPIVolumeBuilder fetches info from downward API from the pod
// and dumps it in files // and dumps it in files
type downwardAPIVolumeBuilder struct { type downwardAPIVolumeBuilder struct {
@ -130,7 +136,7 @@ func (b *downwardAPIVolumeBuilder) SetUp() error {
func (b *downwardAPIVolumeBuilder) SetUpAt(dir string) 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) 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 // 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 { 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()) 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 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) 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. // 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 { if err != nil {
return err return err
} }

View File

@ -39,12 +39,12 @@ func formatMap(m map[string]string) (fmtstr string) {
return 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.") tempDir, err := ioutil.TempDir(basePath, "downwardApi_volume_test.")
if err != nil { if err != nil {
t.Fatalf("can't make a temp rootdir: %v", err) 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) { func TestCanSupport(t *testing.T) {
@ -54,7 +54,8 @@ func TestCanSupport(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
pluginMgr := volume.VolumePluginMgr{} pluginMgr := volume.VolumePluginMgr{}
pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, nil, tmpDir)) _, host := newTestHost(t, nil, tmpDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host)
plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName)
if err != nil { if err != nil {
@ -110,7 +111,8 @@ func TestLabels(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
pluginMgr := volume.VolumePluginMgr{} 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) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName)
volumeSpec := &api.Volume{ volumeSpec := &api.Volume{
Name: testVolumeName, Name: testVolumeName,
@ -141,6 +143,17 @@ func TestLabels(t *testing.T) {
t.Errorf("Failed to setup volume: %v", err) 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 var data []byte
data, err = ioutil.ReadFile(path.Join(volumePath, "labels")) data, err = ioutil.ReadFile(path.Join(volumePath, "labels"))
if err != nil { if err != nil {
@ -189,7 +202,8 @@ func TestAnnotations(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
pluginMgr := volume.VolumePluginMgr{} pluginMgr := volume.VolumePluginMgr{}
pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) _, host := newTestHost(t, fake, tmpDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host)
plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName)
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
@ -254,7 +268,8 @@ func TestName(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
pluginMgr := volume.VolumePluginMgr{} pluginMgr := volume.VolumePluginMgr{}
pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) _, host := newTestHost(t, fake, tmpDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host)
plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName)
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
@ -320,7 +335,8 @@ func TestNamespace(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
pluginMgr := volume.VolumePluginMgr{} pluginMgr := volume.VolumePluginMgr{}
pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) _, host := newTestHost(t, fake, tmpDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host)
plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName)
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")
@ -379,7 +395,8 @@ func TestWriteTwiceNoUpdate(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
pluginMgr := volume.VolumePluginMgr{} pluginMgr := volume.VolumePluginMgr{}
pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) _, host := newTestHost(t, fake, tmpDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host)
plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName)
volumeSpec := &api.Volume{ volumeSpec := &api.Volume{
Name: testVolumeName, Name: testVolumeName,
@ -468,7 +485,8 @@ func TestWriteTwiceWithUpdate(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
pluginMgr := volume.VolumePluginMgr{} pluginMgr := volume.VolumePluginMgr{}
pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) _, host := newTestHost(t, fake, tmpDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host)
plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName)
volumeSpec := &api.Volume{ volumeSpec := &api.Volume{
Name: testVolumeName, Name: testVolumeName,
@ -577,7 +595,8 @@ func TestWriteWithUnixPath(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
pluginMgr := volume.VolumePluginMgr{} pluginMgr := volume.VolumePluginMgr{}
pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) _, host := newTestHost(t, fake, tmpDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host)
plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName)
volumeSpec := &api.Volume{ volumeSpec := &api.Volume{
Name: testVolumeName, Name: testVolumeName,
@ -656,7 +675,8 @@ func TestWriteWithUnixPathBadPath(t *testing.T) {
} }
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
pluginMgr := volume.VolumePluginMgr{} pluginMgr := volume.VolumePluginMgr{}
pluginMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t, fake, tmpDir)) _, host := newTestHost(t, fake, tmpDir)
pluginMgr.InitPlugins(ProbeVolumePlugins(), host)
plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName) plugin, err := pluginMgr.FindPluginByName(downwardAPIPluginName)
if err != nil { if err != nil {
t.Errorf("Can't find the plugin by name") t.Errorf("Can't find the plugin by name")

View File

@ -41,6 +41,10 @@ type gitRepoPlugin struct {
var _ volume.VolumePlugin = &gitRepoPlugin{} var _ volume.VolumePlugin = &gitRepoPlugin{}
var wrappedVolumeSpec = volume.Spec{
Volume: &api.Volume{VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
}
const ( const (
gitRepoPluginName = "kubernetes.io/git-repo" gitRepoPluginName = "kubernetes.io/git-repo"
) )
@ -128,11 +132,6 @@ func (b *gitRepoVolumeBuilder) SetUp() error {
return b.SetUpAt(b.GetPath()) 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. // SetUpAt creates new directory and clones a git repo.
func (b *gitRepoVolumeBuilder) SetUpAt(dir string) error { func (b *gitRepoVolumeBuilder) SetUpAt(dir string) error {
if volumeutil.IsReady(b.getMetaDir()) { if volumeutil.IsReady(b.getMetaDir()) {
@ -140,7 +139,7 @@ func (b *gitRepoVolumeBuilder) SetUpAt(dir string) error {
} }
// Wrap EmptyDir, let it do the setup. // 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 { if err != nil {
return err return err
} }
@ -218,8 +217,9 @@ func (c *gitRepoVolumeCleaner) TearDown() error {
// TearDownAt simply deletes everything in the directory. // TearDownAt simply deletes everything in the directory.
func (c *gitRepoVolumeCleaner) TearDownAt(dir string) error { func (c *gitRepoVolumeCleaner) TearDownAt(dir string) error {
// Wrap EmptyDir, let it do the teardown. // 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 { if err != nil {
return err return err
} }

View File

@ -32,17 +32,18 @@ import (
"k8s.io/kubernetes/pkg/volume/empty_dir" "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.") tempDir, err := ioutil.TempDir("/tmp", "git_repo_test.")
if err != nil { if err != nil {
t.Fatalf("can't make a temp rootdir: %v", err) 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) { func TestCanSupport(t *testing.T) {
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t)) _, host := newTestHost(t)
plugMgr.InitPlugins(ProbeVolumePlugins(), host)
plug, err := plugMgr.FindPluginByName("kubernetes.io/git-repo") plug, err := plugMgr.FindPluginByName("kubernetes.io/git-repo")
if err != nil { if err != nil {
@ -218,7 +219,8 @@ func doTestPlugin(scenario struct {
allErrs := []error{} allErrs := []error{}
plugMgr := volume.VolumePluginMgr{} plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), newTestHost(t)) rootDir, host := newTestHost(t)
plugMgr.InitPlugins(ProbeVolumePlugins(), host)
plug, err := plugMgr.FindPluginByName("kubernetes.io/git-repo") plug, err := plugMgr.FindPluginByName("kubernetes.io/git-repo")
if err != nil { if err != nil {
@ -241,7 +243,8 @@ func doTestPlugin(scenario struct {
} }
path := builder.GetPath() 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, allErrs = append(allErrs,
fmt.Errorf("Got unexpected path: %s", path)) fmt.Errorf("Got unexpected path: %s", path))
return allErrs 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")) cleaner, err := plug.NewCleaner("vol1", types.UID("poduid"))
if err != nil { if err != nil {
allErrs = append(allErrs, allErrs = append(allErrs,

View File

@ -80,7 +80,7 @@ func (plugin *persistentClaimPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod,
return nil, err 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 { if err != nil {
glog.Errorf("Error creating builder for claim: %+v\n", claim.Name) glog.Errorf("Error creating builder for claim: %+v\n", claim.Name)
return nil, err return nil, err

View File

@ -144,12 +144,12 @@ type VolumeHost interface {
// the provided spec. This is used to implement volume plugins which // the provided spec. This is used to implement volume plugins which
// "wrap" other plugins. For example, the "secret" volume is // "wrap" other plugins. For example, the "secret" volume is
// implemented in terms of the "emptyDir" volume. // 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 // NewWrapperCleaner finds an appropriate plugin with which to handle
// the provided spec. See comments on NewWrapperBuilder for more // the provided spec. See comments on NewWrapperBuilder for more
// context. // context.
NewWrapperCleaner(spec *Spec, podUID types.UID) (Cleaner, error) NewWrapperCleaner(volName string, spec Spec, podUID types.UID) (Cleaner, error)
// Get cloud provider from kubelet. // Get cloud provider from kubelet.
GetCloudProvider() cloudprovider.Interface GetCloudProvider() cloudprovider.Interface

View File

@ -47,6 +47,10 @@ type secretPlugin struct {
var _ volume.VolumePlugin = &secretPlugin{} 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 { func (plugin *secretPlugin) Init(host volume.VolumeHost) error {
plugin.host = host plugin.host = host
return nil 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) { func (plugin *secretPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) {
return &secretVolumeBuilder{ return &secretVolumeBuilder{
secretVolume: &secretVolume{spec.Name(), pod.UID, plugin, plugin.host.GetMounter(), plugin.host.GetWriter(), volume.MetricsNil{}}, secretVolume: &secretVolume{
secretName: spec.Volume.Secret.SecretName, spec.Name(),
pod: *pod, pod.UID,
opts: &opts}, nil 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) { 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 { type secretVolume struct {
@ -111,11 +132,6 @@ func (b *secretVolumeBuilder) SetUp() error {
return b.SetUpAt(b.GetPath()) 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 { func (b *secretVolumeBuilder) getMetaDir() string {
return path.Join(b.plugin.host.GetPodPluginDir(b.podUID, strings.EscapeQualifiedNameForDisk(secretPluginName)), b.volName) 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) 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. // 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 { if err != nil {
return err 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) 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. // 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 { if err != nil {
return err return err
} }

View File

@ -70,11 +70,11 @@ func TestPlugin(t *testing.T) {
testNamespace = "test_secret_namespace" testNamespace = "test_secret_namespace"
testName = "test_secret_name" testName = "test_secret_name"
volumeSpec = volumeSpec(testVolumeName, testName) volumeSpec = volumeSpec(testVolumeName, testName)
secret = secret(testNamespace, testName) secret = secret(testNamespace, testName)
client = testclient.NewSimpleFake(&secret) client = testclient.NewSimpleFake(&secret)
pluginMgr = volume.VolumePluginMgr{} pluginMgr = volume.VolumePluginMgr{}
_, host = newTestHost(t, client) rootDir, host = newTestHost(t, client)
) )
pluginMgr.InitPlugins(ProbeVolumePlugins(), host) 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) doTestSecretDataInVolume(volumePath, secret, t)
doTestCleanAndTeardown(plugin, testPodUID, testVolumeName, volumePath, t) doTestCleanAndTeardown(plugin, testPodUID, testVolumeName, volumePath, t)
} }

View File

@ -81,16 +81,26 @@ func (f *fakeVolumeHost) GetWriter() io.Writer {
return f.writer return f.writer
} }
func (f *fakeVolumeHost) NewWrapperBuilder(spec *Spec, pod *api.Pod, opts VolumeOptions) (Builder, error) { func (f *fakeVolumeHost) NewWrapperBuilder(volName string, spec Spec, pod *api.Pod, opts VolumeOptions) (Builder, error) {
plug, err := f.pluginMgr.FindPluginBySpec(spec) // 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 { if err != nil {
return nil, err 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) { func (f *fakeVolumeHost) NewWrapperCleaner(volName string, spec Spec, podUID types.UID) (Cleaner, error) {
plug, err := f.pluginMgr.FindPluginBySpec(spec) // 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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -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))
})
})