mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-07-05 03:26:37 +00:00
Merge pull request #458 from harche/without_devices
virtcontainers: Add support for ephemeral volumes
This commit is contained in:
commit
81c073f67d
@ -109,7 +109,6 @@ func create(containerID, bundlePath, console, pidFilePath string, detach bool,
|
|||||||
disableOutput := noNeedForOutput(detach, ociSpec.Process.Terminal)
|
disableOutput := noNeedForOutput(detach, ociSpec.Process.Terminal)
|
||||||
|
|
||||||
var process vc.Process
|
var process vc.Process
|
||||||
|
|
||||||
switch containerType {
|
switch containerType {
|
||||||
case vc.PodSandbox:
|
case vc.PodSandbox:
|
||||||
process, err = createSandbox(ociSpec, runtimeConfig, containerID, bundlePath, console, disableOutput)
|
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
|
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,
|
func createContainer(ociSpec oci.CompatOCISpec, containerID, bundlePath,
|
||||||
console string, disableOutput bool) (vc.Process, error) {
|
console string, disableOutput bool) (vc.Process, error) {
|
||||||
|
|
||||||
|
ociSpec = setEphemeralStorageType(ociSpec)
|
||||||
|
|
||||||
contConfig, err := oci.ContainerConfig(ociSpec, bundlePath, containerID, console, disableOutput)
|
contConfig, err := oci.ContainerConfig(ociSpec, bundlePath, containerID, console, disableOutput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return vc.Process{}, err
|
return vc.Process{}, err
|
||||||
|
@ -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) {
|
func TestCreateCreateContainer(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
25
cli/utils.go
25
cli/utils.go
@ -15,7 +15,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const unknown = "<<unknown>>"
|
const (
|
||||||
|
unknown = "<<unknown>>"
|
||||||
|
k8sEmptyDir = "kubernetes.io~empty-dir"
|
||||||
|
)
|
||||||
|
|
||||||
// variables to allow tests to modify the values
|
// variables to allow tests to modify the values
|
||||||
var (
|
var (
|
||||||
@ -43,6 +46,26 @@ func getFileContents(file string) (string, error) {
|
|||||||
return string(bytes), nil
|
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) {
|
func getKernelVersion() (string, error) {
|
||||||
contents, err := getFileContents(procVersion)
|
contents, err := getFileContents(procVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -38,6 +38,20 @@ func TestFileExists(t *testing.T) {
|
|||||||
fmt.Sprintf("File %q should exist", file))
|
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) {
|
func TestGetFileContents(t *testing.T) {
|
||||||
type testData struct {
|
type testData struct {
|
||||||
contents string
|
contents string
|
||||||
|
@ -52,6 +52,7 @@ var (
|
|||||||
sharedDir9pOptions = []string{"trans=virtio,version=9p2000.L", "nodev"}
|
sharedDir9pOptions = []string{"trans=virtio,version=9p2000.L", "nodev"}
|
||||||
shmDir = "shm"
|
shmDir = "shm"
|
||||||
kataEphemeralDevType = "ephemeral"
|
kataEphemeralDevType = "ephemeral"
|
||||||
|
ephemeralPath = filepath.Join(kataGuestSandboxDir, kataEphemeralDevType)
|
||||||
)
|
)
|
||||||
|
|
||||||
// KataAgentConfig is a structure storing information needed
|
// KataAgentConfig is a structure storing information needed
|
||||||
@ -803,6 +804,9 @@ func (k *kataAgent) createContainer(sandbox *Sandbox, c *Container) (p *Process,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
epheStorages := k.handleEphemeralStorage(ociSpec.Mounts)
|
||||||
|
ctrStorages = append(ctrStorages, epheStorages...)
|
||||||
|
|
||||||
// We replace all OCI mount sources that match our container mount
|
// We replace all OCI mount sources that match our container mount
|
||||||
// with the right source path (The guest one).
|
// with the right source path (The guest one).
|
||||||
if err = k.replaceOCIMountSource(ociSpec, newMounts); err != nil {
|
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)
|
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
|
// handleBlockVolumes handles volumes that are block devices files
|
||||||
// by passing the block devices as Storage to the agent.
|
// by passing the block devices as Storage to the agent.
|
||||||
func (k *kataAgent) handleBlockVolumes(c *Container) []*grpc.Storage {
|
func (k *kataAgent) handleBlockVolumes(c *Container) []*grpc.Storage {
|
||||||
|
@ -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) {
|
func TestAppendDevicesEmptyContainerDeviceList(t *testing.T) {
|
||||||
k := kataAgent{}
|
k := kataAgent{}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user