Skip to content
This repository was archived by the owner on Feb 8, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions containerd/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ var ContainerdCommand = cli.Command{
return nil
},

Action: func(context *cli.Context) {
Action: func(context *cli.Context) error {
driver := context.GlobalString("driver")
kernel := context.GlobalString("kernel")
initrd := context.GlobalString("initrd")
Expand All @@ -95,13 +95,15 @@ var ContainerdCommand = cli.Command{
path := filepath.Join(template, "config.json")
f, err := os.Open(path)
if err != nil {
glog.Errorf("open template JSON configuration file failed: %v", err)
os.Exit(-1)
err = fmt.Errorf("open template JSON configuration file failed: %v", err)
glog.Error(err)
return cli.NewExitError(err.Error(), -1)
}
if err := json.NewDecoder(f).Decode(&tconfig); err != nil {
glog.Errorf("parse template JSON configuration file failed: %v", err)
err = fmt.Errorf("parse template JSON configuration file failed: %v", err)
glog.Error(err)
f.Close()
os.Exit(-1)
return cli.NewExitError(err.Error(), -1)
}
f.Close()

Expand All @@ -116,15 +118,16 @@ var ContainerdCommand = cli.Command{
driver = tconfig.Driver
}
} else if (bios == "" || cbfs == "") && (kernel == "" || initrd == "") {
glog.Error("argument kernel+initrd or bios+cbfs must be set")
os.Exit(1)
err := fmt.Errorf("argument kernel+initrd or bios+cbfs must be set")
glog.Error(err)
return cli.NewExitError(err.Error(), -1)
}

hypervisor.InterfaceCount = 0
var err error
if hypervisor.HDriver, err = driverloader.Probe(driver); err != nil {
glog.Errorf("%v", err)
os.Exit(1)
return cli.NewExitError(err.Error(), -1)
}

var f factory.Factory
Expand All @@ -144,7 +147,7 @@ var ContainerdCommand = cli.Command{
context.GlobalInt("default_cpus"), context.GlobalInt("default_memory"))
if err != nil {
glog.Errorf("%v", err)
os.Exit(1)
return cli.NewExitError(err.Error(), -1)
}

if context.Bool("solo-namespaced") {
Expand All @@ -153,12 +156,13 @@ var ContainerdCommand = cli.Command{

if err = daemon(sv, context.String("listen")); err != nil {
glog.Errorf("%v", err)
os.Exit(1)
return cli.NewExitError(err.Error(), -1)
}

if context.Bool("solo-namespaced") {
os.RemoveAll(containerdDir)
}
return nil
},
}

Expand Down
83 changes: 36 additions & 47 deletions create.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,39 +57,39 @@ command(s) that get executed on start, edit the args parameter of the spec. See
Usage: "[ignore on runv] do not use pivot root to jail process inside rootfs. This should be used whenever the rootfs is on top of a ramdisk",
},
},
Action: func(context *cli.Context) {
runContainer(context, true)
Action: func(context *cli.Context) error {
if err := runContainer(context, true); err != nil {
return cli.NewExitError(fmt.Sprintf("Run Container error: %v", err), -1)
}
return nil
},
}

