vendor files

This commit is contained in:
Serguei Bezverkhi
2018-01-09 13:57:14 -05:00
parent 558bc6c02a
commit 7b24313bd6
16547 changed files with 4527373 additions and 0 deletions

78
vendor/k8s.io/kubernetes/pkg/volume/empty_dir/BUILD generated vendored Normal file
View File

@ -0,0 +1,78 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"empty_dir.go",
"empty_dir_unsupported.go",
] + select({
"@io_bazel_rules_go//go/platform:linux_amd64": [
"empty_dir_linux.go",
],
"//conditions:default": [],
}),
importpath = "k8s.io/kubernetes/pkg/volume/empty_dir",
deps = [
"//pkg/apis/core/v1/helper:go_default_library",
"//pkg/util/mount:go_default_library",
"//pkg/util/strings:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/util:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
] + select({
"@io_bazel_rules_go//go/platform:linux_amd64": [
"//vendor/golang.org/x/sys/unix:go_default_library",
],
"//conditions:default": [],
}),
)
go_test(
name = "go_default_test",
srcs = select({
"@io_bazel_rules_go//go/platform:linux_amd64": [
"empty_dir_test.go",
],
"//conditions:default": [],
}),
importpath = "k8s.io/kubernetes/pkg/volume/empty_dir",
library = ":go_default_library",
deps = select({
"@io_bazel_rules_go//go/platform:linux_amd64": [
"//pkg/util/mount:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/testing:go_default_library",
"//pkg/volume/util:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/client-go/util/testing:go_default_library",
],
"//conditions:default": [],
}),
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)

14
vendor/k8s.io/kubernetes/pkg/volume/empty_dir/OWNERS generated vendored Normal file
View File

@ -0,0 +1,14 @@
approvers:
- pmorie
- saad-ali
- thockin
- matchstick
reviewers:
- ivan4th
- rata
- sjenning
- saad-ali
- jsafrane
- rootfs
- jingxu97
- msau42

19
vendor/k8s.io/kubernetes/pkg/volume/empty_dir/doc.go generated vendored Normal file
View File

