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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user