Merge pull request #458 from harche/without_devices

virtcontainers: Add support for ephemeral volumes
This commit is contained in:
Peng Tao 2018-07-18 15:06:09 +08:00 committed by GitHub
commit 81c073f67d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 118 additions and 2 deletions

View File

@ -109,7 +109,6 @@ func create(containerID, bundlePath, console, pidFilePath string, detach bool,
disableOutput := noNeedForOutput(detach, ociSpec.Process.Terminal)
var process vc.Process
switch containerType {
case vc.PodSandbox:
process, err = createSandbox(ociSpec, runtimeConfig, containerID, bundlePath, console, disableOutput)
@ -255,9 +254,25 @@ func createSandbox(ociSpec oci.CompatOCISpec, runtimeConfig oci.RuntimeConfig,
return containers[0].Process(), nil
}
// setEphemeralStorageType sets the mount type to 'ephemeral'
// if the mount source path is provisioned by k8s for ephemeral storage.
// For the given pod ephemeral volume is created only once
// backed by tmpfs inside the VM. For successive containers
// of the same pod the already existing volume is reused.
func setEphemeralStorageType(ociSpec oci.CompatOCISpec) oci.CompatOCISpec {
for idx, mnt := range ociSpec.Mounts {
if IsEphemeralStorage(mnt.Source) {
ociSpec.Mounts[idx].Type = "ephemeral"
}
}
return ociSpec
}
func createContainer(ociSpec oci.CompatOCISpec, containerID, bundlePath,
console string, disableOutput bool) (vc.Process, error) {
ociSpec = setEphemeralStorageType(ociSpec)
contConfig, err := oci.ContainerConfig(ociSpec, bundlePath, containerID, console, disableOutput)
if err != nil {
return vc.Process{}, err

View File

@ -1010,6 +1010,24 @@ func TestCreateCreateContainerFail(t *testing.T) {
}
}
func TestSetEphemeralStorageType(t *testing.T) {
assert := assert.New(t)
ociSpec := oci.CompatOCISpec{}
var ociMounts []specs.Mount
mount := specs.Mount{
Source: "/var/lib/kubelet/pods/366c3a77-4869-11e8-b479-507b9ddd5ce4/volumes/kubernetes.io~empty-dir/cache-volume",
}
ociMounts = append(ociMounts, mount)
ociSpec.Mounts = ociMounts
ociSpec = setEphemeralStorageType(ociSpec)
mountType := ociSpec.Mounts[0].Type
assert.Equal(mountType, "ephemeral",
"Unexpected mount type, got %s expected ephemeral", mountType)
}
func TestCreateCreateContainer(t *testing.T) {
assert := assert.New(t)

View File

@ -15,7 +15,10 @@ import (
"strings"
)
const unknown = "<<unknown>>"
const (
unknown = "<<unknown>>"
k8sEmptyDir = "kubernetes.io~empty-dir"
)
// variables to allow tests to modify the values
var (
@ -43,6 +46,26 @@ func getFileContents(file string) (string, error) {
return string(bytes), nil
}
// IsEphemeralStorage returns true if the given path
// to the storage belongs to kubernetes ephemeral storage
//
// This method depends on a specific path used by k8s
// to detect if it's of type ephemeral. As of now,
// this is a very k8s specific solution that works
// but in future there should be a better way for this
// method to determine if the path is for ephemeral
// volume type
func IsEphemeralStorage(path string) bool {
splitSourceSlice := strings.Split(path, "/")
if len(splitSourceSlice) > 1 {
storageType := splitSourceSlice[len(splitSourceSlice)-2]
if storageType == k8sEmptyDir {
return true
}
}
return false
}
func getKernelVersion() (string, error) {
contents, err := getFileContents(procVersion)
if err != nil {

View File

@ -38,6 +38,20 @@ func TestFileExists(t *testing.T) {
fmt.Sprintf("File %q should exist", file))
}
func TestIsEphemeralStorage(t *testing.T) {
sampleEphePath := "/var/lib/kubelet/pods/366c3a75-4869-11e8-b479-507b9ddd5ce4/volumes/kubernetes.io~empty-dir/cache-volume"
isEphe := IsEphemeralStorage(sampleEphePath)
if !isEphe {
t.Fatalf("Unable to correctly determine volume type")
}
sampleEphePath = "/var/lib/kubelet/pods/366c3a75-4869-11e8-b479-507b9ddd5ce4/volumes/cache-volume"
isEphe = IsEphemeralStorage(sampleEphePath)
if isEphe {
t.Fatalf("Unable to correctly determine volume type")
}
}
func TestGetFileContents(t *testing.T) {
type testData struct {
contents string

View File

@ -52,6 +52,7 @@ var (
sharedDir9pOptions = []string{"trans=virtio,version=9p2000.L", "nodev"}
shmDir = "shm"
kataEphemeralDevType = "ephemeral"
ephemeralPath = filepath.Join(kataGuestSandboxDir, kataEphemeralDevType)
)
// KataAgentConfig is a structure storing information needed
@ -803,6 +804,9 @@ func (k *kataAgent) createContainer(sandbox *Sandbox, c *Container) (p *Process,
return nil, err
}
epheStorages := k.handleEphemeralStorage(ociSpec.Mounts)
ctrStorages = append(ctrStorages, epheStorages...)
// We replace all OCI mount sources that match our container mount
// with the right source path (The guest one).
if err = k.replaceOCIMountSource(ociSpec, newMounts); err != nil {
@ -868,6 +872,29 @@ func (k *kataAgent) createContainer(sandbox *Sandbox, c *Container) (p *Process,
k.state.URL, c.config.Cmd, createNSList, enterNSList)
}
// handleEphemeralStorage handles ephemeral storages by
// creating a Storage from corresponding source of the mount point
func (k *kataAgent) handleEphemeralStorage(mounts []specs.Mount) []*grpc.Storage {
var epheStorages []*grpc.Storage
for idx, mnt := range mounts {
if mnt.Type == kataEphemeralDevType {
// Set the mount source path to a path that resides inside the VM
mounts[idx].Source = filepath.Join(ephemeralPath, filepath.Base(mnt.Source))
// Create a storage struct so that kata agent is able to create
// tmpfs backed volume inside the VM
epheStorage := &grpc.Storage{
Driver: kataEphemeralDevType,
Source: "tmpfs",
Fstype: "tmpfs",
MountPoint: mounts[idx].Source,
}
epheStorages = append(epheStorages, epheStorage)
}
}
return epheStorages
}
// handleBlockVolumes handles volumes that are block devices files
// by passing the block devices as Storage to the agent.
func (k *kataAgent) handleBlockVolumes(c *Container) []*grpc.Storage {

View File

@ -369,6 +369,25 @@ func TestGenerateInterfacesAndRoutes(t *testing.T) {
}
func TestHandleEphemeralStorage(t *testing.T) {
k := kataAgent{}
var ociMounts []specs.Mount
mountSource := "/tmp/mountPoint"
mount := specs.Mount{
Type: kataEphemeralDevType,
Source: mountSource,
}
ociMounts = append(ociMounts, mount)
epheStorages := k.handleEphemeralStorage(ociMounts)
epheMountPoint := epheStorages[0].GetMountPoint()
expected := filepath.Join(ephemeralPath, filepath.Base(mountSource))
assert.Equal(t, epheMountPoint, expected,
"Ephemeral mount point didn't match: got %s, expecting %s", epheMountPoint, expected)
}
func TestAppendDevicesEmptyContainerDeviceList(t *testing.T) {
k := kataAgent{}