@ -0,0 +1,19 @@
/*
Copyright 2015 The Kubernetes Authors.
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 contains the internal representation of emptyDir
// volumes.
package empty_dir // import "k8s.io/kubernetes/pkg/volume/empty_dir"

View File

@ -0,0 +1,440 @@
/*
Copyright 2014 The Kubernetes Authors.
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"
"os"
"path"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/kubernetes/pkg/util/mount"
stringsutil "k8s.io/kubernetes/pkg/util/strings"
"k8s.io/kubernetes/pkg/volume"
volumeutil "k8s.io/kubernetes/pkg/volume/util"
)
// TODO: in the near future, this will be changed to be more restrictive
// and the group will be set to allow containers to use emptyDir volumes
// from the group attribute.
//
// http://issue.k8s.io/2630
const perm os.FileMode = 0777
// This is the primary entrypoint for volume plugins.
func ProbeVolumePlugins() []volume.VolumePlugin {
return []volume.VolumePlugin{
&emptyDirPlugin{nil},
}
}
type emptyDirPlugin struct {
host volume.VolumeHost
}
var _ volume.VolumePlugin = &emptyDirPlugin{}
const (
emptyDirPluginName = "kubernetes.io/empty-dir"
hugePagesPageSizeMountOption = "pagesize"
)
func getPath(uid types.UID, volName string, host volume.VolumeHost) string {
return host.GetPodVolumeDir(uid, stringsutil.EscapeQualifiedNameForDisk(emptyDirPluginName), volName)
}
func (plugin *emptyDirPlugin) Init(host volume.VolumeHost) error {
plugin.host = host
return nil
}
func (plugin *emptyDirPlugin) GetPluginName() string {
return emptyDirPluginName
}
func (plugin *emptyDirPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
volumeSource, _ := getVolumeSource(spec)
if volumeSource == nil {
return "", fmt.Errorf("Spec does not reference an EmptyDir volume type")
}
// Return user defined volume name, since this is an ephemeral volume type
return spec.Name(), nil
}
func (plugin *emptyDirPlugin) CanSupport(spec *volume.Spec) bool {
if spec.Volume != nil && spec.Volume.EmptyDir != nil {
return true
}
return false
}
func (plugin *emptyDirPlugin) RequiresRemount() bool {
return false
}
func (plugin *emptyDirPlugin) SupportsMountOption() bool {
return false
}
func (plugin *emptyDirPlugin) SupportsBulkVolumeVerification() bool {
return false
}
func (plugin *emptyDirPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, opts volume.VolumeOptions) (volume.Mounter, error) {
return plugin.newMounterInternal(spec, pod, plugin.host.GetMounter(plugin.GetPluginName()), &realMountDetector{plugin.host.GetMounter(plugin.GetPluginName())}, opts)
}
func (plugin *emptyDirPlugin) newMounterInternal(spec *volume.Spec, pod *v1.Pod, mounter mount.Interface, mountDetector mountDetector, opts volume.VolumeOptions) (volume.Mounter, error) {
medium := v1.StorageMediumDefault
if spec.Volume.EmptyDir != nil { // Support a non-specified source as EmptyDir.
medium = spec.Volume.EmptyDir.Medium
}
return &emptyDir{
pod: pod,
volName: spec.Name(),
medium: medium,
mounter: mounter,
mountDetector: mountDetector,
plugin: plugin,
MetricsProvider: volume.NewMetricsDu(getPath(pod.UID, spec.Name(), plugin.host)),
}, nil
}
func (plugin *emptyDirPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
// Inject real implementations here, test through the internal function.
return plugin.newUnmounterInternal(volName, podUID, plugin.host.GetMounter(plugin.GetPluginName()), &realMountDetector{plugin.host.GetMounter(plugin.GetPluginName())})
}
func (plugin *emptyDirPlugin) newUnmounterInternal(volName string, podUID types.UID, mounter mount.Interface, mountDetector mountDetector) (volume.Unmounter, error) {
ed := &emptyDir{
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: podUID}},
volName: volName,
medium: v1.StorageMediumDefault, // might be changed later
mounter: mounter,
mountDetector: mountDetector,
plugin: plugin,
MetricsProvider: volume.NewMetricsDu(getPath(podUID, volName, plugin.host)),
}
return ed, nil
}
func (plugin *emptyDirPlugin) ConstructVolumeSpec(volName, mountPath string) (*volume.Spec, error) {
emptyDirVolume := &v1.Volume{
Name: volName,
VolumeSource: v1.VolumeSource{
EmptyDir: &v1.EmptyDirVolumeSource{},
},
}
return volume.NewSpecFromVolume(emptyDirVolume), nil
}
// mountDetector abstracts how to find what kind of mount a path is backed by.
type mountDetector interface {
// GetMountMedium determines what type of medium a given path is backed
// by and whether that path is a mount point. For example, if this
// returns (mediumMemory, false, nil), the caller knows that the path is
// on a memory FS (tmpfs on Linux) but is not the root mountpoint of
// that tmpfs.
GetMountMedium(path string) (storageMedium, bool, 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)
mediumHugepages storageMedium = 2 // hugepages
)
// EmptyDir volumes are temporary directories exposed to the pod.
// These do not persist beyond the lifetime of a pod.
type emptyDir struct {
pod *v1.Pod
volName string
medium v1.StorageMedium
mounter mount.Interface
mountDetector mountDetector
plugin *emptyDirPlugin
volume.MetricsProvider
}
func (ed *emptyDir) GetAttributes() volume.Attributes {
return volume.Attributes{
ReadOnly: false,
Managed: true,
SupportsSELinux: true,
}
}
// Checks prior to mount operations to verify that the required components (binaries, etc.)
// to mount the volume are available on the underlying node.
// If not, it returns an error
func (b *emptyDir) CanMount() error {
return nil
}
// SetUp creates new directory.
func (ed *emptyDir) SetUp(fsGroup *int64) error {
return ed.SetUpAt(ed.GetPath(), fsGroup)
}
// SetUpAt creates new directory.
func (ed *emptyDir) SetUpAt(dir string, fsGroup *int64) error {
notMnt, err := ed.mounter.IsLikelyNotMountPoint(dir)
// Getting an os.IsNotExist err from is a contingency; the directory
// may not exist yet, in which case, setup should run.
if err != nil && !os.IsNotExist(err) {
return err
}
// If the plugin readiness file is present for this volume, and the
// storage medium is the default, then the volume is ready. If the
// medium is memory, and a mountpoint is present, then the volume is
// ready.
if volumeutil.IsReady(ed.getMetaDir()) {
if ed.medium == v1.StorageMediumMemory && !notMnt {
return nil
} else if ed.medium == v1.StorageMediumDefault {
return nil
}
}
switch ed.medium {
case v1.StorageMediumDefault:
err = ed.setupDir(dir)
case v1.StorageMediumMemory:
err = ed.setupTmpfs(dir)
case v1.StorageMediumHugePages:
err = ed.setupHugepages(dir)
default:
err = fmt.Errorf("unknown storage medium %q", ed.medium)
}
volume.SetVolumeOwnership(ed, fsGroup)
if err == nil {
volumeutil.SetReady(ed.getMetaDir())
}
return err
}
// setupTmpfs creates a tmpfs mount at the specified directory.
func (ed *emptyDir) setupTmpfs(dir string) error {
if ed.mounter == nil {
return fmt.Errorf("memory storage requested, but mounter is nil")
}
if err := ed.setupDir(dir); err != nil {
return err
}
// Make SetUp idempotent.
medium, isMnt, err := ed.mountDetector.GetMountMedium(dir)
if err != nil {
return err
}
// If the directory is a mountpoint with medium memory, there is no
// work to do since we are already in the desired state.
if isMnt && medium == mediumMemory {
return nil
}
glog.V(3).Infof("pod %v: mounting tmpfs for volume %v", ed.pod.UID, ed.volName)
return ed.mounter.Mount("tmpfs", dir, "tmpfs", nil /* options */)
}
// setupHugepages creates a hugepage mount at the specified directory.
func (ed *emptyDir) setupHugepages(dir string) error {
if ed.mounter == nil {
return fmt.Errorf("memory storage requested, but mounter is nil")
}
if err := ed.setupDir(dir); err != nil {
return err
}
// Make SetUp idempotent.
medium, isMnt, err := ed.mountDetector.GetMountMedium(dir)
if err != nil {
return err
}
// If the directory is a mountpoint with medium hugepages, there is no
// work to do since we are already in the desired state.
if isMnt && medium == mediumHugepages {
return nil
}
pageSizeMountOption, err := getPageSizeMountOptionFromPod(ed.pod)
if err != nil {
return err
}
glog.V(3).Infof("pod %v: mounting hugepages for volume %v", ed.pod.UID, ed.volName)
return ed.mounter.Mount("nodev", dir, "hugetlbfs", []string{pageSizeMountOption})
}
// getPageSizeMountOptionFromPod retrieves pageSize mount option from Pod's resources
// and validates pageSize options in all containers of given Pod.
func getPageSizeMountOptionFromPod(pod *v1.Pod) (string, error) {
pageSizeFound := false
pageSize := resource.Quantity{}
// In some rare cases init containers can also consume Huge pages.
containers := append(pod.Spec.Containers, pod.Spec.InitContainers...)
for _, container := range containers {
// We can take request because limit and requests must match.
for requestName := range container.Resources.Requests {
if v1helper.IsHugePageResourceName(requestName) {
currentPageSize, err := v1helper.HugePageSizeFromResourceName(requestName)
if err != nil {
return "", err
}
// PageSize for all volumes in a POD are equal, except for the first one discovered.
if pageSizeFound && pageSize.Cmp(currentPageSize) != 0 {
return "", fmt.Errorf("multiple pageSizes for huge pages in a single PodSpec")
}
pageSize = currentPageSize
pageSizeFound = true
}
}
}
if !pageSizeFound {
return "", fmt.Errorf("hugePages storage requested, but there is no resource request for huge pages.")
}
return fmt.Sprintf("%s=%s", hugePagesPageSizeMountOption, pageSize.String()), nil
}
// setupDir creates the directory with the default permissions specified by the perm constant.
func (ed *emptyDir) setupDir(dir string) error {
// Create the directory if it doesn't already exist.
if err := os.MkdirAll(dir, perm); err != nil {
return err
}
// stat the directory to read permission bits
fileinfo, err := os.Lstat(dir)
if err != nil {
return err
}
if fileinfo.Mode().Perm() != perm.Perm() {
// If the permissions on the created directory are wrong, the
// kubelet is probably running with a umask set. In order to
// avoid clearing the umask for the entire process or locking
// the thread, clearing the umask, creating the dir, restoring
// the umask, and unlocking the thread, we do a chmod to set
// the specific bits we need.
err := os.Chmod(dir, perm)
if err != nil {
return err
}
fileinfo, err = os.Lstat(dir)
if err != nil {
return err
}
if fileinfo.Mode().Perm() != perm.Perm() {
glog.Errorf("Expected directory %q permissions to be: %s; got: %s", dir, perm.Perm(), fileinfo.Mode().Perm())
}
}
return nil
}
func (ed *emptyDir) GetPath() string {
return getPath(ed.pod.UID, ed.volName, ed.plugin.host)
}
// TearDown simply discards everything in the directory.
func (ed *emptyDir) TearDown() error {
return ed.TearDownAt(ed.GetPath())
}
// TearDownAt simply discards everything in the directory.
func (ed *emptyDir) TearDownAt(dir string) error {
if pathExists, pathErr := volumeutil.PathExists(dir); pathErr != nil {
return fmt.Errorf("Error checking if path exists: %v", pathErr)
} else if !pathExists {
glog.Warningf("Warning: Unmount skipped because path does not exist: %v", dir)
return nil
}
// Figure out the medium.
medium, isMnt, err := ed.mountDetector.GetMountMedium(dir)
if err != nil {
return err
}
if isMnt {
if medium == mediumMemory {
ed.medium = v1.StorageMediumMemory
return ed.teardownTmpfsOrHugetlbfs(dir)
} else if medium == mediumHugepages {
ed.medium = v1.StorageMediumHugePages
return ed.teardownTmpfsOrHugetlbfs(dir)
}
}
// assume StorageMediumDefault
return ed.teardownDefault(dir)
}
func (ed *emptyDir) teardownDefault(dir string) error {
// Renaming the directory is not required anymore because the operation executor
// now handles duplicate operations on the same volume
err := os.RemoveAll(dir)
if err != nil {
return err
}
return nil
}
func (ed *emptyDir) teardownTmpfsOrHugetlbfs(dir string) error {
if ed.mounter == nil {
return fmt.Errorf("memory storage requested, but mounter is nil")
}
if err := ed.mounter.Unmount(dir); err != nil {
return err
}
if err := os.RemoveAll(dir); err != nil {
return err
}
return nil
}
func (ed *emptyDir) getMetaDir() string {
return path.Join(ed.plugin.host.GetPodPluginDir(ed.pod.UID, stringsutil.EscapeQualifiedNameForDisk(emptyDirPluginName)), ed.volName)
}
func getVolumeSource(spec *volume.Spec) (*v1.EmptyDirVolumeSource, bool) {
var readOnly bool
var volumeSource *v1.EmptyDirVolumeSource
if spec.Volume != nil && spec.Volume.EmptyDir != nil {
volumeSource = spec.Volume.EmptyDir
readOnly = spec.ReadOnly
}
return volumeSource, readOnly
}

View File

@ -0,0 +1,58 @@
// +build linux
/*
Copyright 2015 The Kubernetes Authors.
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"
"github.com/golang/glog"
"golang.org/x/sys/unix"
"k8s.io/kubernetes/pkg/util/mount"
)
// Defined by Linux - the type number for tmpfs mounts.
const (
linuxTmpfsMagic = 0x01021994
linuxHugetlbfsMagic = 0x958458f6
)
// realMountDetector implements mountDetector in terms of syscalls.
type realMountDetector struct {
mounter mount.Interface
}
func (m *realMountDetector) GetMountMedium(path string) (storageMedium, bool, error) {
glog.V(5).Infof("Determining mount medium of %v", path)
notMnt, err := m.mounter.IsLikelyNotMountPoint(path)
if err != nil {
return 0, false, fmt.Errorf("IsLikelyNotMountPoint(%q): %v", path, err)
}
buf := unix.Statfs_t{}
if err := unix.Statfs(path, &buf); err != nil {
return 0, false, fmt.Errorf("statfs(%q): %v", path, err)
}
glog.V(5).Infof("Statfs_t of %v: %+v", path, buf)
if buf.Type == linuxTmpfsMagic {
return mediumMemory, !notMnt, nil
} else if int64(buf.Type) == linuxHugetlbfsMagic {
return mediumHugepages, !notMnt, nil
}
return mediumUnknown, !notMnt, nil
}

View File

@ -0,0 +1,441 @@
// +build linux
/*
Copyright 2014 The Kubernetes Authors.
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 (
"os"
"path"
"testing"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
utiltesting "k8s.io/client-go/util/testing"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
"k8s.io/kubernetes/pkg/volume/util"
)
// Construct an instance of a plugin, by name.
func makePluginUnderTest(t *testing.T, plugName, basePath string) volume.VolumePlugin {
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(basePath, nil, 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) {
tmpDir, err := utiltesting.MkTmpdir("emptydirTest")
if err != nil {
t.Fatalf("can't make a temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir", tmpDir)
if plug.GetPluginName() != "kubernetes.io/empty-dir" {
t.Errorf("Wrong name: %s", plug.GetPluginName())
}
if !plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{EmptyDir: &v1.EmptyDirVolumeSource{}}}}) {
t.Errorf("Expected true")
}
if plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{}}}) {
t.Errorf("Expected false")
}
}
type fakeMountDetector struct {
medium storageMedium
isMount bool
}
func (fake *fakeMountDetector) GetMountMedium(path string) (storageMedium, bool, error) {
return fake.medium, fake.isMount, nil
}
func TestPluginEmptyRootContext(t *testing.T) {
doTestPlugin(t, pluginTestConfig{
medium: v1.StorageMediumDefault,
expectedSetupMounts: 0,
expectedTeardownMounts: 0})
}
func TestPluginHugetlbfs(t *testing.T) {
doTestPlugin(t, pluginTestConfig{
medium: v1.StorageMediumHugePages,
expectedSetupMounts: 1,
expectedTeardownMounts: 0,
shouldBeMountedBeforeTeardown: true,
})
}
type pluginTestConfig struct {
medium v1.StorageMedium
idempotent bool
expectedSetupMounts int
shouldBeMountedBeforeTeardown bool
expectedTeardownMounts int
}
// doTestPlugin sets up a volume and tears it back down.
func doTestPlugin(t *testing.T, config pluginTestConfig) {
basePath, err := utiltesting.MkTmpdir("emptydir_volume_test")
if err != nil {
t.Fatalf("can't make a temp rootdir: %v", err)
}
defer os.RemoveAll(basePath)
var (
volumePath = path.Join(basePath, "pods/poduid/volumes/kubernetes.io~empty-dir/test-volume")
metadataDir = path.Join(basePath, "pods/poduid/plugins/kubernetes.io~empty-dir/test-volume")
plug = makePluginUnderTest(t, "kubernetes.io/empty-dir", basePath)
volumeName = "test-volume"
spec = &v1.Volume{
Name: volumeName,
VolumeSource: v1.VolumeSource{EmptyDir: &v1.EmptyDirVolumeSource{Medium: config.medium}},
}
physicalMounter = mount.FakeMounter{}
mountDetector = fakeMountDetector{}
pod = &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
UID: types.UID("poduid"),
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName("hugepages-2Mi"): resource.MustParse("100Mi"),
},
},
},
},
},
}
)
if config.idempotent {
physicalMounter.MountPoints = []mount.MountPoint{
{
Path: volumePath,
},
}
util.SetReady(metadataDir)
}
mounter, err := plug.(*emptyDirPlugin).newMounterInternal(volume.NewSpecFromVolume(spec),
pod,
&physicalMounter,
&mountDetector,
volume.VolumeOptions{})
if err != nil {
t.Errorf("Failed to make a new Mounter: %v", err)
}
if mounter == nil {
t.Errorf("Got a nil Mounter")
}
volPath := mounter.GetPath()
if volPath != volumePath {
t.Errorf("Got unexpected path: %s", volPath)
}
if err := mounter.SetUp(nil); err != nil {
t.Errorf("Expected success, got: %v", err)
}
// Stat the directory and check the permission bits
fileinfo, err := os.Stat(volPath)
if !config.idempotent {
if err != nil {
if os.IsNotExist(err) {
t.Errorf("SetUp() failed, volume path not created: %s", volPath)
} else {
t.Errorf("SetUp() failed: %v", err)
}
}
if e, a := perm, fileinfo.Mode().Perm(); e != a {
t.Errorf("Unexpected file mode for %v: expected: %v, got: %v", volPath, e, a)
}
} else if err == nil {
// If this test is for idempotency and we were able
// to stat the volume path, it's an error.
t.Errorf("Volume directory was created unexpectedly")
}
// Check the number of mounts performed during setup
if e, a := config.expectedSetupMounts, len(physicalMounter.Log); e != a {
t.Errorf("Expected %v physicalMounter calls during setup, got %v", e, a)
} else if config.expectedSetupMounts == 1 &&
(physicalMounter.Log[0].Action != mount.FakeActionMount || (physicalMounter.Log[0].FSType != "tmpfs" && physicalMounter.Log[0].FSType != "hugetlbfs")) {
t.Errorf("Unexpected physicalMounter action during setup: %#v", physicalMounter.Log[0])
}
physicalMounter.ResetLog()
// Make an unmounter for the volume
teardownMedium := mediumUnknown
if config.medium == v1.StorageMediumMemory {
teardownMedium = mediumMemory
}
unmounterMountDetector := &fakeMountDetector{medium: teardownMedium, isMount: config.shouldBeMountedBeforeTeardown}
unmounter, err := plug.(*emptyDirPlugin).newUnmounterInternal(volumeName, types.UID("poduid"), &physicalMounter, unmounterMountDetector)
if err != nil {
t.Errorf("Failed to make a new Unmounter: %v", err)
}
if unmounter == nil {
t.Errorf("Got a nil Unmounter")
}
// Tear down the volume
if err := unmounter.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("TearDown() failed: %v", err)
}
// Check the number of physicalMounter calls during tardown
if e, a := config.expectedTeardownMounts, len(physicalMounter.Log); e != a {
t.Errorf("Expected %v physicalMounter calls during teardown, got %v", e, a)
} else if config.expectedTeardownMounts == 1 && physicalMounter.Log[0].Action != mount.FakeActionUnmount {
t.Errorf("Unexpected physicalMounter action during teardown: %#v", physicalMounter.Log[0])
}
physicalMounter.ResetLog()
}
func TestPluginBackCompat(t *testing.T) {
basePath, err := utiltesting.MkTmpdir("emptydirTest")
if err != nil {
t.Fatalf("can't make a temp dir %v", err)
}
defer os.RemoveAll(basePath)
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir", basePath)
spec := &v1.Volume{
Name: "vol1",
}
pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
mounter, err := plug.NewMounter(volume.NewSpecFromVolume(spec), pod, volume.VolumeOptions{})
if err != nil {
t.Errorf("Failed to make a new Mounter: %v", err)
}
if mounter == nil {
t.Fatalf("Got a nil Mounter")
}
volPath := mounter.GetPath()
if volPath != path.Join(basePath, "pods/poduid/volumes/kubernetes.io~empty-dir/vol1") {
t.Errorf("Got unexpected path: %s", volPath)
}
}
// TestMetrics tests that MetricProvider methods return sane values.
func TestMetrics(t *testing.T) {
// Create an empty temp directory for the volume
tmpDir, err := utiltesting.MkTmpdir("empty_dir_test")
if err != nil {
t.Fatalf("Can't make a tmp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir", tmpDir)
spec := &v1.Volume{
Name: "vol1",
}
pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
mounter, err := plug.NewMounter(volume.NewSpecFromVolume(spec), pod, volume.VolumeOptions{})
if err != nil {
t.Errorf("Failed to make a new Mounter: %v", err)
}
if mounter == nil {
t.Fatalf("Got a nil Mounter")
}
// Need to create the subdirectory
os.MkdirAll(mounter.GetPath(), 0755)
expectedEmptyDirUsage, err := volumetest.FindEmptyDirectoryUsageOnTmpfs()
if err != nil {
t.Errorf("Unexpected error finding expected empty directory usage on tmpfs: %v", err)
}
// TODO(pwittroc): Move this into a reusable testing utility
metrics, err := mounter.GetMetrics()
if err != nil {
t.Errorf("Unexpected error when calling GetMetrics %v", err)
}
if e, a := expectedEmptyDirUsage.Value(), metrics.Used.Value(); e != a {
t.Errorf("Unexpected value for empty directory; expected %v, got %v", e, a)
}
if metrics.Capacity.Value() <= 0 {
t.Errorf("Expected Capacity to be greater than 0")
}
if metrics.Available.Value() <= 0 {
t.Errorf("Expected Available to be greater than 0")
}
}
func TestGetHugePagesMountOptions(t *testing.T) {
testCases := map[string]struct {
pod *v1.Pod
shouldFail bool
expectedResult string
}{
"testWithProperValues": {
pod: &v1.Pod{
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName("hugepages-2Mi"): resource.MustParse("100Mi"),
},
},
},
},
},
},
shouldFail: false,
expectedResult: "pagesize=2Mi",
},
"testWithProperValuesAndDifferentPageSize": {
pod: &v1.Pod{
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName("hugepages-1Gi"): resource.MustParse("2Gi"),
},
},
},
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName("hugepages-1Gi"): resource.MustParse("4Gi"),
},
},
},
},
},
},
shouldFail: false,
expectedResult: "pagesize=1Gi",
},
"InitContainerAndContainerHasProperValues": {
pod: &v1.Pod{
Spec: v1.PodSpec{
InitContainers: []v1.Container{
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName("hugepages-1Gi"): resource.MustParse("2Gi"),
},
},
},
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName("hugepages-1Gi"): resource.MustParse("4Gi"),
},
},
},
},
},
},
shouldFail: false,
expectedResult: "pagesize=1Gi",
},
"InitContainerAndContainerHasDifferentPageSizes": {
pod: &v1.Pod{
Spec: v1.PodSpec{
InitContainers: []v1.Container{
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName("hugepages-2Mi"): resource.MustParse("2Gi"),
},
},
},
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName("hugepages-1Gi"): resource.MustParse("4Gi"),
},
},
},
},
},
},
shouldFail: true,
expectedResult: "",
},
"ContainersWithMultiplePageSizes": {
pod: &v1.Pod{
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName("hugepages-1Gi"): resource.MustParse("2Gi"),
},
},
},
{
Resources: v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName("hugepages-2Mi"): resource.MustParse("100Mi"),
},
},
},
},
},
},
shouldFail: true,
expectedResult: "",
},
"PodWithNoHugePagesRequest": {
pod: &v1.Pod{},
shouldFail: true,
expectedResult: "",
},
}
for testCaseName, testCase := range testCases {
value, err := getPageSizeMountOptionFromPod(testCase.pod)
if testCase.shouldFail && err == nil {
t.Errorf("Expected an error in %v", testCaseName)
} else if !testCase.shouldFail && err != nil {
t.Errorf("Unexpected error in %v, got %v", testCaseName, err)
} else if testCase.expectedResult != value {
t.Errorf("Unexpected mountOptions for Pod. Expected %v, got %v", testCase.expectedResult, value)
}
}
}

View File

@ -0,0 +1,32 @@
// +build !linux
/*
Copyright 2015 The Kubernetes Authors.
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 (
"k8s.io/kubernetes/pkg/util/mount"
)
// realMountDetector pretends to implement mediumer.
type realMountDetector struct {
mounter mount.Interface
}
func (m *realMountDetector) GetMountMedium(path string) (storageMedium, bool, error) {
return mediumUnknown, false, nil
}