mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 06:27:05 +00:00
Merge pull request #5166 from thockin/tmpfs
Add tmpfs support as a flag on emptyDir
This commit is contained in:
commit
efcde725cc
@ -182,12 +182,29 @@ type VolumeSource struct {
|
||||
Secret *SecretVolumeSource `json:"secret"`
|
||||
}
|
||||
|
||||
// HostPathVolumeSource represents bare host directory volume.
|
||||
// HostPathVolumeSource represents a host directory mapped into a pod.
|
||||
type HostPathVolumeSource struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type EmptyDirVolumeSource struct{}
|
||||
// EmptyDirVolumeSource represents an empty directory for a pod.
|
||||
type EmptyDirVolumeSource struct {
|
||||
// TODO: Longer term we want to represent the selection of underlying
|
||||
// media more like a scheduling problem - user says what traits they
|
||||
// need, we give them a backing store that satisifies that. For now
|
||||
// this will cover the most common needs.
|
||||
// Optional: what type of storage medium should back this directory.
|
||||
// The default is "" which means to use the node's default medium.
|
||||
Medium StorageType `json:"medium"`
|
||||
}
|
||||
|
||||
// StorageType defines ways that storage can be allocated to a volume.
|
||||
type StorageType string
|
||||
|
||||
const (
|
||||
StorageTypeDefault StorageType = "" // use whatever the default is for the node
|
||||
StorageTypeMemory StorageType = "Memory" // use memory (tmpfs)
|
||||
)
|
||||
|
||||
// Protocol defines network protocols supported for things like conatiner ports.
|
||||
type Protocol string
|
||||
|
@ -112,7 +112,19 @@ type HostPathVolumeSource struct {
|
||||
Path string `json:"path" description:"path of the directory on the host"`
|
||||
}
|
||||
|
||||
type EmptyDirVolumeSource struct{}
|
||||
type EmptyDirVolumeSource struct {
|
||||
// Optional: what type of storage medium should back this directory.
|
||||
// The default is "" which means to use the node's default medium.
|
||||
Medium StorageType `json:"medium" description:"type of storage used to back the volume; must be an empty string (default) or Memory"`
|
||||
}
|
||||
|
||||
// StorageType defines ways that storage can be allocated to a volume.
|
||||
type StorageType string
|
||||
|
||||
const (
|
||||
StorageTypeDefault StorageType = "" // use whatever the default is for the node
|
||||
StorageTypeMemory StorageType = "Memory" // use memory (tmpfs)
|
||||
)
|
||||
|
||||
// Protocol defines network protocols supported for things like conatiner ports.
|
||||
type Protocol string
|
||||
|
@ -90,7 +90,19 @@ type HostPathVolumeSource struct {
|
||||
// Represents an empty directory volume.
|
||||
//
|
||||
// https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/volumes.md#emptydir
|
||||
type EmptyDirVolumeSource struct{}
|
||||
type EmptyDirVolumeSource struct {
|
||||
// Optional: what type of storage medium should back this directory.
|
||||
// The default is "" which means to use the node's default medium.
|
||||
Medium StorageType `json:"medium" description:"type of storage used to back the volume; must be an empty string (default) or Memory"`
|
||||
}
|
||||
|
||||
// StorageType defines ways that storage can be allocated to a volume.
|
||||
type StorageType string
|
||||
|
||||
const (
|
||||
StorageTypeDefault StorageType = "" // use whatever the default is for the node
|
||||
StorageTypeMemory StorageType = "Memory" // use memory (tmpfs)
|
||||
)
|
||||
|
||||
// SecretVolumeSource adapts a Secret into a VolumeSource
|
||||
//
|
||||
|
@ -206,7 +206,19 @@ type HostPathVolumeSource struct {
|
||||
Path string `json:"path" description:"path of the directory on the host"`
|
||||
}
|
||||
|
||||
type EmptyDirVolumeSource struct{}
|
||||
type EmptyDirVolumeSource struct {
|
||||
// Optional: what type of storage medium should back this directory.
|
||||
// The default is "" which means to use the node's default medium.
|
||||
Medium StorageType `json:"medium" description:"type of storage used to back the volume; must be an empty string (default) or Memory"`
|
||||
}
|
||||
|
||||
// StorageType defines ways that storage can be allocated to a volume.
|
||||
type StorageType string
|
||||
|
||||
const (
|
||||
StorageTypeDefault StorageType = "" // use whatever the default is for the node
|
||||
StorageTypeMemory StorageType = "Memory" // use memory (tmpfs)
|
||||
)
|
||||
|
||||
// Protocol defines network protocols supported for things like conatiner ports.
|
||||
type Protocol string
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/mount"
|
||||
)
|
||||
|
||||
// This is the primary entrypoint for volume plugins.
|
||||
@ -70,26 +71,83 @@ func (plugin *emptyDirPlugin) CanSupport(spec *api.Volume) bool {
|
||||
}
|
||||
|
||||
func (plugin *emptyDirPlugin) NewBuilder(spec *api.Volume, podRef *api.ObjectReference) (volume.Builder, error) {
|
||||
// Inject real implementations here, test through the internal function.
|
||||
return plugin.newBuilderInternal(spec, podRef, mount.New(), &realMediumer{})
|
||||
}
|
||||
|
||||
func (plugin *emptyDirPlugin) newBuilderInternal(spec *api.Volume, podRef *api.ObjectReference, mounter mount.Interface, mediumer mediumer) (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")
|
||||
}
|
||||
return &emptyDir{podRef.UID, spec.Name, plugin, false}, nil
|
||||
medium := api.StorageTypeDefault
|
||||
if spec.EmptyDir != nil { // Support a non-specified source as EmptyDir.
|
||||
medium = spec.EmptyDir.Medium
|
||||
}
|
||||
return &emptyDir{
|
||||
podUID: podRef.UID,
|
||||
volName: spec.Name,
|
||||
medium: medium,
|
||||
mediumer: mediumer,
|
||||
mounter: mounter,
|
||||
plugin: plugin,
|
||||
legacyMode: false,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (plugin *emptyDirPlugin) NewCleaner(volName string, podUID types.UID) (volume.Cleaner, error) {
|
||||
// Inject real implementations here, test through the internal function.
|
||||
return plugin.newCleanerInternal(volName, podUID, mount.New(), &realMediumer{})
|
||||
}
|
||||
|
||||
func (plugin *emptyDirPlugin) newCleanerInternal(volName string, podUID types.UID, mounter mount.Interface, mediumer mediumer) (volume.Cleaner, error) {
|
||||
legacy := false
|
||||
if plugin.legacyMode {
|
||||
legacy = true
|
||||
}
|
||||
return &emptyDir{podUID, volName, plugin, legacy}, nil
|
||||
ed := &emptyDir{
|
||||
podUID: podUID,
|
||||
volName: volName,
|
||||
medium: api.StorageTypeDefault, // might be changed later
|
||||
mounter: mounter,
|
||||
mediumer: mediumer,
|
||||
plugin: plugin,
|
||||
legacyMode: legacy,
|
||||
}
|
||||
// Figure out the medium.
|
||||
if medium, err := mediumer.GetMedium(ed.GetPath()); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
switch medium {
|
||||
case mediumMemory:
|
||||
ed.medium = api.StorageTypeMemory
|
||||
default:
|
||||
// assume StorageTypeDefault
|
||||
}
|
||||
}
|
||||
return ed, nil
|
||||
}
|
||||
|
||||
// mediumer abstracts how to find what storageMedium a path is backed by.
|
||||
type mediumer interface {
|
||||
GetMedium(path string) (storageMedium, error)
|
||||
}
|
||||
|
||||
type storageMedium int
|
||||
|
||||
const (
|
||||
mediumUnknown storageMedium = 0 // assume anything we don't explicitly handle is this
|
||||
mediumMemory storageMedium = 1 // memory (e.g. tmpfs on linux)
|
||||
)
|
||||
|
||||
// EmptyDir volumes are temporary directories exposed to the pod.
|
||||
// These do not persist beyond the lifetime of a pod.
|
||||
type emptyDir struct {
|
||||
podUID types.UID
|
||||
volName string
|
||||
medium api.StorageType
|
||||
mounter mount.Interface
|
||||
mediumer mediumer
|
||||
plugin *emptyDirPlugin
|
||||
legacyMode bool
|
||||
}
|
||||
@ -99,8 +157,34 @@ func (ed *emptyDir) SetUp() error {
|
||||
if ed.legacyMode {
|
||||
return fmt.Errorf("legacy mode: can not create new instances")
|
||||
}
|
||||
path := ed.GetPath()
|
||||
return os.MkdirAll(path, 0750)
|
||||
switch ed.medium {
|
||||
case api.StorageTypeDefault:
|
||||
return ed.setupDefault()
|
||||
case api.StorageTypeMemory:
|
||||
return ed.setupTmpfs()
|
||||
default:
|
||||
return fmt.Errorf("unknown storage medium %q", ed.medium)
|
||||
}
|
||||
}
|
||||
|
||||
func (ed *emptyDir) setupDefault() error {
|
||||
return os.MkdirAll(ed.GetPath(), 0750)
|
||||
}
|
||||
|
||||
func (ed *emptyDir) setupTmpfs() error {
|
||||
if ed.mounter == nil {
|
||||
return fmt.Errorf("memory storage requested, but mounter is nil")
|
||||
}
|
||||
if err := os.MkdirAll(ed.GetPath(), 0750); err != nil {
|
||||
return err
|
||||
}
|
||||
// Make SetUp idempotent.
|
||||
if medium, err := ed.mediumer.GetMedium(ed.GetPath()); err != nil {
|
||||
return err
|
||||
} else if medium == mediumMemory {
|
||||
return nil // current state is what we expect
|
||||
}
|
||||
return ed.mounter.Mount("tmpfs", ed.GetPath(), "tmpfs", 0, "")
|
||||
}
|
||||
|
||||
func (ed *emptyDir) GetPath() string {
|
||||
@ -111,8 +195,19 @@ func (ed *emptyDir) GetPath() string {
|
||||
return ed.plugin.host.GetPodVolumeDir(ed.podUID, volume.EscapePluginName(name), ed.volName)
|
||||
}
|
||||
|
||||
// TearDown simply deletes everything in the directory.
|
||||
// TearDown simply discards everything in the directory.
|
||||
func (ed *emptyDir) TearDown() error {
|
||||
switch ed.medium {
|
||||
case api.StorageTypeDefault:
|
||||
return ed.teardownDefault()
|
||||
case api.StorageTypeMemory:
|
||||
return ed.teardownTmpfs()
|
||||
default:
|
||||
return fmt.Errorf("unknown storage medium %q", ed.medium)
|
||||
}
|
||||
}
|
||||
|
||||
func (ed *emptyDir) teardownDefault() error {
|
||||
tmpDir, err := volume.RenameDirectory(ed.GetPath(), ed.volName+".deleting~")
|
||||
if err != nil {
|
||||
return err
|
||||
@ -123,3 +218,16 @@ func (ed *emptyDir) TearDown() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ed *emptyDir) teardownTmpfs() error {
|
||||
if ed.mounter == nil {
|
||||
return fmt.Errorf("memory storage requested, but mounter is nil")
|
||||
}
|
||||
if err := ed.mounter.Unmount(ed.GetPath(), 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.RemoveAll(ed.GetPath()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
39
pkg/kubelet/volume/empty_dir/empty_dir_linux.go
Normal file
39
pkg/kubelet/volume/empty_dir/empty_dir_linux.go
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
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 empty_dir
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Defined by Linux - the type number for tmpfs mounts.
|
||||
const linuxTmpfsMagic = 0x01021994
|
||||
|
||||
// realMediumer implements mediumer in terms of syscalls.
|
||||
type realMediumer struct{}
|
||||
|
||||
func (m *realMediumer) GetMedium(path string) (storageMedium, error) {
|
||||
buf := syscall.Statfs_t{}
|
||||
if err := syscall.Statfs(path, &buf); err != nil {
|
||||
return 0, fmt.Errorf("statfs(%q): %v", path, err)
|
||||
}
|
||||
if buf.Type == linuxTmpfsMagic {
|
||||
return mediumMemory, nil
|
||||
}
|
||||
return mediumUnknown, nil
|
||||
}
|
@ -18,21 +18,33 @@ package empty_dir
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/mount"
|
||||
)
|
||||
|
||||
func TestCanSupport(t *testing.T) {
|
||||
plugMgr := volume.PluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), &volume.FakeHost{"/tmp/fake", nil})
|
||||
// The dir where volumes will be stored.
|
||||
const basePath = "/tmp/fake"
|
||||
|
||||
plug, err := plugMgr.FindPluginByName("kubernetes.io/empty-dir")
|
||||
// Construct an instance of a plugin, by name.
|
||||
func makePluginUnderTest(t *testing.T, plugName string) volume.Plugin {
|
||||
plugMgr := volume.PluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), &volume.FakeHost{basePath, nil})
|
||||
|
||||
plug, err := plugMgr.FindPluginByName(plugName)
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
return plug
|
||||
}
|
||||
|
||||
func TestCanSupport(t *testing.T) {
|
||||
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir")
|
||||
|
||||
if plug.Name() != "kubernetes.io/empty-dir" {
|
||||
t.Errorf("Wrong name: %s", plug.Name())
|
||||
}
|
||||
@ -44,19 +56,24 @@ func TestCanSupport(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlugin(t *testing.T) {
|
||||
plugMgr := volume.PluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), &volume.FakeHost{"/tmp/fake", nil})
|
||||
type fakeMediumer struct {
|
||||
typeToReturn storageMedium
|
||||
}
|
||||
|
||||
func (fake *fakeMediumer) GetMedium(path string) (storageMedium, error) {
|
||||
return fake.typeToReturn, nil
|
||||
}
|
||||
|
||||
func TestPlugin(t *testing.T) {
|
||||
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir")
|
||||
|
||||
plug, err := plugMgr.FindPluginByName("kubernetes.io/empty-dir")
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
spec := &api.Volume{
|
||||
Name: "vol1",
|
||||
VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}},
|
||||
VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{Medium: api.StorageTypeDefault}},
|
||||
}
|
||||
builder, err := plug.NewBuilder(spec, &api.ObjectReference{UID: types.UID("poduid")})
|
||||
mounter := mount.FakeMounter{}
|
||||
mediumer := fakeMediumer{}
|
||||
builder, err := plug.(*emptyDirPlugin).newBuilderInternal(spec, &api.ObjectReference{UID: types.UID("poduid")}, &mounter, &mediumer)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to make a new Builder: %v", err)
|
||||
}
|
||||
@ -64,23 +81,27 @@ func TestPlugin(t *testing.T) {
|
||||
t.Errorf("Got a nil Builder: %v")
|
||||
}
|
||||
|
||||
path := builder.GetPath()
|
||||
if path != "/tmp/fake/pods/poduid/volumes/kubernetes.io~empty-dir/vol1" {
|
||||
t.Errorf("Got unexpected path: %s", path)
|
||||
volPath := builder.GetPath()
|
||||
if volPath != path.Join(basePath, "pods/poduid/volumes/kubernetes.io~empty-dir/vol1") {
|
||||
t.Errorf("Got unexpected path: %s", volPath)
|
||||
}
|
||||
|
||||
if err := builder.SetUp(); err != nil {
|
||||
t.Errorf("Expected success, got: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
if _, err := os.Stat(volPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
t.Errorf("SetUp() failed, volume path not created: %s", path)
|
||||
t.Errorf("SetUp() failed, volume path not created: %s", volPath)
|
||||
} else {
|
||||
t.Errorf("SetUp() failed: %v", err)
|
||||
}
|
||||
}
|
||||
if len(mounter.Log) != 0 {
|
||||
t.Errorf("Expected 0 mounter calls, got %#v", mounter.Log)
|
||||
}
|
||||
mounter.ResetLog()
|
||||
|
||||
cleaner, err := plug.NewCleaner("vol1", types.UID("poduid"))
|
||||
cleaner, err := plug.(*emptyDirPlugin).newCleanerInternal("vol1", types.UID("poduid"), &mounter, &fakeMediumer{})
|
||||
if err != nil {
|
||||
t.Errorf("Failed to make a new Cleaner: %v", err)
|
||||
}
|
||||
@ -91,21 +112,87 @@ func TestPlugin(t *testing.T) {
|
||||
if err := cleaner.TearDown(); err != nil {
|
||||
t.Errorf("Expected success, got: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
t.Errorf("TearDown() failed, volume path still exists: %s", path)
|
||||
if _, err := os.Stat(volPath); err == nil {
|
||||
t.Errorf("TearDown() failed, volume path still exists: %s", volPath)
|
||||
} else if !os.IsNotExist(err) {
|
||||
t.Errorf("SetUp() failed: %v", err)
|
||||
}
|
||||
if len(mounter.Log) != 0 {
|
||||
t.Errorf("Expected 0 mounter calls, got %#v", mounter.Log)
|
||||
}
|
||||
mounter.ResetLog()
|
||||
}
|
||||
|
||||
func TestPluginTmpfs(t *testing.T) {
|
||||
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir")
|
||||
|
||||
spec := &api.Volume{
|
||||
Name: "vol1",
|
||||
VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{Medium: api.StorageTypeMemory}},
|
||||
}
|
||||
mounter := mount.FakeMounter{}
|
||||
mediumer := fakeMediumer{}
|
||||
builder, err := plug.(*emptyDirPlugin).newBuilderInternal(spec, &api.ObjectReference{UID: types.UID("poduid")}, &mounter, &mediumer)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to make a new Builder: %v", err)
|
||||
}
|
||||
if builder == nil {
|
||||
t.Errorf("Got a nil Builder: %v")
|
||||
}
|
||||
|
||||
volPath := builder.GetPath()
|
||||
if volPath != path.Join(basePath, "pods/poduid/volumes/kubernetes.io~empty-dir/vol1") {
|
||||
t.Errorf("Got unexpected path: %s", volPath)
|
||||
}
|
||||
|
||||
if err := builder.SetUp(); err != nil {
|
||||
t.Errorf("Expected success, got: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(volPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
t.Errorf("SetUp() failed, volume path not created: %s", volPath)
|
||||
} else {
|
||||
t.Errorf("SetUp() failed: %v", err)
|
||||
}
|
||||
}
|
||||
if len(mounter.Log) != 1 {
|
||||
t.Errorf("Expected 1 mounter call, got %#v", mounter.Log)
|
||||
} else {
|
||||
if mounter.Log[0].Action != mount.FakeActionMount || mounter.Log[0].FSType != "tmpfs" {
|
||||
t.Errorf("Unexpected mounter action: %#v", mounter.Log[0])
|
||||
}
|
||||
}
|
||||
mounter.ResetLog()
|
||||
|
||||
cleaner, err := plug.(*emptyDirPlugin).newCleanerInternal("vol1", types.UID("poduid"), &mounter, &fakeMediumer{mediumMemory})
|
||||
if err != nil {
|
||||
t.Errorf("Failed to make a new Cleaner: %v", err)
|
||||
}
|
||||
if cleaner == nil {
|
||||
t.Errorf("Got a nil Cleaner: %v")
|
||||
}
|
||||
|
||||
if err := cleaner.TearDown(); err != nil {
|
||||
t.Errorf("Expected success, got: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(volPath); err == nil {
|
||||
t.Errorf("TearDown() failed, volume path still exists: %s", volPath)
|
||||
} else if !os.IsNotExist(err) {
|
||||
t.Errorf("SetUp() failed: %v", err)
|
||||
}
|
||||
if len(mounter.Log) != 1 {
|
||||
t.Errorf("Expected 1 mounter call, got %#v", mounter.Log)
|
||||
} else {
|
||||
if mounter.Log[0].Action != mount.FakeActionUnmount {
|
||||
t.Errorf("Unexpected mounter action: %#v", mounter.Log[0])
|
||||
}
|
||||
}
|
||||
mounter.ResetLog()
|
||||
}
|
||||
|
||||
func TestPluginBackCompat(t *testing.T) {
|
||||
plugMgr := volume.PluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), &volume.FakeHost{"/tmp/fake", nil})
|
||||
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir")
|
||||
|
||||
plug, err := plugMgr.FindPluginByName("kubernetes.io/empty-dir")
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
spec := &api.Volume{
|
||||
Name: "vol1",
|
||||
}
|
||||
@ -117,20 +204,15 @@ func TestPluginBackCompat(t *testing.T) {
|
||||
t.Errorf("Got a nil Builder: %v")
|
||||
}
|
||||
|
||||
path := builder.GetPath()
|
||||
if path != "/tmp/fake/pods/poduid/volumes/kubernetes.io~empty-dir/vol1" {
|
||||
t.Errorf("Got unexpected path: %s", path)
|
||||
volPath := builder.GetPath()
|
||||
if volPath != path.Join(basePath, "pods/poduid/volumes/kubernetes.io~empty-dir/vol1") {
|
||||
t.Errorf("Got unexpected path: %s", volPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginLegacy(t *testing.T) {
|
||||
plugMgr := volume.PluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), &volume.FakeHost{"/tmp/fake", nil})
|
||||
plug := makePluginUnderTest(t, "empty")
|
||||
|
||||
plug, err := plugMgr.FindPluginByName("empty")
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
if plug.Name() != "empty" {
|
||||
t.Errorf("Wrong name: %s", plug.Name())
|
||||
}
|
||||
@ -138,11 +220,12 @@ func TestPluginLegacy(t *testing.T) {
|
||||
t.Errorf("Expected false")
|
||||
}
|
||||
|
||||
if _, err := plug.NewBuilder(&api.Volume{VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}, &api.ObjectReference{UID: types.UID("poduid")}); err == nil {
|
||||
spec := api.Volume{VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}
|
||||
if _, err := plug.(*emptyDirPlugin).newBuilderInternal(&spec, &api.ObjectReference{UID: types.UID("poduid")}, &mount.FakeMounter{}, &fakeMediumer{}); err == nil {
|
||||
t.Errorf("Expected failiure")
|
||||
}
|
||||
|
||||
cleaner, err := plug.NewCleaner("vol1", types.UID("poduid"))
|
||||
cleaner, err := plug.(*emptyDirPlugin).newCleanerInternal("vol1", types.UID("poduid"), &mount.FakeMounter{}, &fakeMediumer{})
|
||||
if err != nil {
|
||||
t.Errorf("Failed to make a new Cleaner: %v", err)
|
||||
}
|
||||
|
26
pkg/kubelet/volume/empty_dir/empty_dir_unsupported.go
Normal file
26
pkg/kubelet/volume/empty_dir/empty_dir_unsupported.go
Normal file
@ -0,0 +1,26 @@
|
||||
// +build !linux
|
||||
|
||||
/*
|
||||
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 empty_dir
|
||||
|
||||
// realMediumer pretends to implement mediumer.
|
||||
type realMediumer struct{}
|
||||
|
||||
func (m *realMediumer) GetMedium(path string) (storageMedium, error) {
|
||||
return mediumUnknown, nil
|
||||
}
|
@ -16,16 +16,35 @@ limitations under the License.
|
||||
|
||||
package mount
|
||||
|
||||
// FakeMounter implements mount.Interface.
|
||||
// FakeMounter implements mount.Interface for tests.
|
||||
type FakeMounter struct {
|
||||
MountPoints []MountPoint
|
||||
Log []FakeAction
|
||||
}
|
||||
|
||||
// Values for FakeAction.Action
|
||||
const FakeActionMount = "mount"
|
||||
const FakeActionUnmount = "unmount"
|
||||
|
||||
// FakeAction objects are logged every time a fake mount or unmount is called.
|
||||
type FakeAction struct {
|
||||
Action string // "mount" or "unmount"
|
||||
Target string // applies to both mount and unmount actions
|
||||
Source string // applies only to "mount" actions
|
||||
FSType string // applies only to "mount" actions
|
||||
}
|
||||
|
||||
func (f *FakeMounter) ResetLog() {
|
||||
f.Log = []FakeAction{}
|
||||
}
|
||||
|
||||
func (f *FakeMounter) Mount(source string, target string, fstype string, flags uintptr, data string) error {
|
||||
f.Log = append(f.Log, FakeAction{Action: FakeActionMount, Target: target, Source: source, FSType: fstype})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeMounter) Unmount(target string, flags int) error {
|
||||
f.Log = append(f.Log, FakeAction{Action: FakeActionUnmount, Target: target})
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ func slicesEqual(a, b []string) bool {
|
||||
|
||||
func TestGetMountRefs(t *testing.T) {
|
||||
fm := &FakeMounter{
|
||||
[]MountPoint{
|
||||
MountPoints: []MountPoint{
|
||||
{Device: "/dev/sdb", Path: "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd"},
|
||||
{Device: "/dev/sdb", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd-in-pod"},
|
||||
{Device: "/dev/sdc", Path: "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd2"},
|
||||
|
Loading…
Reference in New Issue
Block a user