Fix volume wrapper doesn't have name

Integration test
This commit is contained in:
harry 2015-12-10 18:07:17 +08:00
parent 7ca0fa431b
commit c0d49450e4
8 changed files with 234 additions and 65 deletions

View File

@ -55,7 +55,10 @@ import (
"k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/util/wait"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/empty_dir" "k8s.io/kubernetes/pkg/volume/empty_dir"
"k8s.io/kubernetes/pkg/volume/git_repo"
"k8s.io/kubernetes/pkg/volume/secret"
"k8s.io/kubernetes/plugin/pkg/scheduler" "k8s.io/kubernetes/plugin/pkg/scheduler"
_ "k8s.io/kubernetes/plugin/pkg/scheduler/algorithmprovider" _ "k8s.io/kubernetes/plugin/pkg/scheduler/algorithmprovider"
"k8s.io/kubernetes/plugin/pkg/scheduler/factory" "k8s.io/kubernetes/plugin/pkg/scheduler/factory"
@ -211,7 +214,7 @@ func startComponents(firstManifestURL, secondManifestURL string) (string, string
10250, /* KubeletPort */ 10250, /* KubeletPort */
0, /* ReadOnlyPort */ 0, /* ReadOnlyPort */
api.NamespaceDefault, api.NamespaceDefault,
empty_dir.ProbeVolumePlugins(), probeVolumePlugins(),
nil, nil,
cadvisorInterface, cadvisorInterface,
configFilePath, configFilePath,
@ -244,7 +247,7 @@ func startComponents(firstManifestURL, secondManifestURL string) (string, string
10251, /* KubeletPort */ 10251, /* KubeletPort */
0, /* ReadOnlyPort */ 0, /* ReadOnlyPort */
api.NamespaceDefault, api.NamespaceDefault,
empty_dir.ProbeVolumePlugins(), probeVolumePlugins(),
nil, nil,
cadvisorInterface, cadvisorInterface,
"", "",
@ -265,6 +268,16 @@ func startComponents(firstManifestURL, secondManifestURL string) (string, string
return apiServer.URL, configFilePath return apiServer.URL, configFilePath
} }
// The list of plugins to probe in this test
func probeVolumePlugins() []volume.VolumePlugin {
allPlugins := []volume.VolumePlugin{}
allPlugins = append(allPlugins, empty_dir.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, git_repo.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, secret.ProbeVolumePlugins()...)
return allPlugins
}
func makeTempDirOrDie(prefix string, baseDir string) string { func makeTempDirOrDie(prefix string, baseDir string) string {
if baseDir == "" { if baseDir == "" {
baseDir = "/tmp" baseDir = "/tmp"
@ -989,6 +1002,7 @@ func main() {
runServiceTest, runServiceTest,
runAPIVersionsTest, runAPIVersionsTest,
runMasterServiceTest, runMasterServiceTest,
runWrapperVolumesPluginsTest,
func(c *client.Client) { func(c *client.Client) {
runSelfLinkTestOnNamespace(c, api.NamespaceDefault) runSelfLinkTestOnNamespace(c, api.NamespaceDefault)
runSelfLinkTestOnNamespace(c, "other") runSelfLinkTestOnNamespace(c, "other")
@ -1038,8 +1052,8 @@ func main() {
// 1 pod infra container + 1 container from the service test. // 1 pod infra container + 1 container from the service test.
// The total number of container created is 9 // The total number of container created is 9
if len(createdConts) != 12 { if len(createdConts) != 14 {
glog.Fatalf("Expected 12 containers; got %v\n\nlist of created containers:\n\n%#v\n\nDocker 1 Created:\n\n%#v\n\nDocker 2 Created:\n\n%#v\n\n", len(createdConts), createdConts.List(), fakeDocker1.Created, fakeDocker2.Created) glog.Fatalf("Expected 14 containers; got %v\n\nlist of created containers:\n\n%#v\n\nDocker 1 Created:\n\n%#v\n\nDocker 2 Created:\n\n%#v\n\n", len(createdConts), createdConts.List(), fakeDocker1.Created, fakeDocker2.Created)
} }
glog.Infof("OK - found created containers: %#v", createdConts.List()) glog.Infof("OK - found created containers: %#v", createdConts.List())
@ -1097,3 +1111,72 @@ const (
} }
}` }`
) )
// This is a test to make sure multiple empty_dir wrapper based volumes should not affect each other
func runWrapperVolumesPluginsTest(client *client.Client) {
// Make a secret object.
ns := api.NamespaceDefault
s := api.Secret{
ObjectMeta: api.ObjectMeta{
Name: "secret-name",
Namespace: ns,
},
Data: map[string][]byte{
"data": []byte("value1\n"),
},
}
if _, err := client.Secrets(s.Namespace).Create(&s); err != nil {
glog.Fatalf("unable to create test secret: %v", err)
}
pod := &api.Pod{
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "vol-container",
Image: "kubernetes/pause",
VolumeMounts: []api.VolumeMount{
{
Name: "vol-secret",
MountPath: "/fake/path-1",
ReadOnly: true,
},
{
Name: "vol-git",
MountPath: "/fake/path-2",
},
},
},
},
Volumes: []api.Volume{
{
Name: "vol-secret",
VolumeSource: api.VolumeSource{
Secret: &api.SecretVolumeSource{
SecretName: "secret-name",
},
},
},
{
Name: "vol-git",
VolumeSource: api.VolumeSource{
GitRepo: &api.GitRepoVolumeSource{
Repository: "https://github.com/kubernetes/kubedash",
},
},
},
},
},
}
pod.ObjectMeta.Name = "wrappedvolumes.foo"
foo, err := client.Pods(api.NamespaceDefault).Create(pod)
if err != nil {
glog.Fatalf("Failed to create pod: %v, %v", pod, err)
}
if err := wait.Poll(time.Second, longTestTimeout, podRunning(client, foo.Namespace, foo.Name)); err != nil {
glog.Fatalf("FAILED: pod never started running %v", err)
}
glog.Info("empty_dir wrapper based volumes doesn't affect each other: test passed.")
}

View File

@ -66,10 +66,11 @@ func (plugin *downwardAPIPlugin) CanSupport(spec *volume.Spec) bool {
func (plugin *downwardAPIPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) { func (plugin *downwardAPIPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) {
v := &downwardAPIVolume{ v := &downwardAPIVolume{
volName: spec.Name(), volName: spec.Name(),
pod: pod, pod: pod,
podUID: pod.UID, podUID: pod.UID,
plugin: plugin, plugin: plugin,
wrappedVolumeSpec: volume.GetWrappedVolumeSpec(spec.Name(), downwardAPIPluginName),
} }
v.fieldReferenceFileNames = make(map[string]string) v.fieldReferenceFileNames = make(map[string]string)
for _, fileInfo := range spec.Volume.DownwardAPI.Items { for _, fileInfo := range spec.Volume.DownwardAPI.Items {
@ -81,7 +82,12 @@ func (plugin *downwardAPIPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opt
} }
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,
wrappedVolumeSpec: volume.GetWrappedVolumeSpec(volName, downwardAPIPluginName)},
}, 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.
@ -92,11 +98,7 @@ type downwardAPIVolume struct {
podUID types.UID // TODO: remove this redundancy as soon NewCleaner func will have *api.POD and not only types.UID podUID types.UID // TODO: remove this redundancy as soon NewCleaner func will have *api.POD and not only types.UID
plugin *downwardAPIPlugin plugin *downwardAPIPlugin
volume.MetricsNil volume.MetricsNil
} wrappedVolumeSpec *volume.Spec
// 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
@ -130,7 +132,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.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 +366,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.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)
} }
// gitRepo volume should create it's 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

@ -61,9 +61,10 @@ func (plugin *gitRepoPlugin) CanSupport(spec *volume.Spec) bool {
func (plugin *gitRepoPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) { func (plugin *gitRepoPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opts volume.VolumeOptions) (volume.Builder, error) {
return &gitRepoVolumeBuilder{ return &gitRepoVolumeBuilder{
gitRepoVolume: &gitRepoVolume{ gitRepoVolume: &gitRepoVolume{
volName: spec.Name(), volName: spec.Name(),
podUID: pod.UID, podUID: pod.UID,
plugin: plugin, plugin: plugin,
wrappedVolumeSpec: volume.GetWrappedVolumeSpec(spec.Name(), gitRepoPluginName),
}, },
pod: *pod, pod: *pod,
source: spec.Volume.GitRepo.Repository, source: spec.Volume.GitRepo.Repository,
@ -77,9 +78,10 @@ func (plugin *gitRepoPlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, opts vo
func (plugin *gitRepoPlugin) NewCleaner(volName string, podUID types.UID) (volume.Cleaner, error) { func (plugin *gitRepoPlugin) NewCleaner(volName string, podUID types.UID) (volume.Cleaner, error) {
return &gitRepoVolumeCleaner{ return &gitRepoVolumeCleaner{
&gitRepoVolume{ &gitRepoVolume{
volName: volName, volName: volName,
podUID: podUID, podUID: podUID,
plugin: plugin, plugin: plugin,
wrappedVolumeSpec: volume.GetWrappedVolumeSpec(volName, gitRepoPluginName),
}, },
}, nil }, nil
} }
@ -87,9 +89,10 @@ func (plugin *gitRepoPlugin) NewCleaner(volName string, podUID types.UID) (volum
// gitRepo volumes are directories which are pre-filled from a git repository. // gitRepo volumes are directories which are pre-filled from a git repository.
// These do not persist beyond the lifetime of a pod. // These do not persist beyond the lifetime of a pod.
type gitRepoVolume struct { type gitRepoVolume struct {
volName string volName string
podUID types.UID podUID types.UID
plugin *gitRepoPlugin plugin *gitRepoPlugin
wrappedVolumeSpec *volume.Spec
volume.MetricsNil volume.MetricsNil
} }
@ -128,11 +131,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 +138,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.wrappedVolumeSpec, &b.pod, b.opts)
if err != nil { if err != nil {
return err return err
} }
@ -218,8 +216,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.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 it's 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

@ -62,14 +62,33 @@ 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{},
volume.GetWrappedVolumeSpec(spec.Name(), secretPluginName),
},
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{},
volume.GetWrappedVolumeSpec(volName, secretPluginName),
},
}, nil
} }
type secretVolume struct { type secretVolume struct {
@ -79,6 +98,7 @@ type secretVolume struct {
mounter mount.Interface mounter mount.Interface
writer ioutil.Writer writer ioutil.Writer
volume.MetricsNil volume.MetricsNil
wrappedVolumeSpec *volume.Spec
} }
var _ volume.Volume = &secretVolume{} var _ volume.Volume = &secretVolume{}
@ -111,11 +131,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, util.EscapeQualifiedNameForDisk(secretPluginName)), b.volName) return path.Join(b.plugin.host.GetPodPluginDir(b.podUID, util.EscapeQualifiedNameForDisk(secretPluginName)), b.volName)
} }
@ -137,7 +152,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.wrappedVolumeSpec, &b.pod, *b.opts)
if err != nil { if err != nil {
return err return err
} }
@ -202,7 +217,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.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 it's 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

