Add kpod run and kpod create CLI front ends

Add kpod-run/kpod-create man page and command completions

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>

This patch implements the ability to create and run containers
using kpod

Signed-off-by: Matthew Heon <mheon@redhat.com>
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh 2017-10-09 20:35:59 +00:00 committed by baude
parent c5e73ba65f
commit 409a228a73
10 changed files with 2901 additions and 2 deletions

View file

@ -133,3 +133,320 @@ func validateFlags(c *cli.Context, flags []cli.Flag) error {
}
return nil
}
// Common flags shared between commands
var createFlags = []cli.Flag{
cli.StringSliceFlag{
Name: "add-host",
Usage: "Add a custom host-to-IP mapping (host:ip) (default [])",
},
cli.StringSliceFlag{
Name: "attach, a",
Usage: "Attach to STDIN, STDOUT or STDERR (default [])",
},
cli.Int64Flag{
Name: "blkio-weight",
Usage: "Block IO weight (relative weight) accepts a weight value between 10 and 1000.",
},
cli.StringSliceFlag{
Name: "blkio-weight-device",
Usage: "Block IO weight (relative device weight, format: `DEVICE_NAME:WEIGHT`)",
},
cli.StringSliceFlag{
Name: "cap-add",
Usage: "Add capabilities to the container",
},
cli.StringSliceFlag{
Name: "cap-drop",
Usage: "Drop capabilities from the container",
},
cli.StringFlag{
Name: "cgroup-parent",
Usage: "Optional parent cgroup for the container",
},
cli.Int64Flag{
Name: "cpu-count",
Usage: "Limit the number of CPUs available for execution by the container.",
},
cli.StringFlag{
Name: "cid-file",
Usage: "Write the container ID to the file",
},
cli.Int64Flag{
Name: "cpu-period",
Usage: "Limit the CPU CFS (Completely Fair Scheduler) period",
},
cli.Int64Flag{
Name: "cpu-quota",
Usage: "Limit the CPU CFS (Completely Fair Scheduler) quota",
},
cli.Int64Flag{
Name: "cpu-rt-period",
Usage: "Limit the CPU real-time period in microseconds",
},
cli.Int64Flag{
Name: "cpu-rt-runtime",
Usage: "Limit the CPU real-time runtime in microseconds",
},
cli.Int64Flag{
Name: "cpu-shares",
Usage: "CPU shares (relative weight)",
},
cli.StringFlag{
Name: "cpus",
Usage: "Number of CPUs. The default is 0.000 which means no limit",
},
cli.StringFlag{
Name: "cpuset-cpus",
Usage: "CPUs in which to allow execution (0-3, 0,1)",
},
cli.StringFlag{
Name: "cpuset-mems",
Usage: "Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.",
},
cli.BoolFlag{
Name: "detach, d",
Usage: "Run container in background and print container ID",
},
cli.StringFlag{
Name: "detach-keys",
Usage: "Override the key sequence for detaching a container. Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`",
},
cli.StringSliceFlag{
Name: "device",
Usage: "Add a host device to the container (default [])",
},
cli.StringSliceFlag{
Name: "device-read-bps",
Usage: "Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)",
},
cli.StringSliceFlag{
Name: "device-read-iops",
Usage: "Limit read rate (IO per second) from a device (e.g. --device-read-iops=/dev/sda:1000)",
},
cli.StringSliceFlag{
Name: "device-write-bps",
Usage: "Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb)",
},
cli.StringSliceFlag{
Name: "device-write-iops",
Usage: "Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000)",
},
cli.StringSliceFlag{
Name: "dns",
Usage: "Set custom DNS servers",
},
cli.StringSliceFlag{
Name: "dns-opt",
Usage: "Set custom DNS options",
},
cli.StringSliceFlag{
Name: "dns-search",
Usage: "Set custom DNS search domains",
},
cli.StringFlag{
Name: "entrypoint",
Usage: "Overwrite the default ENTRYPOINT of the image",
},
cli.StringSliceFlag{
Name: "env, e",
Usage: "Set environment variables in container",
},
cli.StringSliceFlag{
Name: "env-file",
Usage: "Read in a file of environment variables",
},
cli.StringSliceFlag{
Name: "expose",
Usage: "Expose a port or a range of ports (default [])",
},
cli.StringSliceFlag{
Name: "group-add",
Usage: "Add additional groups to join (default [])",
},
cli.StringFlag{
Name: "hostname",
Usage: "Set container hostname",
},
cli.BoolFlag{
Name: "interactive, i",
Usage: "Keep STDIN open even if not attached",
},
cli.StringFlag{
Name: "ip",
Usage: "Container IPv4 address (e.g. 172.23.0.9)",
},
cli.StringFlag{
Name: "ip6",
Usage: "Container IPv6 address (e.g. 2001:db8::1b99)",
},
cli.StringFlag{
Name: "ipc",
Usage: "IPC Namespace to use",
},
cli.StringFlag{
Name: "kernel-memory",
Usage: "Kernel memory limit (format: `<number>[<unit>]`, where unit = b, k, m or g)",
},
cli.StringSliceFlag{
Name: "label",
Usage: "Set metadata on container (default [])",
},
cli.StringSliceFlag{
Name: "label-file",
Usage: "Read in a line delimited file of labels (default [])",
},
cli.StringSliceFlag{
Name: "link-local-ip",
Usage: "Container IPv4/IPv6 link-local addresses (default [])",
},
cli.StringFlag{
Name: "log-driver",
Usage: "Logging driver for the container",
},
cli.StringSliceFlag{
Name: "log-opt",
Usage: "Logging driver options (default [])",
},
cli.StringFlag{
Name: "mac-address",
Usage: "Container MAC address (e.g. 92:d0:c6:0a:29:33)",
},
cli.StringFlag{
Name: "memory, m",
Usage: "Memory limit (format: <number>[<unit>], where unit = b, k, m or g)",
},
cli.StringFlag{
Name: "memory-reservation",
Usage: "Memory soft limit (format: <number>[<unit>], where unit = b, k, m or g)",
},
cli.StringFlag{
Name: "memory-swap",
Usage: "Swap limit equal to memory plus swap: '-1' to enable unlimited swap",
},
cli.StringFlag{
Name: "memory-swappiness",
Usage: "Tune container memory swappiness (0 to 100) (default -1)",
},
cli.StringFlag{
Name: "name",
Usage: "Assign a name to the container",
},
cli.StringFlag{
Name: "net",
Usage: "Setup the network namespace",
},
cli.StringFlag{
Name: "network",
Usage: "Connect a container to a network (default 'default')",
},
cli.StringSliceFlag{
Name: "network-alias",
Usage: "Add network-scoped alias for the container (default [])",
},
cli.BoolFlag{
Name: "oom-kill-disable",
Usage: "Disable OOM Killer",
},
cli.StringFlag{
Name: "oom-score-adj",
Usage: "Tune the host's OOM preferences (-1000 to 1000)",
},
cli.StringFlag{
Name: "pid",
Usage: "PID Namespace to use",
},
cli.Int64Flag{
Name: "pids-limit",
Usage: "Tune container pids limit (set -1 for unlimited)",
},
cli.StringFlag{
Name: "pod",
Usage: "Run container in an existing pod",
},
cli.BoolFlag{
Name: "privileged",
Usage: "Give extended privileges to container",
},
cli.StringSliceFlag{
Name: "publish, p",
Usage: "Publish a container's port, or a range of ports, to the host (default [])",
},
cli.BoolFlag{
Name: "publish-all, P",
Usage: "Publish all exposed ports to random ports on the host interface",
},
cli.BoolFlag{
Name: "read-only",
Usage: "Make containers root filesystem read-only",
},
cli.BoolFlag{
Name: "rm",
Usage: "Remove container (and pod if created) after exit",
},
cli.StringSliceFlag{
Name: "security-opt",
Usage: "Security Options (default [])",
},
cli.StringFlag{
Name: "shm-size",
Usage: "Size of `/dev/shm`. The format is `<number><unit>`. default is 64 MB",
},
cli.BoolFlag{
Name: "sig-proxy",
Usage: "Proxy received signals to the process (default true)",
},
cli.StringFlag{
Name: "stop-signal",
Usage: "Signal to stop a container. Default is SIGTERM",
},
cli.IntFlag{
Name: "stop-timeout",
Usage: "Timeout (in seconds) to stop a container. Default is 10",
},
cli.StringSliceFlag{
Name: "storage-opt",
Usage: "Storage driver options per container (default [])",
},
cli.StringSliceFlag{
Name: "sysctl",
Usage: "Sysctl options (default [])",
},
cli.StringSliceFlag{
Name: "tmpfs",
Usage: "Mount a temporary filesystem (`tmpfs`) into a container (default [])",
},
cli.BoolFlag{
Name: "tty, t",
Usage: "Allocate a pseudo-TTY for container",
},
cli.StringSliceFlag{
Name: "ulimit",
Usage: "Ulimit options (default [])",
},
cli.StringFlag{
Name: "user, u",
Usage: "Username or UID (format: <name|uid>[:<group|gid>])",
},
cli.StringFlag{
Name: "userns",
Usage: "User namespace to use",
},
cli.StringFlag{
Name: "uts",
Usage: "UTS namespace to use",
},
cli.StringSliceFlag{
Name: "volume, v",
Usage: "Bind mount a volume into the container (default [])",
},
cli.StringSliceFlag{
Name: "volumes-from",
Usage: "Mount volumes from the specified container(s) (default [])",
},
cli.StringFlag{
Name: "workdir, w",
Usage: "Working `directory inside the container",
Value: "/",
},
}