func runContainer(context *cli.Context, createOnly bool) {
func runContainer(context *cli.Context, createOnly bool) error {
root := context.GlobalString("root")
bundle := context.String("bundle")
container := context.Args().First()
ocffile := filepath.Join(bundle, specConfig)
spec, err := loadSpec(ocffile)
if err != nil {
fmt.Fprintf(os.Stderr, "load config failed: %v\n", err)
os.Exit(-1)
return fmt.Errorf("load config failed: %v", err)
}
if spec.Linux == nil {
fmt.Fprintf(os.Stderr, "it is not linux container config\n")
os.Exit(-1)
return fmt.Errorf("it is not linux container config")
}
if os.Geteuid() != 0 {
fmt.Fprintf(os.Stderr, "runv should be run as root\n")
os.Exit(-1)
return fmt.Errorf("runv should be run as root")
}
if container == "" {
fmt.Fprintf(os.Stderr, "no container id provided\n")
os.Exit(-1)
return fmt.Errorf("no container id provided")
}
_, err = os.Stat(filepath.Join(root, container))
if err == nil {
fmt.Fprintf(os.Stderr, "Container %q exists\n", container)
os.Exit(-1)
return fmt.Errorf("container %q exists", container)
}
if err = checkConsole(context, &spec.Process, createOnly); err != nil {
return err
}
checkConsole(context, &spec.Process, createOnly)

var sharedContainer string
if containerType, ok := spec.Annotations["ocid/container_type"]; ok {
Expand All @@ -100,24 +100,20 @@ func runContainer(context *cli.Context, createOnly bool) {
for _, ns := range spec.Linux.Namespaces {
if ns.Path != "" {
if strings.Contains(ns.Path, "/") {
fmt.Fprintf(os.Stderr, "Runv doesn't support path to namespace file, it supports containers name as shared namespaces only\n")
os.Exit(-1)
return fmt.Errorf("Runv doesn't support path to namespace file, it supports containers name as shared namespaces only")
}
if ns.Type == "mount" {
// TODO support it!
fmt.Fprintf(os.Stderr, "Runv doesn't support shared mount namespace currently\n")
os.Exit(-1)
return fmt.Errorf("Runv doesn't support shared mount namespace currently")
}
sharedContainer = ns.Path
_, err = os.Stat(filepath.Join(root, sharedContainer, stateJson))
if err != nil {
fmt.Fprintf(os.Stderr, "The container %q is not existing or not ready\n", sharedContainer)
os.Exit(-1)
return fmt.Errorf("The container %q is not existing or not ready", sharedContainer)
}
_, err = os.Stat(filepath.Join(root, sharedContainer, "namespace"))
if err != nil {
fmt.Fprintf(os.Stderr, "The container %q is not ready\n", sharedContainer)
os.Exit(-1)
return fmt.Errorf("The container %q is not ready", sharedContainer)
}
}
}
Expand All @@ -129,26 +125,22 @@ func runContainer(context *cli.Context, createOnly bool) {
namespace = filepath.Join(root, sharedContainer, "namespace")
namespace, err = os.Readlink(namespace)
if err != nil {
fmt.Fprintf(os.Stderr, "Cannot get namespace link of the shared container: %v\n", err)
os.Exit(-1)
return fmt.Errorf("cannot get namespace link of the shared container: %v", err)
}
} else {
path, err := osext.Executable()
if err != nil {
fmt.Fprintf(os.Stderr, "cannot find self executable path for %s: %v\n", os.Args[0], err)
os.Exit(-1)
return fmt.Errorf("cannot find self executable path for %s: %v", os.Args[0], err)
}

kernel, initrd, bios, cbfs, err := getKernelFiles(context, spec.Root.Path)
if err != nil {
fmt.Fprintf(os.Stderr, "Can't find kernel/initrd/bios/cbfs files")
os.Exit(-1)
return fmt.Errorf("can't find kernel/initrd/bios/cbfs files")
}

namespace, err = ioutil.TempDir("/run", "runv-namespace-")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create runv namespace path: %v", err)
os.Exit(-1)
return fmt.Errorf("failed to create runv namespace path: %v", err)
}

args := []string{
Expand All @@ -173,8 +165,7 @@ func runContainer(context *cli.Context, createOnly bool) {
if context.GlobalIsSet(goption) {
abs_path, err := filepath.Abs(context.GlobalString(goption))
if err != nil {
fmt.Fprintf(os.Stderr, "Cannot get abs path for %s: %v\n", goption, err)
os.Exit(-1)
return fmt.Errorf("Cannot get abs path for %s: %v\n", goption, err)
}
args = append(args, "--"+goption, abs_path)
}
Expand All @@ -195,8 +186,7 @@ func runContainer(context *cli.Context, createOnly bool) {
}
err = cmd.Start()
if err != nil {
fmt.Fprintf(os.Stderr, "failed to launch runv containerd: %v\n", err)
os.Exit(-1)
return fmt.Errorf("failed to launch runv containerd: %v", err)
}
if _, err = os.Stat(filepath.Join(namespace, "namespaced.sock")); os.IsNotExist(err) {
time.Sleep(3 * time.Second)
Expand All @@ -205,34 +195,31 @@ func runContainer(context *cli.Context, createOnly bool) {

err = createContainer(context, container, namespace, spec)
if err != nil {
fmt.Fprintf(os.Stderr, "error %v\n", err)
cmd.Process.Signal(syscall.SIGINT)
os.Exit(-1)
return fmt.Errorf("failed to create container: %v", err)
}
if !createOnly {
address := filepath.Join(namespace, "namespaced.sock")
startContainer(context, bundle, container, address, spec, context.Bool("detach"))
}
os.Exit(0)
return nil
}

func checkConsole(context *cli.Context, p *specs.Process, createOnly bool) {
func checkConsole(context *cli.Context, p *specs.Process, createOnly bool) error {
if context.String("console") != "" && context.String("console-socket") != "" {
fmt.Fprintf(os.Stderr, "only one of --console & --console-socket can be specified")
os.Exit(-1)
return fmt.Errorf("only one of --console & --console-socket can be specified")
}
detach := createOnly
if !createOnly {
detach = context.Bool("detach")
}
if (context.String("console") != "" || context.String("console-socket") != "") && !detach {
fmt.Fprintf(os.Stderr, "--console[-socket] should be used on detached mode\n")
os.Exit(-1)
return fmt.Errorf("--console[-socket] should be used on detached mode\n")
}
if (context.String("console") != "" || context.String("console-socket") != "") && !p.Terminal {
fmt.Fprintf(os.Stderr, "--console[-socket] should be used on tty mode\n")
os.Exit(-1)
return fmt.Errorf("--console[-socket] should be used on tty mode\n")
}
return nil
}

// Shared namespaces multiple containers suppurt
Expand All @@ -250,7 +237,10 @@ func checkConsole(context *cli.Context, p *specs.Process, createOnly bool) {

func createContainer(context *cli.Context, container, namespace string, config *specs.Spec) error {
address := filepath.Join(namespace, "namespaced.sock")
c := getClient(address)
c, err := getClient(address)
if err != nil {
return err
}

return ociCreate(context, container, func(stdin, stdout, stderr string) error {
r := &types.CreateContainerRequest{
Expand Down Expand Up @@ -279,8 +269,7 @@ func createContainer(context *cli.Context, container, namespace string, config *
func ociCreate(context *cli.Context, container string, createFunc func(stdin, stdout, stderr string) error) error {
path, err := osext.Executable()
if err != nil {
fmt.Fprintf(os.Stderr, "cannot find self executable path for %s: %v\n", os.Args[0], err)
os.Exit(-1)
return fmt.Errorf("cannot find self executable path for %s: %v\n", os.Args[0], err)
}

var stdin, stdout, stderr string
Expand Down
50 changes: 27 additions & 23 deletions exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,44 +85,46 @@ following will output a list of processes running in the container:
Usage: "[ignore on runv] disable the use of the subreaper used to reap reparented processes",
},
},
Action: func(context *cli.Context) {
Action: func(context *cli.Context) error {
root := context.GlobalString("root")
container := context.Args().First()

if container == "" {
fmt.Printf("Please specify container ID\n")
os.Exit(-1)
return cli.NewExitError("Please specify container ID", -1)
}
if os.Geteuid() != 0 {
fmt.Printf("runv should be run as root\n")
os.Exit(-1)
return cli.NewExitError("runv should be run as root", -1)
}

// get bundle path from state
path := filepath.Join(root, container, stateJson)
f, err := os.Open(path)
if err != nil {
fmt.Printf("open JSON configuration file failed: %v\n", err)
os.Exit(-1)
return cli.NewExitError(fmt.Sprintf("open JSON configuration file failed: %v", err), -1)
}
defer f.Close()
var s *specs.State
if err := json.NewDecoder(f).Decode(&s); err != nil {
fmt.Printf("parse JSON configuration file failed: %v\n", err)
os.Exit(-1)
return cli.NewExitError(fmt.Sprintf("parse JSON configuration file failed: %v", err), -1)
}
bundle := s.Bundle

// get process
config, err := getProcess(context, bundle)
if err != nil {
fmt.Printf("get process config failed %v\n", err)
os.Exit(-1)
return cli.NewExitError(fmt.Sprintf("get process config failed %v", err), -1)
}
if err := checkConsole(context, config, false); err != nil {
return cli.NewExitError(err.Error(), -1)
}
checkConsole(context, config, false)

code := runProcess(context, container, config)
os.Exit(code)
code, err := runProcess(context, container, config)
if code != 0 {
return cli.NewExitError(err, code)
} else if err != nil {
return cli.NewExitError(err, -1)
}
return nil
},
}

Expand Down Expand Up @@ -188,23 +190,25 @@ func getProcess(context *cli.Context, bundle string) (*specs.Process, error) {
return &p, nil
}

func runProcess(context *cli.Context, container string, config *specs.Process) int {
func runProcess(context *cli.Context, container string, config *specs.Process) (int, error) {
pid := os.Getpid()
process := fmt.Sprintf("p-%x", pid+0xabcdef) // uniq name
c := getClient(filepath.Join(context.GlobalString("root"), container, "namespace/namespaced.sock"))
c, err := getClient(filepath.Join(context.GlobalString("root"), container, "namespace/namespaced.sock"))
if err != nil {
return -1, fmt.Errorf("failed to get client: %v", err)
}
evChan := containerEvents(c, container)

if !context.Bool("detach") && config.Terminal {
s, err := term.SetRawTerminal(os.Stdin.Fd())
if err != nil {
fmt.Printf("error %v\n", err)
return -1
return -1, fmt.Errorf("failed to set raw terminal: %v", err)
}
defer term.RestoreTerminal(os.Stdin.Fd(), s)
monitorTtySize(c, container, process)
}

err := ociCreate(context, container, func(stdin, stdout, stderr string) error {
err = ociCreate(context, container, func(stdin, stdout, stderr string) error {
p := &types.AddProcessRequest{
Id: container,
Pid: process,
Expand All @@ -226,16 +230,16 @@ func runProcess(context *cli.Context, container string, config *specs.Process) i
return nil
})
if err != nil {
return -1
return -1, err
}

if !context.Bool("detach") {
for e := range evChan {
if e.Type == "exit" && e.Pid == process {
return int(e.Status)
return int(e.Status), nil
}
}
return -1
return -1, fmt.Errorf("unknown error")
}
return 0
return 0, nil
}
Loading