mirror of
https://github.com/aljazceru/kata-containers.git
synced 2025-12-26 18:44:47 +01:00
We can now remove all the sandbox shared types and convert the rest of the code to using the new internal types package. This commit includes virtcontainers, cli and containerd-shim changes in one atomic change in order to not break bisect'ibility. Fixes: #1095 Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
289 lines
5.8 KiB
Go
289 lines
5.8 KiB
Go
// Copyright (c) 2017 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
package virtcontainers
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"syscall"
|
|
"time"
|
|
|
|
ns "github.com/kata-containers/runtime/virtcontainers/pkg/nsenter"
|
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
|
"github.com/mitchellh/mapstructure"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// ShimType describes a shim type.
|
|
type ShimType string
|
|
|
|
const (
|
|
// CCShimType is the ccShim.
|
|
CCShimType ShimType = "ccShim"
|
|
|
|
// NoopShimType is the noopShim.
|
|
NoopShimType ShimType = "noopShim"
|
|
|
|
// KataShimType is the Kata Containers shim type.
|
|
KataShimType ShimType = "kataShim"
|
|
|
|
// KataBuiltInShimType is the Kata Containers builtin shim type.
|
|
KataBuiltInShimType ShimType = "kataBuiltInShim"
|
|
)
|
|
|
|
var waitForShimTimeout = 10.0
|
|
var consoleFileMode = os.FileMode(0660)
|
|
|
|
// ShimParams is the structure providing specific parameters needed
|
|
// for the execution of the shim binary.
|
|
type ShimParams struct {
|
|
Container string
|
|
Token string
|
|
URL string
|
|
Console string
|
|
Terminal bool
|
|
Detach bool
|
|
PID int
|
|
CreateNS []ns.NSType
|
|
EnterNS []ns.Namespace
|
|
}
|
|
|
|
// ShimConfig is the structure providing specific configuration
|
|
// for shim implementations.
|
|
type ShimConfig struct {
|
|
Path string
|
|
Debug bool
|
|
Trace bool
|
|
}
|
|
|
|
// Set sets a shim type based on the input string.
|
|
func (pType *ShimType) Set(value string) error {
|
|
switch value {
|
|
case "noopShim":
|
|
*pType = NoopShimType
|
|
case "ccShim":
|
|
*pType = CCShimType
|
|
case "kataShim":
|
|
*pType = KataShimType
|
|
case "kataBuiltInShim":
|
|
*pType = KataBuiltInShimType
|
|
default:
|
|
return fmt.Errorf("Unknown shim type %s", value)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// String converts a shim type to a string.
|
|
func (pType *ShimType) String() string {
|
|
switch *pType {
|
|
case NoopShimType:
|
|
return string(NoopShimType)
|
|
case CCShimType:
|
|
return string(CCShimType)
|
|
case KataShimType:
|
|
return string(KataShimType)
|
|
case KataBuiltInShimType:
|
|
return string(KataBuiltInShimType)
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
// newShim returns a shim from a shim type.
|
|
func newShim(pType ShimType) (shim, error) {
|
|
switch pType {
|
|
case NoopShimType:
|
|
return &noopShim{}, nil
|
|
case CCShimType:
|
|
return &ccShim{}, nil
|
|
case KataShimType:
|
|
return &kataShim{}, nil
|
|
case KataBuiltInShimType:
|
|
return &kataBuiltInShim{}, nil
|
|
default:
|
|
return &noopShim{}, nil
|
|
}
|
|
}
|
|
|
|
// newShimConfig returns a shim config from a generic SandboxConfig interface.
|
|
func newShimConfig(config SandboxConfig) interface{} {
|
|
switch config.ShimType {
|
|
case NoopShimType, KataBuiltInShimType:
|
|
return nil
|
|
case CCShimType, KataShimType:
|
|
var shimConfig ShimConfig
|
|
err := mapstructure.Decode(config.ShimConfig, &shimConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return shimConfig
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func shimLogger() *logrus.Entry {
|
|
return virtLog.WithField("subsystem", "shim")
|
|
}
|
|
|
|
func signalShim(pid int, sig syscall.Signal) error {
|
|
if pid <= 0 {
|
|
return nil
|
|
}
|
|
|
|
shimLogger().WithFields(
|
|
logrus.Fields{
|
|
"shim-pid": pid,
|
|
"shim-signal": sig,
|
|
}).Info("Signalling shim")
|
|
|
|
return syscall.Kill(pid, sig)
|
|
}
|
|
|
|
func stopShim(pid int) error {
|
|
if pid <= 0 {
|
|
return nil
|
|
}
|
|
|
|
if err := signalShim(pid, syscall.SIGKILL); err != nil && err != syscall.ESRCH {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func prepareAndStartShim(sandbox *Sandbox, shim shim, cid, token, url string, cmd types.Cmd,
|
|
createNSList []ns.NSType, enterNSList []ns.Namespace) (*Process, error) {
|
|
process := &Process{
|
|
Token: token,
|
|
StartTime: time.Now().UTC(),
|
|
}
|
|
|
|
shimParams := ShimParams{
|
|
Container: cid,
|
|
Token: token,
|
|
URL: url,
|
|
Console: cmd.Console,
|
|
Terminal: cmd.Interactive,
|
|
Detach: cmd.Detach,
|
|
CreateNS: createNSList,
|
|
EnterNS: enterNSList,
|
|
}
|
|
|
|
pid, err := shim.start(sandbox, shimParams)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
process.Pid = pid
|
|
|
|
return process, nil
|
|
}
|
|
|
|
func startShim(args []string, params ShimParams) (int, error) {
|
|
cmd := exec.Command(args[0], args[1:]...)
|
|
|
|
if !params.Detach {
|
|
cmd.Stdin = os.Stdin
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
}
|
|
|
|
cloneFlags := 0
|
|
for _, nsType := range params.CreateNS {
|
|
cloneFlags |= ns.CloneFlagsTable[nsType]
|
|
}
|
|
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
|
Cloneflags: uintptr(cloneFlags),
|
|
}
|
|
|
|
var f *os.File
|
|
var err error
|
|
if params.Console != "" {
|
|
f, err = os.OpenFile(params.Console, os.O_RDWR, consoleFileMode)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
|
|
cmd.Stdin = f
|
|
cmd.Stdout = f
|
|
cmd.Stderr = f
|
|
// Create Session
|
|
cmd.SysProcAttr.Setsid = true
|
|
// Set Controlling terminal to Ctty
|
|
cmd.SysProcAttr.Setctty = true
|
|
cmd.SysProcAttr.Ctty = int(f.Fd())
|
|
}
|
|
defer func() {
|
|
if f != nil {
|
|
f.Close()
|
|
}
|
|
}()
|
|
|
|
if err := ns.NsEnter(params.EnterNS, func() error {
|
|
return cmd.Start()
|
|
}); err != nil {
|
|
return -1, err
|
|
}
|
|
|
|
return cmd.Process.Pid, nil
|
|
}
|
|
|
|
func isShimRunning(pid int) (bool, error) {
|
|
if pid <= 0 {
|
|
return false, nil
|
|
}
|
|
|
|
process, err := os.FindProcess(pid)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if err := process.Signal(syscall.Signal(0)); err != nil {
|
|
return false, nil
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
// waitForShim waits for the end of the shim unless it reaches the timeout
|
|
// first, returning an error in that case.
|
|
func waitForShim(pid int) error {
|
|
if pid <= 0 {
|
|
return nil
|
|
}
|
|
|
|
tInit := time.Now()
|
|
for {
|
|
running, err := isShimRunning(pid)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !running {
|
|
break
|
|
}
|
|
|
|
if time.Since(tInit).Seconds() >= waitForShimTimeout {
|
|
return fmt.Errorf("Shim still running, timeout %f s has been reached", waitForShimTimeout)
|
|
}
|
|
|
|
// Let's avoid to run a too busy loop
|
|
time.Sleep(time.Duration(100) * time.Millisecond)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// shim is the virtcontainers shim interface.
|
|
type shim interface {
|
|
// start starts the shim relying on its configuration and on
|
|
// parameters provided.
|
|
start(sandbox *Sandbox, params ShimParams) (int, error)
|
|
}
|