160
cmd/kpod/create.go Normal file
View file

@ -0,0 +1,160 @@
package main
import (
"fmt"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/urfave/cli"
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
)
type createResourceConfig struct {
blkioWeight int64
blkioDevice []string
cpuShares int64
cpuCount int64
cpuPeriod int64
cpusetCpus string
cpusetNames string
cpuFile string
cpuMems string
cpuQuota int64
cpuRtPeriod int64
cpuRtRuntime int64
cpus int64
deviceReadBps []string
deviceReadIops []string
deviceWriteBps []string
deviceWriteIops []string
memory string
memoryReservation string
memorySwap string
memorySwapiness string
kernelMemory string
oomScoreAdj string
pidsLimit string
shmSize string
ulimit []string
}
type createConfig struct {
additionalGroups []int64
args []string
capAdd []string
capDrop []string
cgroupParent string
command string
detach bool
devices []*pb.Device
dnsOpt []string
dnsSearch []string
dnsServers []string
entrypoint string
env map[string]string
expose []string
groupAdd []string
hostname string
image string
interactive bool
ip6Address string
ipAddress string
labels map[string]string
linkLocalIP []string
logDriver string
logDriverOpt []string
macAddress string
mounts []*pb.Mount
name string
network string
networkAlias []string
nsIPC string
nsNet string
nsPID string
nsUser string
pod string
ports []*pb.PortMapping
privileged bool
publish []string
publishAll bool
readOnlyRootfs bool
resources createResourceConfig
rm bool
securityOpts []string
shmSize string
sigProxy bool
stdin bool
stopSignal string
stopTimeout int64
storageOpts []string
sysctl string
tmpfs []string
tty bool
user int64
userns string
volumes []string
volumesFrom []string
workDir string
}
var createDescription = "Creates a new container from the given image or" +
" storage and prepares it for running the specified command. The" +
" container ID is then printed to stdout. You can then start it at" +
" any time with the kpod start <container_id> command. The container" +
" will be created with the initial state 'created'."
var createCommand = cli.Command{
Name: "create",
Usage: "create but do not start a container",
Description: createDescription,
Flags: createFlags,
Action: createCmd,
ArgsUsage: "IMAGE [COMMAND [ARG...]]",
}
func createCmd(c *cli.Context) error {
// TODO should allow user to create based off a directory on the host not just image
// Need CLI support for this
if len(c.Args()) != 1 {
return errors.Errorf("must specify name of image to create from")
}
if err := validateFlags(c, createFlags); err != nil {
return err
}
runtime, err := getRuntime(c)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
createConfig, err := parseCreateOpts(c)
if err != nil {
return err
}
runtimeSpec, err := createConfigToOCISpec(createConfig)
if err != nil {
return err
}
ctr, err := runtime.NewContainer(runtimeSpec)
if err != nil {
return err
}
// Should we also call ctr.Create() to make the container in runc?
fmt.Printf("%s\n", ctr.ID())
return nil
}
// Parses CLI options related to container creation into a config which can be
// parsed into an OCI runtime spec
func parseCreateOpts(c *cli.Context) (*createConfig, error) {
return nil, errors.Errorf("NOT IMPLEMENTED")
}
// Parses information needed to create a container into an OCI runtime spec
func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
return nil, errors.Errorf("NOT IMPLEMENTED")
}

