Add tmpfs support to EmptyDir

# *** ERROR: *** docs are out of sync between cli and markdown
# run hack/run-gendocs.sh > docs/kubectl.md to regenerate

#
# Your commit will be aborted unless you regenerate docs.
    COMMIT_BLOCKED_ON_GENDOCS
This commit is contained in:
Tim Hockin
2015-03-07 12:35:00 -08:00
parent 50c96789e7
commit caca5e7358
8 changed files with 357 additions and 48 deletions

View File

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