@ -17,6 +17,7 @@ limitations under the License.
package volume package volume
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/resource"
@ -24,6 +25,10 @@ import (
"path" "path"
) )
const (
randomLength = 5
)
// Volume represents a directory used by pods or hosts on a node. // Volume represents a directory used by pods or hosts on a node.
// All method implementations of methods in the volume interface must be idempotent. // All method implementations of methods in the volume interface must be idempotent.
type Volume interface { type Volume interface {
@ -132,3 +137,22 @@ func RenameDirectory(oldPath, newName string) (string, error) {
} }
return newPath, nil return newPath, nil
} }
// Return the wrapper volume spec of specific volume plugin
func GetWrappedVolumeSpec(volName string, pluginName string) *Spec {
// The name of wrapper volume is set to "wrapped_{wrapped_volume_name}"
wrapperVolumeName := fmt.Sprintf("wrapped_%v", volName)
var volumeSpec *Spec
switch pluginName {
case "kubernetes.io/downward-api", "kubernetes.io/secret":
volumeSpec = &Spec{
Volume: &api.Volume{Name: wrapperVolumeName, VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{Medium: api.StorageMediumMemory}}},
}
case "kubernetes.io/git-repo":
volumeSpec = &Spec{
Volume: &api.Volume{Name: wrapperVolumeName, VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}},
}
}
return volumeSpec
}