View file

@ -31,6 +31,7 @@ func main() {
app.Version = v
app.Commands = []cli.Command{
createCommand,
diffCommand,
exportCommand,
historyCommand,
@ -50,6 +51,7 @@ func main() {
renameCommand,
rmCommand,
rmiCommand,
runCommand,
saveCommand,
statsCommand,
stopCommand,

53
cmd/kpod/run.go Normal file
View file

@ -0,0 +1,53 @@
package main
import (
"fmt"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
var runDescription = "Runs a command in a new container from the given image"
var runCommand = cli.Command{
Name: "run",
Usage: "run a command in a new container",
Description: runDescription,
Flags: createFlags,
Action: runCmd,
ArgsUsage: "IMAGE [COMMAND [ARG...]]",
}
func runCmd(c *cli.Context) error {
if len(c.Args()) != 1 {
return errors.Errorf("must specify name of image to create from")
}
if err := validateFlags(c, createFlags); err != nil {
return err
}
runtime, err := getRuntime(c)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
createConfig, err := parseCreateOpts(c)
if err != nil {
return err
}
runtimeSpec, err := createConfigToOCISpec(createConfig)
if err != nil {
return err
}
ctr, err := runtime.NewContainer(runtimeSpec)
if err != nil {
return err
}
// Should we also call ctr.Create() to make the container in runc?
fmt.Printf("%s\n", ctr.ID())
return nil
}