Merge v1.2.1-master
Signed-off-by: Emile Vauge <emile@vauge.com>
This commit is contained in:
parent
a590155b0b
commit
aeb17182b4
396 changed files with 27271 additions and 9969 deletions
21
vendor/github.com/opencontainers/runc/checkpoint.go
generated
vendored
21
vendor/github.com/opencontainers/runc/checkpoint.go
generated
vendored
|
@ -24,20 +24,37 @@ checkpointed.`,
|
|||
Flags: []cli.Flag{
|
||||
cli.StringFlag{Name: "image-path", Value: "", Usage: "path for saving criu image files"},
|
||||
cli.StringFlag{Name: "work-path", Value: "", Usage: "path for saving work files and logs"},
|
||||
cli.StringFlag{Name: "parent-path", Value: "", Usage: "path for previous criu image files in pre-dump"},
|
||||
cli.BoolFlag{Name: "leave-running", Usage: "leave the process running after checkpointing"},
|
||||
cli.BoolFlag{Name: "tcp-established", Usage: "allow open tcp connections"},
|
||||
cli.BoolFlag{Name: "ext-unix-sk", Usage: "allow external unix sockets"},
|
||||
cli.BoolFlag{Name: "shell-job", Usage: "allow shell jobs"},
|
||||
cli.StringFlag{Name: "page-server", Value: "", Usage: "ADDRESS:PORT of the page server"},
|
||||
cli.BoolFlag{Name: "file-locks", Usage: "handle file locks, for safety"},
|
||||
cli.BoolFlag{Name: "pre-dump", Usage: "dump container's memory information only, leave the container running after this"},
|
||||
cli.StringFlag{Name: "manage-cgroups-mode", Value: "", Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'"},
|
||||
cli.StringSliceFlag{Name: "empty-ns", Usage: "create a namespace, but don't restore its properies"},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
// XXX: Currently this is untested with rootless containers.
|
||||
if isRootless() {
|
||||
return fmt.Errorf("runc checkpoint requires root")
|
||||
}
|
||||
|
||||
container, err := getContainer(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
status, err := container.Status()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status == libcontainer.Created {
|
||||
fatalf("Container cannot be checkpointed in created state")
|
||||
}
|
||||
defer destroy(container)
|
||||
options := criuOptions(context)
|
||||
// these are the mandatory criu options for a container
|
||||
|
@ -95,7 +112,7 @@ func setManageCgroupsMode(context *cli.Context, options *libcontainer.CriuOpts)
|
|||
}
|
||||
}
|
||||
|
||||
var namespaceMapping = map[specs.NamespaceType]int{
|
||||
var namespaceMapping = map[specs.LinuxNamespaceType]int{
|
||||
specs.NetworkNamespace: syscall.CLONE_NEWNET,
|
||||
}
|
||||
|
||||
|
@ -103,7 +120,7 @@ func setEmptyNsMask(context *cli.Context, options *libcontainer.CriuOpts) error
|
|||
var nsmask int
|
||||
|
||||
for _, ns := range context.StringSlice("empty-ns") {
|
||||
f, exists := namespaceMapping[specs.NamespaceType(ns)]
|
||||
f, exists := namespaceMapping[specs.LinuxNamespaceType(ns)]
|
||||
if !exists {
|
||||
return fmt.Errorf("namespace %q is not supported", ns)
|
||||
}
|
||||
|
|
14
vendor/github.com/opencontainers/runc/create.go
generated
vendored
14
vendor/github.com/opencontainers/runc/create.go
generated
vendored
|
@ -29,9 +29,9 @@ command(s) that get executed on start, edit the args parameter of the spec. See
|
|||
Usage: `path to the root of the bundle directory, defaults to the current directory`,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "console",
|
||||
Name: "console-socket",
|
||||
Value: "",
|
||||
Usage: "specify the pty slave path for use with the container",
|
||||
Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "pid-file",
|
||||
|
@ -46,8 +46,18 @@ command(s) that get executed on start, edit the args parameter of the spec. See
|
|||
Name: "no-new-keyring",
|
||||
Usage: "do not create a new session keyring for the container. This will cause the container to inherit the calling processes session key",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "preserve-fds",
|
||||
Usage: "Pass N additional file descriptors to the container (stdio + $LISTEN_FDS + N in total)",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := revisePidFile(context); err != nil {
|
||||
return err
|
||||
}
|
||||
spec, err := setupSpec(context)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
25
vendor/github.com/opencontainers/runc/delete.go
generated
vendored
25
vendor/github.com/opencontainers/runc/delete.go
generated
vendored
|
@ -14,10 +14,10 @@ import (
|
|||
)
|
||||
|
||||
func killContainer(container libcontainer.Container) error {
|
||||
container.Signal(syscall.SIGKILL)
|
||||
_ = container.Signal(syscall.SIGKILL, false)
|
||||
for i := 0; i < 100; i++ {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
if err := container.Signal(syscall.Signal(0)); err != nil {
|
||||
if err := container.Signal(syscall.Signal(0), false); err != nil {
|
||||
destroy(container)
|
||||
return nil
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ func killContainer(container libcontainer.Container) error {
|
|||
|
||||
var deleteCommand = cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "delete any resources held by the container often used with detached containers",
|
||||
Usage: "delete any resources held by the container often used with detached container",
|
||||
ArgsUsage: `<container-id>
|
||||
|
||||
Where "<container-id>" is the name for the instance of the container.
|
||||
|
@ -41,21 +41,26 @@ status of "ubuntu01" as "stopped" the following will delete resources held for
|
|||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "force, f",
|
||||
Usage: "Forcibly kills the container if it is still running",
|
||||
Usage: "Forcibly deletes the container if it is still running (uses SIGKILL)",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
id := context.Args().First()
|
||||
container, err := getContainer(context)
|
||||
if err != nil {
|
||||
if lerr, ok := err.(libcontainer.Error); ok && lerr.Code() == libcontainer.ContainerNotExists {
|
||||
// if there was an aborted start or something of the sort then the container's directory could exist but
|
||||
// libcontainer does not see it because the state.json file inside that directory was never created.
|
||||
path := filepath.Join(context.GlobalString("root"), context.Args().First())
|
||||
if err := os.RemoveAll(path); err != nil {
|
||||
return err
|
||||
path := filepath.Join(context.GlobalString("root"), id)
|
||||
if e := os.RemoveAll(path); e != nil {
|
||||
fmt.Fprintf(os.Stderr, "remove %s: %v\n", path, e)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
s, err := container.Status()
|
||||
if err != nil {
|
||||
|
@ -69,9 +74,11 @@ status of "ubuntu01" as "stopped" the following will delete resources held for
|
|||
default:
|
||||
if context.Bool("force") {
|
||||
return killContainer(container)
|
||||
} else {
|
||||
return fmt.Errorf("cannot delete container %s that is not stopped: %s\n", id, s)
|
||||
}
|
||||
return fmt.Errorf("cannot delete container that is not stopped: %s", s)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
20
vendor/github.com/opencontainers/runc/events.go
generated
vendored
20
vendor/github.com/opencontainers/runc/events.go
generated
vendored
|
@ -24,7 +24,7 @@ type event struct {
|
|||
|
||||
// stats is the runc specific stats structure for stability when encoding and decoding stats.
|
||||
type stats struct {
|
||||
Cpu cpu `json:"cpu"`
|
||||
CPU cpu `json:"cpu"`
|
||||
Memory memory `json:"memory"`
|
||||
Pids pids `json:"pids"`
|
||||
Blkio blkio `json:"blkio"`
|
||||
|
@ -108,6 +108,9 @@ information is displayed once every 5 seconds.`,
|
|||
cli.BoolFlag{Name: "stats", Usage: "display the container's stats then exit"},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
container, err := getContainer(context)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -121,7 +124,6 @@ information is displayed once every 5 seconds.`,
|
|||
return err
|
||||
}
|
||||
if status == libcontainer.Stopped {
|
||||
fatalf("container with id %s is not running", container.ID())
|
||||
return fmt.Errorf("container with id %s is not running", container.ID())
|
||||
}
|
||||
var (
|
||||
|
@ -196,13 +198,13 @@ func convertLibcontainerStats(ls *libcontainer.Stats) *stats {
|
|||
s.Pids.Current = cg.PidsStats.Current
|
||||
s.Pids.Limit = cg.PidsStats.Limit
|
||||
|
||||
s.Cpu.Usage.Kernel = cg.CpuStats.CpuUsage.UsageInKernelmode
|
||||
s.Cpu.Usage.User = cg.CpuStats.CpuUsage.UsageInUsermode
|
||||
s.Cpu.Usage.Total = cg.CpuStats.CpuUsage.TotalUsage
|
||||
s.Cpu.Usage.Percpu = cg.CpuStats.CpuUsage.PercpuUsage
|
||||
s.Cpu.Throttling.Periods = cg.CpuStats.ThrottlingData.Periods
|
||||
s.Cpu.Throttling.ThrottledPeriods = cg.CpuStats.ThrottlingData.ThrottledPeriods
|
||||
s.Cpu.Throttling.ThrottledTime = cg.CpuStats.ThrottlingData.ThrottledTime
|
||||
s.CPU.Usage.Kernel = cg.CpuStats.CpuUsage.UsageInKernelmode
|
||||
s.CPU.Usage.User = cg.CpuStats.CpuUsage.UsageInUsermode
|
||||
s.CPU.Usage.Total = cg.CpuStats.CpuUsage.TotalUsage
|
||||
s.CPU.Usage.Percpu = cg.CpuStats.CpuUsage.PercpuUsage
|
||||
s.CPU.Throttling.Periods = cg.CpuStats.ThrottlingData.Periods
|
||||
s.CPU.Throttling.ThrottledPeriods = cg.CpuStats.ThrottlingData.ThrottledPeriods
|
||||
s.CPU.Throttling.ThrottledTime = cg.CpuStats.ThrottlingData.ThrottledTime
|
||||
|
||||
s.Memory.Cache = cg.MemoryStats.Cache
|
||||
s.Memory.Kernel = convertMemoryEntry(cg.MemoryStats.KernelUsage)
|
||||
|
|
49
vendor/github.com/opencontainers/runc/exec.go
generated
vendored
49
vendor/github.com/opencontainers/runc/exec.go
generated
vendored
|
@ -9,6 +9,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/urfave/cli"
|
||||
|
@ -17,20 +18,21 @@ import (
|
|||
var execCommand = cli.Command{
|
||||
Name: "exec",
|
||||
Usage: "execute new process inside the container",
|
||||
ArgsUsage: `<container-id> <container command>
|
||||
ArgsUsage: `<container-id> <command> [command options] || -p process.json <container-id>
|
||||
|
||||
Where "<container-id>" is the name for the instance of the container and
|
||||
"<container command>" is the command to be executed in the container.
|
||||
"<command>" is the command to be executed in the container.
|
||||
"<command>" can't be empty unless a "-p" flag provided.
|
||||
|
||||
EXAMPLE:
|
||||
For example, if the container is configured to run the linux ps command the
|
||||
following will output a list of processes running in the container:
|
||||
|
||||
|
||||
# runc exec <container-id> ps`,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "console",
|
||||
Usage: "specify the pty slave path for use with the container",
|
||||
Name: "console-socket",
|
||||
Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cwd",
|
||||
|
@ -79,13 +81,17 @@ following will output a list of processes running in the container:
|
|||
Usage: "add a capability to the bounding set for the process",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "no-subreaper",
|
||||
Usage: "disable the use of the subreaper used to reap reparented processes",
|
||||
Name: "no-subreaper",
|
||||
Usage: "disable the use of the subreaper used to reap reparented processes",
|
||||
Hidden: true,
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if os.Geteuid() != 0 {
|
||||
return fmt.Errorf("runc should be run as root")
|
||||
if err := checkArgs(context, 1, minArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := revisePidFile(context); err != nil {
|
||||
return err
|
||||
}
|
||||
status, err := execProcess(context)
|
||||
if err == nil {
|
||||
|
@ -93,6 +99,7 @@ following will output a list of processes running in the container:
|
|||
}
|
||||
return fmt.Errorf("exec failed: %v", err)
|
||||
},
|
||||
SkipArgReorder: true,
|
||||
}
|
||||
|
||||
func execProcess(context *cli.Context) (int, error) {
|
||||
|
@ -100,6 +107,13 @@ func execProcess(context *cli.Context) (int, error) {
|
|||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
status, err := container.Status()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if status == libcontainer.Stopped {
|
||||
return -1, fmt.Errorf("cannot exec a container that has stopped")
|
||||
}
|
||||
path := context.String("process")
|
||||
if path == "" && len(context.Args()) == 1 {
|
||||
return -1, fmt.Errorf("process args cannot be empty")
|
||||
|
@ -115,10 +129,10 @@ func execProcess(context *cli.Context) (int, error) {
|
|||
return -1, err
|
||||
}
|
||||
r := &runner{
|
||||
enableSubreaper: !context.Bool("no-subreaper"),
|
||||
enableSubreaper: false,
|
||||
shouldDestroy: false,
|
||||
container: container,
|
||||
console: context.String("console"),
|
||||
consoleSocket: context.String("console-socket"),
|
||||
detach: detach,
|
||||
pidFile: context.String("pid-file"),
|
||||
}
|
||||
|
@ -159,12 +173,17 @@ func getProcess(context *cli.Context, bundle string) (*specs.Process, error) {
|
|||
p.SelinuxLabel = l
|
||||
}
|
||||
if caps := context.StringSlice("cap"); len(caps) > 0 {
|
||||
p.Capabilities = caps
|
||||
for _, c := range caps {
|
||||
p.Capabilities.Bounding = append(p.Capabilities.Bounding, c)
|
||||
p.Capabilities.Inheritable = append(p.Capabilities.Inheritable, c)
|
||||
p.Capabilities.Effective = append(p.Capabilities.Effective, c)
|
||||
p.Capabilities.Permitted = append(p.Capabilities.Permitted, c)
|
||||
p.Capabilities.Ambient = append(p.Capabilities.Ambient, c)
|
||||
}
|
||||
}
|
||||
// append the passed env variables
|
||||
for _, e := range context.StringSlice("env") {
|
||||
p.Env = append(p.Env, e)
|
||||
}
|
||||
p.Env = append(p.Env, context.StringSlice("env")...)
|
||||
|
||||
// set the tty
|
||||
if context.IsSet("tty") {
|
||||
p.Terminal = context.Bool("tty")
|
||||
|
|
27
vendor/github.com/opencontainers/runc/kill.go
generated
vendored
27
vendor/github.com/opencontainers/runc/kill.go
generated
vendored
|
@ -52,17 +52,29 @@ var signalMap = map[string]syscall.Signal{
|
|||
var killCommand = cli.Command{
|
||||
Name: "kill",
|
||||
Usage: "kill sends the specified signal (default: SIGTERM) to the container's init process",
|
||||
ArgsUsage: `<container-id> <signal>
|
||||
ArgsUsage: `<container-id> [signal]
|
||||
|
||||
Where "<container-id>" is the name for the instance of the container and
|
||||
"<signal>" is the signal to be sent to the init process.
|
||||
"[signal]" is the signal to be sent to the init process.
|
||||
|
||||
EXAMPLE:
|
||||
For example, if the container id is "ubuntu01" the following will send a "KILL"
|
||||
signal to the init process of the "ubuntu01" container:
|
||||
|
||||
# runc kill ubuntu01 KILL`,
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Usage: "send the specified signal to all processes inside the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, minArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkArgs(context, 2, maxArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
container, err := getContainer(context)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -77,8 +89,7 @@ signal to the init process of the "ubuntu01" container:
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := container.Signal(signal); err != nil {
|
||||
if err := container.Signal(signal, context.Bool("all")); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -88,7 +99,13 @@ signal to the init process of the "ubuntu01" container:
|
|||
func parseSignal(rawSignal string) (syscall.Signal, error) {
|
||||
s, err := strconv.Atoi(rawSignal)
|
||||
if err == nil {
|
||||
return syscall.Signal(s), nil
|
||||
sig := syscall.Signal(s)
|
||||
for _, msig := range signalMap {
|
||||
if sig == msig {
|
||||
return sig, nil
|
||||
}
|
||||
}
|
||||
return -1, fmt.Errorf("unknown signal %q", rawSignal)
|
||||
}
|
||||
signal, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")]
|
||||
if !ok {
|
||||
|
|
28
vendor/github.com/opencontainers/runc/libcontainer/user/user.go
generated
vendored
28
vendor/github.com/opencontainers/runc/libcontainer/user/user.go
generated
vendored
|
@ -199,18 +199,16 @@ type ExecUser struct {
|
|||
// files cannot be opened for any reason, the error is ignored and a nil
|
||||
// io.Reader is passed instead.
|
||||
func GetExecUserPath(userSpec string, defaults *ExecUser, passwdPath, groupPath string) (*ExecUser, error) {
|
||||
passwd, err := os.Open(passwdPath)
|
||||
if err != nil {
|
||||
passwd = nil
|
||||
} else {
|
||||
defer passwd.Close()
|
||||
var passwd, group io.Reader
|
||||
|
||||
if passwdFile, err := os.Open(passwdPath); err == nil {
|
||||
passwd = passwdFile
|
||||
defer passwdFile.Close()
|
||||
}
|
||||
|
||||
group, err := os.Open(groupPath)
|
||||
if err != nil {
|
||||
group = nil
|
||||
} else {
|
||||
defer group.Close()
|
||||
if groupFile, err := os.Open(groupPath); err == nil {
|
||||
group = groupFile
|
||||
defer groupFile.Close()
|
||||
}
|
||||
|
||||
return GetExecUser(userSpec, defaults, passwd, group)
|
||||
|
@ -343,7 +341,7 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) (
|
|||
if len(groups) > 0 {
|
||||
// First match wins, even if there's more than one matching entry.
|
||||
user.Gid = groups[0].Gid
|
||||
} else if groupArg != "" {
|
||||
} else {
|
||||
// If we can't find a group with the given name, the only other valid
|
||||
// option is if it's a numeric group name with no associated entry in group.
|
||||
|
||||
|
@ -433,9 +431,11 @@ func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, err
|
|||
// that opens the groupPath given and gives it as an argument to
|
||||
// GetAdditionalGroups.
|
||||
func GetAdditionalGroupsPath(additionalGroups []string, groupPath string) ([]int, error) {
|
||||
group, err := os.Open(groupPath)
|
||||
if err == nil {
|
||||
defer group.Close()
|
||||
var group io.Reader
|
||||
|
||||
if groupFile, err := os.Open(groupPath); err == nil {
|
||||
group = groupFile
|
||||
defer groupFile.Close()
|
||||
}
|
||||
return GetAdditionalGroups(additionalGroups, group)
|
||||
}
|
||||
|
|
44
vendor/github.com/opencontainers/runc/list.go
generated
vendored
44
vendor/github.com/opencontainers/runc/list.go
generated
vendored
|
@ -7,11 +7,14 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/user"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
@ -21,6 +24,8 @@ const formatOptions = `table or json`
|
|||
// containerState represents the platform agnostic pieces relating to a
|
||||
// running container's status and state
|
||||
type containerState struct {
|
||||
// Version is the OCI version for the container
|
||||
Version string `json:"ociVersion"`
|
||||
// ID is the container ID
|
||||
ID string `json:"id"`
|
||||
// InitProcessPid is the init process id in the parent namespace
|
||||
|
@ -29,10 +34,14 @@ type containerState struct {
|
|||
Status string `json:"status"`
|
||||
// Bundle is the path on the filesystem to the bundle
|
||||
Bundle string `json:"bundle"`
|
||||
// Rootfs is a path to a directory containing the container's root filesystem.
|
||||
Rootfs string `json:"rootfs"`
|
||||
// Created is the unix timestamp for the creation time of the container in UTC
|
||||
Created time.Time `json:"created"`
|
||||
// Annotations is the user defined annotations added to the config.
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
// The owner of the state directory (the owner of the container).
|
||||
Owner string `json:"owner"`
|
||||
}
|
||||
|
||||
var listCommand = cli.Command{
|
||||
|
@ -62,6 +71,9 @@ To list containers created using a non-default value for "--root":
|
|||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 0, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
s, err := getContainers(context)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -77,14 +89,15 @@ To list containers created using a non-default value for "--root":
|
|||
switch context.String("format") {
|
||||
case "table":
|
||||
w := tabwriter.NewWriter(os.Stdout, 12, 1, 3, ' ', 0)
|
||||
fmt.Fprint(w, "ID\tPID\tSTATUS\tBUNDLE\tCREATED\n")
|
||||
fmt.Fprint(w, "ID\tPID\tSTATUS\tBUNDLE\tCREATED\tOWNER\n")
|
||||
for _, item := range s {
|
||||
fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\n",
|
||||
fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\n",
|
||||
item.ID,
|
||||
item.InitProcessPid,
|
||||
item.Status,
|
||||
item.Bundle,
|
||||
item.Created.Format(time.RFC3339Nano))
|
||||
item.Created.Format(time.RFC3339Nano),
|
||||
item.Owner)
|
||||
}
|
||||
if err := w.Flush(); err != nil {
|
||||
return err
|
||||
|
@ -118,26 +131,43 @@ func getContainers(context *cli.Context) ([]containerState, error) {
|
|||
var s []containerState
|
||||
for _, item := range list {
|
||||
if item.IsDir() {
|
||||
// This cast is safe on Linux.
|
||||
stat := item.Sys().(*syscall.Stat_t)
|
||||
owner, err := user.LookupUid(int(stat.Uid))
|
||||
if err != nil {
|
||||
owner.Name = string(stat.Uid)
|
||||
}
|
||||
|
||||
container, err := factory.Load(item.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
fmt.Fprintf(os.Stderr, "load container %s: %v\n", item.Name(), err)
|
||||
continue
|
||||
}
|
||||
containerStatus, err := container.Status()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
fmt.Fprintf(os.Stderr, "status for %s: %v\n", item.Name(), err)
|
||||
continue
|
||||
}
|
||||
state, err := container.State()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
fmt.Fprintf(os.Stderr, "state for %s: %v\n", item.Name(), err)
|
||||
continue
|
||||
}
|
||||
pid := state.BaseState.InitProcessPid
|
||||
if containerStatus == libcontainer.Stopped {
|
||||
pid = 0
|
||||
}
|
||||
bundle, annotations := utils.Annotations(state.Config.Labels)
|
||||
s = append(s, containerState{
|
||||
Version: state.BaseState.Config.Version,
|
||||
ID: state.BaseState.ID,
|
||||
InitProcessPid: state.BaseState.InitProcessPid,
|
||||
InitProcessPid: pid,
|
||||
Status: containerStatus.String(),
|
||||
Bundle: bundle,
|
||||
Rootfs: state.BaseState.Config.Rootfs,
|
||||
Created: state.BaseState.Created,
|
||||
Annotations: annotations,
|
||||
Owner: owner.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
14
vendor/github.com/opencontainers/runc/main.go
generated
vendored
14
vendor/github.com/opencontainers/runc/main.go
generated
vendored
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
|
@ -129,7 +130,20 @@ func main() {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
// If the command returns an error, cli takes upon itself to print
|
||||
// the error on cli.ErrWriter and exit.
|
||||
// Use our own writer here to ensure the log gets sent to the right location.
|
||||
cli.ErrWriter = &FatalWriter{cli.ErrWriter}
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
type FatalWriter struct {
|
||||
cliErrWriter io.Writer
|
||||
}
|
||||
|
||||
func (f *FatalWriter) Write(p []byte) (n int, err error) {
|
||||
logrus.Error(string(p))
|
||||
return f.cliErrWriter.Write(p)
|
||||
}
|
||||
|
|
108
vendor/github.com/opencontainers/runc/notify_socket.go
generated
vendored
Normal file
108
vendor/github.com/opencontainers/runc/notify_socket.go
generated
vendored
Normal file
|
@ -0,0 +1,108 @@
|
|||
// +build linux
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type notifySocket struct {
|
||||
socket *net.UnixConn
|
||||
host string
|
||||
socketPath string
|
||||
}
|
||||
|
||||
func newNotifySocket(context *cli.Context, notifySocketHost string, id string) *notifySocket {
|
||||
if notifySocketHost == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
root := filepath.Join(context.GlobalString("root"), id)
|
||||
path := filepath.Join(root, "notify.sock")
|
||||
|
||||
notifySocket := ¬ifySocket{
|
||||
socket: nil,
|
||||
host: notifySocketHost,
|
||||
socketPath: path,
|
||||
}
|
||||
|
||||
return notifySocket
|
||||
}
|
||||
|
||||
func (ns *notifySocket) Close() error {
|
||||
return ns.socket.Close()
|
||||
}
|
||||
|
||||
// If systemd is supporting sd_notify protocol, this function will add support
|
||||
// for sd_notify protocol from within the container.
|
||||
func (s *notifySocket) setupSpec(context *cli.Context, spec *specs.Spec) {
|
||||
mount := specs.Mount{Destination: s.host, Type: "bind", Source: s.socketPath, Options: []string{"bind"}}
|
||||
spec.Mounts = append(spec.Mounts, mount)
|
||||
spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", s.host))
|
||||
}
|
||||
|
||||
func (s *notifySocket) setupSocket() error {
|
||||
addr := net.UnixAddr{
|
||||
Name: s.socketPath,
|
||||
Net: "unixgram",
|
||||
}
|
||||
|
||||
socket, err := net.ListenUnixgram("unixgram", &addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.socket = socket
|
||||
return nil
|
||||
}
|
||||
|
||||
// pid1 must be set only with -d, as it is used to set the new process as the main process
|
||||
// for the service in systemd
|
||||
func (notifySocket *notifySocket) run(pid1 int) {
|
||||
buf := make([]byte, 512)
|
||||
notifySocketHostAddr := net.UnixAddr{Name: notifySocket.host, Net: "unixgram"}
|
||||
client, err := net.DialUnix("unixgram", nil, ¬ifySocketHostAddr)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return
|
||||
}
|
||||
for {
|
||||
r, err := notifySocket.socket.Read(buf)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
var out bytes.Buffer
|
||||
for _, line := range bytes.Split(buf[0:r], []byte{'\n'}) {
|
||||
if bytes.HasPrefix(line, []byte("READY=")) {
|
||||
_, err = out.Write(line)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = out.Write([]byte{'\n'})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = client.Write(out.Bytes())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// now we can inform systemd to use pid1 as the pid to monitor
|
||||
if pid1 > 0 {
|
||||
newPid := fmt.Sprintf("MAINPID=%d\n", pid1)
|
||||
client.Write([]byte(newPid))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
8
vendor/github.com/opencontainers/runc/pause.go
generated
vendored
8
vendor/github.com/opencontainers/runc/pause.go
generated
vendored
|
@ -15,6 +15,9 @@ paused. `,
|
|||
|
||||
Use runc list to identiy instances of containers and their current status.`,
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
container, err := getContainer(context)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -22,6 +25,7 @@ Use runc list to identiy instances of containers and their current status.`,
|
|||
if err := container.Pause(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -37,6 +41,9 @@ resumed.`,
|
|||
|
||||
Use runc list to identiy instances of containers and their current status.`,
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
container, err := getContainer(context)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -44,6 +51,7 @@ Use runc list to identiy instances of containers and their current status.`,
|
|||
if err := container.Resume(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
37
vendor/github.com/opencontainers/runc/ps.go
generated
vendored
37
vendor/github.com/opencontainers/runc/ps.go
generated
vendored
|
@ -20,11 +20,19 @@ var psCommand = cli.Command{
|
|||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "format, f",
|
||||
Value: "",
|
||||
Value: "table",
|
||||
Usage: `select one of: ` + formatOptions,
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, minArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
// XXX: Currently not supported with rootless containers.
|
||||
if isRootless() {
|
||||
return fmt.Errorf("runc ps requires root")
|
||||
}
|
||||
|
||||
container, err := getContainer(context)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -35,21 +43,27 @@ var psCommand = cli.Command{
|
|||
return err
|
||||
}
|
||||
|
||||
if context.String("format") == "json" {
|
||||
if err := json.NewEncoder(os.Stdout).Encode(pids); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
switch context.String("format") {
|
||||
case "table":
|
||||
case "json":
|
||||
return json.NewEncoder(os.Stdout).Encode(pids)
|
||||
default:
|
||||
return fmt.Errorf("invalid format option")
|
||||
}
|
||||
|
||||
psArgs := context.Args().Get(1)
|
||||
if psArgs == "" {
|
||||
psArgs = "-ef"
|
||||
// [1:] is to remove command name, ex:
|
||||
// context.Args(): [containet_id ps_arg1 ps_arg2 ...]
|
||||
// psArgs: [ps_arg1 ps_arg2 ...]
|
||||
//
|
||||
psArgs := context.Args()[1:]
|
||||
if len(psArgs) == 0 {
|
||||
psArgs = []string{"-ef"}
|
||||
}
|
||||
|
||||
output, err := exec.Command("ps", strings.Split(psArgs, " ")...).Output()
|
||||
cmd := exec.Command("ps", psArgs...)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("%s: %s", err, output)
|
||||
}
|
||||
|
||||
lines := strings.Split(string(output), "\n")
|
||||
|
@ -78,6 +92,7 @@ var psCommand = cli.Command{
|
|||
}
|
||||
return nil
|
||||
},
|
||||
SkipArgReorder: true,
|
||||
}
|
||||
|
||||
func getPidIndex(title string) (int, error) {
|
||||
|
|
36
vendor/github.com/opencontainers/runc/restore.go
generated
vendored
36
vendor/github.com/opencontainers/runc/restore.go
generated
vendored
|
@ -3,6 +3,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
|
@ -83,6 +84,14 @@ using the runc checkpoint command.`,
|
|||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
// XXX: Currently this is untested with rootless containers.
|
||||
if isRootless() {
|
||||
return fmt.Errorf("runc restore requires root")
|
||||
}
|
||||
|
||||
imagePath := context.String("image-path")
|
||||
id := context.Args().First()
|
||||
if id == "" {
|
||||
|
@ -147,7 +156,7 @@ func restoreContainer(context *cli.Context, spec *specs.Spec, config *configs.Co
|
|||
|
||||
setManageCgroupsMode(context, options)
|
||||
|
||||
if err := setEmptyNsMask(context, options); err != nil {
|
||||
if err = setEmptyNsMask(context, options); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
|
@ -158,29 +167,34 @@ func restoreContainer(context *cli.Context, spec *specs.Spec, config *configs.Co
|
|||
defer destroy(container)
|
||||
}
|
||||
process := &libcontainer.Process{}
|
||||
tty, err := setupIO(process, rootuid, rootgid, "", false, detach)
|
||||
tty, err := setupIO(process, rootuid, rootgid, false, detach, "")
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
defer tty.Close()
|
||||
handler := newSignalHandler(tty, !context.Bool("no-subreaper"))
|
||||
|
||||
notifySocket := newNotifySocket(context, os.Getenv("NOTIFY_SOCKET"), id)
|
||||
if notifySocket != nil {
|
||||
notifySocket.setupSpec(context, spec)
|
||||
notifySocket.setupSocket()
|
||||
}
|
||||
|
||||
handler := newSignalHandler(!context.Bool("no-subreaper"), notifySocket)
|
||||
if err := container.Restore(process, options); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
// We don't need to do a tty.recvtty because config.Terminal is always false.
|
||||
defer tty.Close()
|
||||
if err := tty.ClosePostStart(); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if pidFile := context.String("pid-file"); pidFile != "" {
|
||||
if err := createPidFile(pidFile, process); err != nil {
|
||||
process.Signal(syscall.SIGKILL)
|
||||
process.Wait()
|
||||
_ = process.Signal(syscall.SIGKILL)
|
||||
_, _ = process.Wait()
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
if detach {
|
||||
return 0, nil
|
||||
}
|
||||
return handler.forward(process)
|
||||
return handler.forward(process, tty, detach)
|
||||
}
|
||||
|
||||
func criuOptions(context *cli.Context) *libcontainer.CriuOpts {
|
||||
|
@ -191,10 +205,12 @@ func criuOptions(context *cli.Context) *libcontainer.CriuOpts {
|
|||
return &libcontainer.CriuOpts{
|
||||
ImagesDirectory: imagePath,
|
||||
WorkDirectory: context.String("work-path"),
|
||||
ParentImage: context.String("parent-path"),
|
||||
LeaveRunning: context.Bool("leave-running"),
|
||||
TcpEstablished: context.Bool("tcp-established"),
|
||||
ExternalUnixConnections: context.Bool("ext-unix-sk"),
|
||||
ShellJob: context.Bool("shell-job"),
|
||||
FileLocks: context.Bool("file-locks"),
|
||||
PreDump: context.Bool("pre-dump"),
|
||||
}
|
||||
}
|
||||
|
|
2
vendor/github.com/opencontainers/runc/rlimit_linux.go
generated
vendored
2
vendor/github.com/opencontainers/runc/rlimit_linux.go
generated
vendored
|
@ -43,7 +43,7 @@ var rlimitMap = map[string]int{
|
|||
func strToRlimit(key string) (int, error) {
|
||||
rl, ok := rlimitMap[key]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("Wrong rlimit value: %s", key)
|
||||
return 0, fmt.Errorf("wrong rlimit value: %s", key)
|
||||
}
|
||||
return rl, nil
|
||||
}
|
||||
|
|
14
vendor/github.com/opencontainers/runc/run.go
generated
vendored
14
vendor/github.com/opencontainers/runc/run.go
generated
vendored
|
@ -32,9 +32,9 @@ command(s) that get executed on start, edit the args parameter of the spec. See
|
|||
Usage: `path to the root of the bundle directory, defaults to the current directory`,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "console",
|
||||
Name: "console-socket",
|
||||
Value: "",
|
||||
Usage: "specify the pty slave path for use with the container",
|
||||
Usage: "path to an AF_UNIX socket which will receive a file descriptor referencing the master end of the console's pseudoterminal",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "detach, d",
|
||||
|
@ -57,8 +57,18 @@ command(s) that get executed on start, edit the args parameter of the spec. See
|
|||
Name: "no-new-keyring",
|
||||
Usage: "do not create a new session keyring for the container. This will cause the container to inherit the calling processes session key",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "preserve-fds",
|
||||
Usage: "Pass N additional file descriptors to the container (stdio + $LISTEN_FDS + N in total)",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := revisePidFile(context); err != nil {
|
||||
return err
|
||||
}
|
||||
spec, err := setupSpec(context)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
35
vendor/github.com/opencontainers/runc/signals.go
generated
vendored
35
vendor/github.com/opencontainers/runc/signals.go
generated
vendored
|
@ -17,7 +17,9 @@ const signalBufferSize = 2048
|
|||
|
||||
// newSignalHandler returns a signal handler for processing SIGCHLD and SIGWINCH signals
|
||||
// while still forwarding all other signals to the process.
|
||||
func newSignalHandler(tty *tty, enableSubreaper bool) *signalHandler {
|
||||
// If notifySocket is present, use it to read systemd notifications from the container and
|
||||
// forward them to notifySocketHost.
|
||||
func newSignalHandler(enableSubreaper bool, notifySocket *notifySocket) *signalHandler {
|
||||
if enableSubreaper {
|
||||
// set us as the subreaper before registering the signal handler for the container
|
||||
if err := system.SetSubreaper(1); err != nil {
|
||||
|
@ -30,8 +32,8 @@ func newSignalHandler(tty *tty, enableSubreaper bool) *signalHandler {
|
|||
// handle all signals for the process.
|
||||
signal.Notify(s)
|
||||
return &signalHandler{
|
||||
tty: tty,
|
||||
signals: s,
|
||||
signals: s,
|
||||
notifySocket: notifySocket,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,25 +45,39 @@ type exit struct {
|
|||
}
|
||||
|
||||
type signalHandler struct {
|
||||
signals chan os.Signal
|
||||
tty *tty
|
||||
signals chan os.Signal
|
||||
notifySocket *notifySocket
|
||||
}
|
||||
|
||||
// forward handles the main signal event loop forwarding, resizing, or reaping depending
|
||||
// on the signal received.
|
||||
func (h *signalHandler) forward(process *libcontainer.Process) (int, error) {
|
||||
func (h *signalHandler) forward(process *libcontainer.Process, tty *tty, detach bool) (int, error) {
|
||||
// make sure we know the pid of our main process so that we can return
|
||||
// after it dies.
|
||||
if detach && h.notifySocket == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
pid1, err := process.Pid()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if h.notifySocket != nil {
|
||||
if detach {
|
||||
h.notifySocket.run(pid1)
|
||||
return 0, nil
|
||||
} else {
|
||||
go h.notifySocket.run(0)
|
||||
}
|
||||
}
|
||||
|
||||
// perform the initial tty resize.
|
||||
h.tty.resize()
|
||||
tty.resize()
|
||||
for s := range h.signals {
|
||||
switch s {
|
||||
case syscall.SIGWINCH:
|
||||
h.tty.resize()
|
||||
tty.resize()
|
||||
case syscall.SIGCHLD:
|
||||
exits, err := h.reap()
|
||||
if err != nil {
|
||||
|
@ -77,6 +93,9 @@ func (h *signalHandler) forward(process *libcontainer.Process) (int, error) {
|
|||
// status because we must ensure that any of the go specific process
|
||||
// fun such as flushing pipes are complete before we return.
|
||||
process.Wait()
|
||||
if h.notifySocket != nil {
|
||||
h.notifySocket.Close()
|
||||
}
|
||||
return e.status, nil
|
||||
}
|
||||
}
|
||||
|
|
167
vendor/github.com/opencontainers/runc/spec.go
generated
vendored
167
vendor/github.com/opencontainers/runc/spec.go
generated
vendored
|
@ -10,6 +10,7 @@ import (
|
|||
"runtime"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/specconv"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
@ -48,9 +49,9 @@ In the run command above, "container1" is the name for the instance of the
|
|||
container that you are starting. The name you provide for the container instance
|
||||
must be unique on your host.
|
||||
|
||||
An alternative for generating a customized spec config is to use "ocitools", the
|
||||
sub-command "ocitools generate" has lots of options that can be used to do any
|
||||
customizations as you want, see [ocitools](https://github.com/opencontainers/ocitools)
|
||||
An alternative for generating a customized spec config is to use "oci-runtime-tool", the
|
||||
sub-command "oci-runtime-tool generate" has lots of options that can be used to do any
|
||||
customizations as you want, see [runtime-tools](https://github.com/opencontainers/runtime-tools)
|
||||
to get more information.
|
||||
|
||||
When starting a container through runc, runc needs root privilege. If not
|
||||
|
@ -63,129 +64,20 @@ container on your host.`,
|
|||
Value: "",
|
||||
Usage: "path to the root of the bundle directory",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "rootless",
|
||||
Usage: "generate a configuration for a rootless container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
spec := specs.Spec{
|
||||
Version: specs.Version,
|
||||
Platform: specs.Platform{
|
||||
OS: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
},
|
||||
Root: specs.Root{
|
||||
Path: "rootfs",
|
||||
Readonly: true,
|
||||
},
|
||||
Process: specs.Process{
|
||||
Terminal: true,
|
||||
User: specs.User{},
|
||||
Args: []string{
|
||||
"sh",
|
||||
},
|
||||
Env: []string{
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"TERM=xterm",
|
||||
},
|
||||
Cwd: "/",
|
||||
NoNewPrivileges: true,
|
||||
Capabilities: []string{
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_KILL",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
},
|
||||
Rlimits: []specs.Rlimit{
|
||||
{
|
||||
Type: "RLIMIT_NOFILE",
|
||||
Hard: uint64(1024),
|
||||
Soft: uint64(1024),
|
||||
},
|
||||
},
|
||||
},
|
||||
Hostname: "runc",
|
||||
Mounts: []specs.Mount{
|
||||
{
|
||||
Destination: "/proc",
|
||||
Type: "proc",
|
||||
Source: "proc",
|
||||
Options: nil,
|
||||
},
|
||||
{
|
||||
Destination: "/dev",
|
||||
Type: "tmpfs",
|
||||
Source: "tmpfs",
|
||||
Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/pts",
|
||||
Type: "devpts",
|
||||
Source: "devpts",
|
||||
Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/shm",
|
||||
Type: "tmpfs",
|
||||
Source: "shm",
|
||||
Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/mqueue",
|
||||
Type: "mqueue",
|
||||
Source: "mqueue",
|
||||
Options: []string{"nosuid", "noexec", "nodev"},
|
||||
},
|
||||
{
|
||||
Destination: "/sys",
|
||||
Type: "sysfs",
|
||||
Source: "sysfs",
|
||||
Options: []string{"nosuid", "noexec", "nodev", "ro"},
|
||||
},
|
||||
{
|
||||
Destination: "/sys/fs/cgroup",
|
||||
Type: "cgroup",
|
||||
Source: "cgroup",
|
||||
Options: []string{"nosuid", "noexec", "nodev", "relatime", "ro"},
|
||||
},
|
||||
},
|
||||
Linux: specs.Linux{
|
||||
MaskedPaths: []string{
|
||||
"/proc/kcore",
|
||||
"/proc/latency_stats",
|
||||
"/proc/timer_stats",
|
||||
"/proc/sched_debug",
|
||||
},
|
||||
ReadonlyPaths: []string{
|
||||
"/proc/asound",
|
||||
"/proc/bus",
|
||||
"/proc/fs",
|
||||
"/proc/irq",
|
||||
"/proc/sys",
|
||||
"/proc/sysrq-trigger",
|
||||
},
|
||||
Resources: &specs.Resources{
|
||||
Devices: []specs.DeviceCgroup{
|
||||
{
|
||||
Allow: false,
|
||||
Access: sPtr("rwm"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Namespaces: []specs.Namespace{
|
||||
{
|
||||
Type: "pid",
|
||||
},
|
||||
{
|
||||
Type: "network",
|
||||
},
|
||||
{
|
||||
Type: "ipc",
|
||||
},
|
||||
{
|
||||
Type: "uts",
|
||||
},
|
||||
{
|
||||
Type: "mount",
|
||||
},
|
||||
},
|
||||
},
|
||||
if err := checkArgs(context, 0, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
spec := specconv.Example()
|
||||
|
||||
rootless := context.Bool("rootless")
|
||||
if rootless {
|
||||
specconv.ToRootless(spec)
|
||||
}
|
||||
|
||||
checkNoFile := func(name string) error {
|
||||
|
@ -207,7 +99,7 @@ container on your host.`,
|
|||
if err := checkNoFile(specConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.MarshalIndent(&spec, "", "\t")
|
||||
data, err := json.MarshalIndent(spec, "", "\t")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -218,11 +110,7 @@ container on your host.`,
|
|||
},
|
||||
}
|
||||
|
||||
func sPtr(s string) *string { return &s }
|
||||
func rPtr(r rune) *rune { return &r }
|
||||
func iPtr(i int64) *int64 { return &i }
|
||||
func u32Ptr(i int64) *uint32 { u := uint32(i); return &u }
|
||||
func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm }
|
||||
func sPtr(s string) *string { return &s }
|
||||
|
||||
// loadSpec loads the specification from the provided path.
|
||||
func loadSpec(cPath string) (spec *specs.Spec, err error) {
|
||||
|
@ -238,17 +126,30 @@ func loadSpec(cPath string) (spec *specs.Spec, err error) {
|
|||
if err = json.NewDecoder(cf).Decode(&spec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = validatePlatform(&spec.Platform); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return spec, validateProcessSpec(&spec.Process)
|
||||
}
|
||||
|
||||
func createLibContainerRlimit(rlimit specs.Rlimit) (configs.Rlimit, error) {
|
||||
func createLibContainerRlimit(rlimit specs.LinuxRlimit) (configs.Rlimit, error) {
|
||||
rl, err := strToRlimit(rlimit.Type)
|
||||
if err != nil {
|
||||
return configs.Rlimit{}, err
|
||||
}
|
||||
return configs.Rlimit{
|
||||
Type: rl,
|
||||
Hard: uint64(rlimit.Hard),
|
||||
Soft: uint64(rlimit.Soft),
|
||||
Hard: rlimit.Hard,
|
||||
Soft: rlimit.Soft,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func validatePlatform(platform *specs.Platform) error {
|
||||
if platform.OS != runtime.GOOS {
|
||||
return fmt.Errorf("target os %s mismatch with current os %s", platform.OS, runtime.GOOS)
|
||||
}
|
||||
if platform.Arch != runtime.GOARCH {
|
||||
return fmt.Errorf("target arch %s mismatch with current arch %s", platform.Arch, runtime.GOARCH)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
14
vendor/github.com/opencontainers/runc/start.go
generated
vendored
14
vendor/github.com/opencontainers/runc/start.go
generated
vendored
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
|
@ -9,14 +10,17 @@ import (
|
|||
|
||||
var startCommand = cli.Command{
|
||||
Name: "start",
|
||||
Usage: "start signals a created container to execute the user defined process",
|
||||
Usage: "executes the user defined process in a created container",
|
||||
ArgsUsage: `<container-id>
|
||||
|
||||
Where "<container-id>" is your name for the instance of the container that you
|
||||
are starting. The name you provide for the container instance must be unique on
|
||||
your host.`,
|
||||
Description: `The start command signals the container to start the user's defined process.`,
|
||||
Description: `The start command executes the user defined process in a created container.`,
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
container, err := getContainer(context)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -29,11 +33,11 @@ your host.`,
|
|||
case libcontainer.Created:
|
||||
return container.Exec()
|
||||
case libcontainer.Stopped:
|
||||
return fmt.Errorf("cannot start a container that has run and stopped")
|
||||
return errors.New("cannot start a container that has stopped")
|
||||
case libcontainer.Running:
|
||||
return fmt.Errorf("cannot start an already running container")
|
||||
return errors.New("cannot start an already running container")
|
||||
default:
|
||||
return fmt.Errorf("cannot start a container in the %s state", status)
|
||||
return fmt.Errorf("cannot start a container in the %s state\n", status)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
36
vendor/github.com/opencontainers/runc/state.go
generated
vendored
36
vendor/github.com/opencontainers/runc/state.go
generated
vendored
|
@ -5,35 +5,12 @@ package main
|
|||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// cState represents the platform agnostic pieces relating to a running
|
||||
// container's status and state. Note: The fields in this structure adhere to
|
||||
// the opencontainers/runtime-spec/specs-go requirement for json fields that must be returned
|
||||
// in a state command.
|
||||
type cState struct {
|
||||
// Version is the OCI version for the container
|
||||
Version string `json:"ociVersion"`
|
||||
// ID is the container ID
|
||||
ID string `json:"id"`
|
||||
// InitProcessPid is the init process id in the parent namespace
|
||||
InitProcessPid int `json:"pid"`
|
||||
// Bundle is the path on the filesystem to the bundle
|
||||
Bundle string `json:"bundlePath"`
|
||||
// Rootfs is a path to a directory containing the container's root filesystem.
|
||||
Rootfs string `json:"rootfsPath"`
|
||||
// Status is the current status of the container, running, paused, ...
|
||||
Status string `json:"status"`
|
||||
// Created is the unix timestamp for the creation time of the container in UTC
|
||||
Created time.Time `json:"created"`
|
||||
// Annotations is the user defined annotations added to the config.
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
var stateCommand = cli.Command{
|
||||
Name: "state",
|
||||
Usage: "output the state of a container",
|
||||
|
@ -43,6 +20,9 @@ Where "<container-id>" is your name for the instance of the container.`,
|
|||
Description: `The state command outputs current state information for the
|
||||
instance of a container.`,
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
container, err := getContainer(context)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -55,11 +35,15 @@ instance of a container.`,
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pid := state.BaseState.InitProcessPid
|
||||
if containerStatus == libcontainer.Stopped {
|
||||
pid = 0
|
||||
}
|
||||
bundle, annotations := utils.Annotations(state.Config.Labels)
|
||||
cs := cState{
|
||||
cs := containerState{
|
||||
Version: state.BaseState.Config.Version,
|
||||
ID: state.BaseState.ID,
|
||||
InitProcessPid: state.BaseState.InitProcessPid,
|
||||
InitProcessPid: pid,
|
||||
Status: containerStatus.String(),
|
||||
Bundle: bundle,
|
||||
Rootfs: state.BaseState.Config.Rootfs,
|
||||
|
|
74
vendor/github.com/opencontainers/runc/tty.go
generated
vendored
74
vendor/github.com/opencontainers/runc/tty.go
generated
vendored
|
@ -10,11 +10,27 @@ import (
|
|||
|
||||
"github.com/docker/docker/pkg/term"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
)
|
||||
|
||||
// setup standard pipes so that the TTY of the calling runc process
|
||||
// is not inherited by the container.
|
||||
func createStdioPipes(p *libcontainer.Process, rootuid, rootgid int) (*tty, error) {
|
||||
type tty struct {
|
||||
console libcontainer.Console
|
||||
state *term.State
|
||||
closers []io.Closer
|
||||
postStart []io.Closer
|
||||
wg sync.WaitGroup
|
||||
consoleC chan error
|
||||
}
|
||||
|
||||
func (t *tty) copyIO(w io.Writer, r io.ReadCloser) {
|
||||
defer t.wg.Done()
|
||||
io.Copy(w, r)
|
||||
r.Close()
|
||||
}
|
||||
|
||||
// setup pipes for the process so that advanced features like c/r are able to easily checkpoint
|
||||
// and restore the process's IO without depending on a host specific path or device
|
||||
func setupProcessPipes(p *libcontainer.Process, rootuid, rootgid int) (*tty, error) {
|
||||
i, err := p.InitializeIO(rootuid, rootgid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -46,45 +62,37 @@ func createStdioPipes(p *libcontainer.Process, rootuid, rootgid int) (*tty, erro
|
|||
return t, nil
|
||||
}
|
||||
|
||||
func (t *tty) copyIO(w io.Writer, r io.ReadCloser) {
|
||||
defer t.wg.Done()
|
||||
io.Copy(w, r)
|
||||
r.Close()
|
||||
func inheritStdio(process *libcontainer.Process) error {
|
||||
process.Stdin = os.Stdin
|
||||
process.Stdout = os.Stdout
|
||||
process.Stderr = os.Stderr
|
||||
return nil
|
||||
}
|
||||
|
||||
func createTty(p *libcontainer.Process, rootuid, rootgid int, consolePath string) (*tty, error) {
|
||||
if consolePath != "" {
|
||||
if err := p.ConsoleFromPath(consolePath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tty{}, nil
|
||||
}
|
||||
console, err := p.NewConsole(rootuid, rootgid)
|
||||
func (t *tty) recvtty(process *libcontainer.Process, socket *os.File) error {
|
||||
f, err := utils.RecvFd(socket)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
console := libcontainer.ConsoleFromFile(f)
|
||||
go io.Copy(console, os.Stdin)
|
||||
go io.Copy(os.Stdout, console)
|
||||
|
||||
t.wg.Add(1)
|
||||
go t.copyIO(os.Stdout, console)
|
||||
state, err := term.SetRawTerminal(os.Stdin.Fd())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to set the terminal from the stdin: %v", err)
|
||||
return fmt.Errorf("failed to set the terminal from the stdin: %v", err)
|
||||
}
|
||||
return &tty{
|
||||
console: console,
|
||||
state: state,
|
||||
closers: []io.Closer{
|
||||
console,
|
||||
},
|
||||
}, nil
|
||||
t.state = state
|
||||
t.console = console
|
||||
t.closers = []io.Closer{console}
|
||||
return nil
|
||||
}
|
||||
|
||||
type tty struct {
|
||||
console libcontainer.Console
|
||||
state *term.State
|
||||
closers []io.Closer
|
||||
postStart []io.Closer
|
||||
wg sync.WaitGroup
|
||||
func (t *tty) waitConsole() error {
|
||||
if t.consoleC != nil {
|
||||
return <-t.consoleC
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClosePostStart closes any fds that are provided to the container and dup2'd
|
||||
|
@ -122,5 +130,5 @@ func (t *tty) resize() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return term.SetWinsize(t.console.Fd(), ws)
|
||||
return term.SetWinsize(t.console.File().Fd(), ws)
|
||||
}
|
||||
|
|
133
vendor/github.com/opencontainers/runc/update.go
generated
vendored
133
vendor/github.com/opencontainers/runc/update.go
generated
vendored
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func i64Ptr(i int64) *int64 { return &i }
|
||||
func u64Ptr(i uint64) *uint64 { return &i }
|
||||
func u16Ptr(i uint16) *uint16 { return &i }
|
||||
|
||||
|
@ -40,12 +41,14 @@ The accepted format is as follow (unchanged values can be omitted):
|
|||
"shares": 0,
|
||||
"quota": 0,
|
||||
"period": 0,
|
||||
"realtimeRuntime": 0,
|
||||
"realtimePeriod": 0,
|
||||
"cpus": "",
|
||||
"mems": ""
|
||||
},
|
||||
"blockIO": {
|
||||
"blkioWeight": 0
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Note: if data is to be read from a file or the standard input, all
|
||||
|
@ -59,16 +62,24 @@ other options are ignored.
|
|||
},
|
||||
cli.StringFlag{
|
||||
Name: "cpu-period",
|
||||
Usage: "CPU period to be used for hardcapping (in usecs). 0 to use system default",
|
||||
Usage: "CPU CFS period to be used for hardcapping (in usecs). 0 to use system default",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cpu-quota",
|
||||
Usage: "CPU hardcap limit (in usecs). Allowed cpu time in a given period",
|
||||
Usage: "CPU CFS hardcap limit (in usecs). Allowed cpu time in a given period",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cpu-share",
|
||||
Usage: "CPU shares (relative weight vs. other containers)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cpu-rt-period",
|
||||
Usage: "CPU realtime period to be used for hardcapping (in usecs). 0 to use system default",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cpu-rt-runtime",
|
||||
Usage: "CPU realtime hardcap limit (in usecs). Allowed cpu time in a given period",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cpuset-cpus",
|
||||
Usage: "CPU(s) to use",
|
||||
|
@ -99,27 +110,32 @@ other options are ignored.
|
|||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
if err := checkArgs(context, 1, exactArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
container, err := getContainer(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := specs.Resources{
|
||||
Memory: &specs.Memory{
|
||||
r := specs.LinuxResources{
|
||||
Memory: &specs.LinuxMemory{
|
||||
Limit: u64Ptr(0),
|
||||
Reservation: u64Ptr(0),
|
||||
Swap: u64Ptr(0),
|
||||
Kernel: u64Ptr(0),
|
||||
KernelTCP: u64Ptr(0),
|
||||
},
|
||||
CPU: &specs.CPU{
|
||||
Shares: u64Ptr(0),
|
||||
Quota: u64Ptr(0),
|
||||
Period: u64Ptr(0),
|
||||
Cpus: sPtr(""),
|
||||
Mems: sPtr(""),
|
||||
CPU: &specs.LinuxCPU{
|
||||
Shares: u64Ptr(0),
|
||||
Quota: i64Ptr(0),
|
||||
Period: u64Ptr(0),
|
||||
RealtimeRuntime: i64Ptr(0),
|
||||
RealtimePeriod: u64Ptr(0),
|
||||
Cpus: "",
|
||||
Mems: "",
|
||||
},
|
||||
BlockIO: &specs.BlockIO{
|
||||
BlockIO: &specs.LinuxBlockIO{
|
||||
Weight: u16Ptr(0),
|
||||
},
|
||||
}
|
||||
|
@ -149,59 +165,86 @@ other options are ignored.
|
|||
r.BlockIO.Weight = u16Ptr(uint16(val))
|
||||
}
|
||||
if val := context.String("cpuset-cpus"); val != "" {
|
||||
r.CPU.Cpus = &val
|
||||
r.CPU.Cpus = val
|
||||
}
|
||||
if val := context.String("cpuset-mems"); val != "" {
|
||||
r.CPU.Mems = &val
|
||||
r.CPU.Mems = val
|
||||
}
|
||||
|
||||
for opt, dest := range map[string]*uint64{
|
||||
"cpu-period": r.CPU.Period,
|
||||
"cpu-quota": r.CPU.Quota,
|
||||
"cpu-share": r.CPU.Shares,
|
||||
for _, pair := range []struct {
|
||||
opt string
|
||||
dest *uint64
|
||||
}{
|
||||
|
||||
{"cpu-period", r.CPU.Period},
|
||||
{"cpu-rt-period", r.CPU.RealtimePeriod},
|
||||
{"cpu-share", r.CPU.Shares},
|
||||
} {
|
||||
if val := context.String(opt); val != "" {
|
||||
if val := context.String(pair.opt); val != "" {
|
||||
var err error
|
||||
*dest, err = strconv.ParseUint(val, 10, 64)
|
||||
*pair.dest, err = strconv.ParseUint(val, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid value for %s: %s", opt, err)
|
||||
return fmt.Errorf("invalid value for %s: %s", pair.opt, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, pair := range []struct {
|
||||
opt string
|
||||
dest *int64
|
||||
}{
|
||||
|
||||
for opt, dest := range map[string]*uint64{
|
||||
"kernel-memory": r.Memory.Kernel,
|
||||
"kernel-memory-tcp": r.Memory.KernelTCP,
|
||||
"memory": r.Memory.Limit,
|
||||
"memory-reservation": r.Memory.Reservation,
|
||||
"memory-swap": r.Memory.Swap,
|
||||
{"cpu-quota", r.CPU.Quota},
|
||||
{"cpu-rt-runtime", r.CPU.RealtimeRuntime},
|
||||
} {
|
||||
if val := context.String(opt); val != "" {
|
||||
v, err := units.RAMInBytes(val)
|
||||
if val := context.String(pair.opt); val != "" {
|
||||
var err error
|
||||
*pair.dest, err = strconv.ParseInt(val, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid value for %s: %s", opt, err)
|
||||
return fmt.Errorf("invalid value for %s: %s", pair.opt, err)
|
||||
}
|
||||
*dest = uint64(v)
|
||||
}
|
||||
}
|
||||
for _, pair := range []struct {
|
||||
opt string
|
||||
dest *uint64
|
||||
}{
|
||||
{"memory", r.Memory.Limit},
|
||||
{"memory-swap", r.Memory.Swap},
|
||||
{"kernel-memory", r.Memory.Kernel},
|
||||
{"kernel-memory-tcp", r.Memory.KernelTCP},
|
||||
{"memory-reservation", r.Memory.Reservation},
|
||||
} {
|
||||
if val := context.String(pair.opt); val != "" {
|
||||
var v int64
|
||||
|
||||
if val != "-1" {
|
||||
v, err = units.RAMInBytes(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid value for %s: %s", pair.opt, err)
|
||||
}
|
||||
} else {
|
||||
v = -1
|
||||
}
|
||||
*pair.dest = uint64(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the value
|
||||
config.Cgroups.Resources.BlkioWeight = *r.BlockIO.Weight
|
||||
config.Cgroups.Resources.CpuPeriod = int64(*r.CPU.Period)
|
||||
config.Cgroups.Resources.CpuQuota = int64(*r.CPU.Quota)
|
||||
config.Cgroups.Resources.CpuShares = int64(*r.CPU.Shares)
|
||||
config.Cgroups.Resources.CpusetCpus = *r.CPU.Cpus
|
||||
config.Cgroups.Resources.CpusetMems = *r.CPU.Mems
|
||||
config.Cgroups.Resources.KernelMemory = int64(*r.Memory.Kernel)
|
||||
config.Cgroups.Resources.KernelMemoryTCP = int64(*r.Memory.KernelTCP)
|
||||
config.Cgroups.Resources.Memory = int64(*r.Memory.Limit)
|
||||
config.Cgroups.Resources.MemoryReservation = int64(*r.Memory.Reservation)
|
||||
config.Cgroups.Resources.MemorySwap = int64(*r.Memory.Swap)
|
||||
config.Cgroups.Resources.CpuPeriod = *r.CPU.Period
|
||||
config.Cgroups.Resources.CpuQuota = *r.CPU.Quota
|
||||
config.Cgroups.Resources.CpuShares = *r.CPU.Shares
|
||||
config.Cgroups.Resources.CpuRtPeriod = *r.CPU.RealtimePeriod
|
||||
config.Cgroups.Resources.CpuRtRuntime = *r.CPU.RealtimeRuntime
|
||||
config.Cgroups.Resources.CpusetCpus = r.CPU.Cpus
|
||||
config.Cgroups.Resources.CpusetMems = r.CPU.Mems
|
||||
config.Cgroups.Resources.KernelMemory = *r.Memory.Kernel
|
||||
config.Cgroups.Resources.KernelMemoryTCP = *r.Memory.KernelTCP
|
||||
config.Cgroups.Resources.Memory = *r.Memory.Limit
|
||||
config.Cgroups.Resources.MemoryReservation = *r.Memory.Reservation
|
||||
config.Cgroups.Resources.MemorySwap = *r.Memory.Swap
|
||||
|
||||
if err := container.Set(config); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return container.Set(config)
|
||||
},
|
||||
}
|
||||
|
|
57
vendor/github.com/opencontainers/runc/utils.go
generated
vendored
57
vendor/github.com/opencontainers/runc/utils.go
generated
vendored
|
@ -3,12 +3,45 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
const (
|
||||
exactArgs = iota
|
||||
minArgs
|
||||
maxArgs
|
||||
)
|
||||
|
||||
func checkArgs(context *cli.Context, expected, checkType int) error {
|
||||
var err error
|
||||
cmdName := context.Command.Name
|
||||
switch checkType {
|
||||
case exactArgs:
|
||||
if context.NArg() != expected {
|
||||
err = fmt.Errorf("%s: %q requires exactly %d argument(s)", os.Args[0], cmdName, expected)
|
||||
}
|
||||
case minArgs:
|
||||
if context.NArg() < expected {
|
||||
err = fmt.Errorf("%s: %q requires a minimum of %d argument(s)", os.Args[0], cmdName, expected)
|
||||
}
|
||||
case maxArgs:
|
||||
if context.NArg() > expected {
|
||||
err = fmt.Errorf("%s: %q requires a maximum of %d argument(s)", os.Args[0], cmdName, expected)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Incorrect Usage.\n\n")
|
||||
cli.ShowCommandHelp(context, cmdName)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fatal prints the error's details if it is a libcontainer specific error type
|
||||
// then exits the program with an exit status of 1.
|
||||
func fatal(err error) {
|
||||
|
@ -18,7 +51,7 @@ func fatal(err error) {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
// setupSpec performs inital setup based on the cli.Context for the container
|
||||
// setupSpec performs initial setup based on the cli.Context for the container
|
||||
func setupSpec(context *cli.Context) (*specs.Spec, error) {
|
||||
bundle := context.String("bundle")
|
||||
if bundle != "" {
|
||||
|
@ -30,12 +63,20 @@ func setupSpec(context *cli.Context) (*specs.Spec, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
notifySocket := os.Getenv("NOTIFY_SOCKET")
|
||||
if notifySocket != "" {
|
||||
setupSdNotify(spec, notifySocket)
|
||||
}
|
||||
if os.Geteuid() != 0 {
|
||||
return nil, fmt.Errorf("runc should be run as root")
|
||||
}
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
func revisePidFile(context *cli.Context) error {
|
||||
pidFile := context.String("pid-file")
|
||||
if pidFile == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// convert pid-file to an absolute path so we can write to the right
|
||||
// file after chdir to bundle
|
||||
pidFile, err := filepath.Abs(pidFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return context.Set("pid-file", pidFile)
|
||||
}
|
||||
|
|
197
vendor/github.com/opencontainers/runc/utils_linux.go
generated
vendored
197
vendor/github.com/opencontainers/runc/utils_linux.go
generated
vendored
|
@ -5,6 +5,7 @@ package main
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
@ -14,7 +15,9 @@ import (
|
|||
"github.com/coreos/go-systemd/activation"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/systemd"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/specconv"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
@ -76,11 +79,18 @@ func newProcess(p specs.Process) (*libcontainer.Process, error) {
|
|||
// TODO: fix libcontainer's API to better support uid/gid in a typesafe way.
|
||||
User: fmt.Sprintf("%d:%d", p.User.UID, p.User.GID),
|
||||
Cwd: p.Cwd,
|
||||
Capabilities: p.Capabilities,
|
||||
Label: p.SelinuxLabel,
|
||||
NoNewPrivileges: &p.NoNewPrivileges,
|
||||
AppArmorProfile: p.ApparmorProfile,
|
||||
}
|
||||
if p.Capabilities != nil {
|
||||
lp.Capabilities = &configs.Capabilities{}
|
||||
lp.Capabilities.Bounding = p.Capabilities.Bounding
|
||||
lp.Capabilities.Effective = p.Capabilities.Effective
|
||||
lp.Capabilities.Inheritable = p.Capabilities.Inheritable
|
||||
lp.Capabilities.Permitted = p.Capabilities.Permitted
|
||||
lp.Capabilities.Ambient = p.Capabilities.Ambient
|
||||
}
|
||||
for _, gid := range p.User.AdditionalGids {
|
||||
lp.AdditionalGroups = append(lp.AdditionalGroups, strconv.FormatUint(uint64(gid), 10))
|
||||
}
|
||||
|
@ -94,53 +104,62 @@ func newProcess(p specs.Process) (*libcontainer.Process, error) {
|
|||
return lp, nil
|
||||
}
|
||||
|
||||
func dupStdio(process *libcontainer.Process, rootuid, rootgid int) error {
|
||||
process.Stdin = os.Stdin
|
||||
process.Stdout = os.Stdout
|
||||
process.Stderr = os.Stderr
|
||||
for _, fd := range []uintptr{
|
||||
os.Stdin.Fd(),
|
||||
os.Stdout.Fd(),
|
||||
os.Stderr.Fd(),
|
||||
} {
|
||||
if err := syscall.Fchown(int(fd), rootuid, rootgid); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// If systemd is supporting sd_notify protocol, this function will add support
|
||||
// for sd_notify protocol from within the container.
|
||||
func setupSdNotify(spec *specs.Spec, notifySocket string) {
|
||||
spec.Mounts = append(spec.Mounts, specs.Mount{Destination: notifySocket, Type: "bind", Source: notifySocket, Options: []string{"bind"}})
|
||||
spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", notifySocket))
|
||||
}
|
||||
|
||||
func destroy(container libcontainer.Container) {
|
||||
if err := container.Destroy(); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// setupIO sets the proper IO on the process depending on the configuration
|
||||
// If there is a nil error then there must be a non nil tty returned
|
||||
func setupIO(process *libcontainer.Process, rootuid, rootgid int, console string, createTTY, detach bool) (*tty, error) {
|
||||
// detach and createTty will not work unless a console path is passed
|
||||
// so error out here before changing any terminal settings
|
||||
if createTTY && detach && console == "" {
|
||||
return nil, fmt.Errorf("cannot allocate tty if runc will detach")
|
||||
}
|
||||
// setupIO modifies the given process config according to the options.
|
||||
func setupIO(process *libcontainer.Process, rootuid, rootgid int, createTTY, detach bool, sockpath string) (*tty, error) {
|
||||
if createTTY {
|
||||
return createTty(process, rootuid, rootgid, console)
|
||||
process.Stdin = nil
|
||||
process.Stdout = nil
|
||||
process.Stderr = nil
|
||||
t := &tty{}
|
||||
if !detach {
|
||||
parent, child, err := utils.NewSockPair("console")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
process.ConsoleSocket = child
|
||||
t.postStart = append(t.postStart, parent, child)
|
||||
t.consoleC = make(chan error, 1)
|
||||
go func() {
|
||||
if err := t.recvtty(process, parent); err != nil {
|
||||
t.consoleC <- err
|
||||
}
|
||||
t.consoleC <- nil
|
||||
}()
|
||||
} else {
|
||||
// the caller of runc will handle receiving the console master
|
||||
conn, err := net.Dial("unix", sockpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uc, ok := conn.(*net.UnixConn)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("casting to UnixConn failed")
|
||||
}
|
||||
t.postStart = append(t.postStart, uc)
|
||||
socket, err := uc.File()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.postStart = append(t.postStart, socket)
|
||||
process.ConsoleSocket = socket
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
// when runc will detach the caller provides the stdio to runc via runc's 0,1,2
|
||||
// and the container's process inherits runc's stdio.
|
||||
if detach {
|
||||
if err := dupStdio(process, rootuid, rootgid); err != nil {
|
||||
if err := inheritStdio(process); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tty{}, nil
|
||||
}
|
||||
return createStdioPipes(process, rootuid, rootgid)
|
||||
return setupProcessPipes(process, rootuid, rootgid)
|
||||
}
|
||||
|
||||
// createPidFile creates a file with the processes pid inside it atomically
|
||||
|
@ -167,6 +186,11 @@ func createPidFile(path string, process *libcontainer.Process) error {
|
|||
return os.Rename(tmpName, path)
|
||||
}
|
||||
|
||||
// XXX: Currently we autodetect rootless mode.
|
||||
func isRootless() bool {
|
||||
return os.Geteuid() != 0
|
||||
}
|
||||
|
||||
func createContainer(context *cli.Context, id string, spec *specs.Spec) (libcontainer.Container, error) {
|
||||
config, err := specconv.CreateLibcontainerConfig(&specconv.CreateOpts{
|
||||
CgroupName: id,
|
||||
|
@ -174,18 +198,12 @@ func createContainer(context *cli.Context, id string, spec *specs.Spec) (libcont
|
|||
NoPivotRoot: context.Bool("no-pivot"),
|
||||
NoNewKeyring: context.Bool("no-new-keyring"),
|
||||
Spec: spec,
|
||||
Rootless: isRootless(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(config.Rootfs); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("rootfs (%q) does not exist", config.Rootfs)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
factory, err := loadFactory(context)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -198,13 +216,19 @@ type runner struct {
|
|||
shouldDestroy bool
|
||||
detach bool
|
||||
listenFDs []*os.File
|
||||
preserveFDs int
|
||||
pidFile string
|
||||
console string
|
||||
consoleSocket string
|
||||
container libcontainer.Container
|
||||
create bool
|
||||
notifySocket *notifySocket
|
||||
}
|
||||
|
||||
func (r *runner) run(config *specs.Process) (int, error) {
|
||||
if err := r.checkTerminal(config); err != nil {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
process, err := newProcess(*config)
|
||||
if err != nil {
|
||||
r.destroy()
|
||||
|
@ -214,55 +238,66 @@ func (r *runner) run(config *specs.Process) (int, error) {
|
|||
process.Env = append(process.Env, fmt.Sprintf("LISTEN_FDS=%d", len(r.listenFDs)), "LISTEN_PID=1")
|
||||
process.ExtraFiles = append(process.ExtraFiles, r.listenFDs...)
|
||||
}
|
||||
rootuid, err := r.container.Config().HostUID()
|
||||
baseFd := 3 + len(process.ExtraFiles)
|
||||
for i := baseFd; i < baseFd+r.preserveFDs; i++ {
|
||||
process.ExtraFiles = append(process.ExtraFiles, os.NewFile(uintptr(i), "PreserveFD:"+strconv.Itoa(i)))
|
||||
}
|
||||
rootuid, err := r.container.Config().HostRootUID()
|
||||
if err != nil {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
rootgid, err := r.container.Config().HostGID()
|
||||
rootgid, err := r.container.Config().HostRootGID()
|
||||
if err != nil {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
tty, err := setupIO(process, rootuid, rootgid, r.console, config.Terminal, r.detach || r.create)
|
||||
if err != nil {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
handler := newSignalHandler(tty, r.enableSubreaper)
|
||||
startFn := r.container.Start
|
||||
var (
|
||||
detach = r.detach || r.create
|
||||
startFn = r.container.Start
|
||||
)
|
||||
if !r.create {
|
||||
startFn = r.container.Run
|
||||
}
|
||||
if err := startFn(process); err != nil {
|
||||
// Setting up IO is a two stage process. We need to modify process to deal
|
||||
// with detaching containers, and then we get a tty after the container has
|
||||
// started.
|
||||
handler := newSignalHandler(r.enableSubreaper, r.notifySocket)
|
||||
tty, err := setupIO(process, rootuid, rootgid, config.Terminal, detach, r.consoleSocket)
|
||||
if err != nil {
|
||||
r.destroy()
|
||||
tty.Close()
|
||||
return -1, err
|
||||
}
|
||||
if err := tty.ClosePostStart(); err != nil {
|
||||
defer tty.Close()
|
||||
if err = startFn(process); err != nil {
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
if err := tty.waitConsole(); err != nil {
|
||||
r.terminate(process)
|
||||
r.destroy()
|
||||
return -1, err
|
||||
}
|
||||
if err = tty.ClosePostStart(); err != nil {
|
||||
r.terminate(process)
|
||||
r.destroy()
|
||||
tty.Close()
|
||||
return -1, err
|
||||
}
|
||||
if r.pidFile != "" {
|
||||
if err := createPidFile(r.pidFile, process); err != nil {
|
||||
if err = createPidFile(r.pidFile, process); err != nil {
|
||||
r.terminate(process)
|
||||
r.destroy()
|
||||
tty.Close()
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
if r.detach || r.create {
|
||||
tty.Close()
|
||||
return 0, nil
|
||||
}
|
||||
status, err := handler.forward(process)
|
||||
status, err := handler.forward(process, tty, detach)
|
||||
if err != nil {
|
||||
r.terminate(process)
|
||||
}
|
||||
if detach {
|
||||
return 0, nil
|
||||
}
|
||||
r.destroy()
|
||||
tty.Close()
|
||||
return status, err
|
||||
}
|
||||
|
||||
|
@ -273,8 +308,20 @@ func (r *runner) destroy() {
|
|||
}
|
||||
|
||||
func (r *runner) terminate(p *libcontainer.Process) {
|
||||
p.Signal(syscall.SIGKILL)
|
||||
p.Wait()
|
||||
_ = p.Signal(syscall.SIGKILL)
|
||||
_, _ = p.Wait()
|
||||
}
|
||||
|
||||
func (r *runner) checkTerminal(config *specs.Process) error {
|
||||
detach := r.detach || r.create
|
||||
// Check command-line for sanity.
|
||||
if detach && config.Terminal && r.consoleSocket == "" {
|
||||
return fmt.Errorf("cannot allocate tty if runc will detach without setting console socket")
|
||||
}
|
||||
if (!detach || !config.Terminal) && r.consoleSocket != "" {
|
||||
return fmt.Errorf("cannot use console socket if runc will not detach or allocate tty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateProcessSpec(spec *specs.Process) error {
|
||||
|
@ -295,11 +342,21 @@ func startContainer(context *cli.Context, spec *specs.Spec, create bool) (int, e
|
|||
if id == "" {
|
||||
return -1, errEmptyID
|
||||
}
|
||||
|
||||
notifySocket := newNotifySocket(context, os.Getenv("NOTIFY_SOCKET"), id)
|
||||
if notifySocket != nil {
|
||||
notifySocket.setupSpec(context, spec)
|
||||
}
|
||||
|
||||
container, err := createContainer(context, id, spec)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
detach := context.Bool("detach")
|
||||
|
||||
if notifySocket != nil {
|
||||
notifySocket.setupSocket()
|
||||
}
|
||||
|
||||
// Support on-demand socket activation by passing file descriptors into the container init process.
|
||||
listenFDs := []*os.File{}
|
||||
if os.Getenv("LISTEN_FDS") != "" {
|
||||
|
@ -310,9 +367,11 @@ func startContainer(context *cli.Context, spec *specs.Spec, create bool) (int, e
|
|||
shouldDestroy: true,
|
||||
container: container,
|
||||
listenFDs: listenFDs,
|
||||
console: context.String("console"),
|
||||
detach: detach,
|
||||
notifySocket: notifySocket,
|
||||
consoleSocket: context.String("console-socket"),
|
||||
detach: context.Bool("detach"),
|
||||
pidFile: context.String("pid-file"),
|
||||
preserveFDs: context.Int("preserve-fds"),
|
||||
create: create,
|
||||
}
|
||||
return r.run(&spec.Process)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue