summaryrefslogtreecommitdiff
path: root/cmd/kpod
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/kpod')
-rw-r--r--cmd/kpod/README.md16
-rw-r--r--cmd/kpod/attach.go86
-rw-r--r--cmd/kpod/common.go438
-rw-r--r--cmd/kpod/common_test.go41
-rw-r--r--cmd/kpod/create.go507
-rw-r--r--cmd/kpod/create_cli.go242
-rw-r--r--cmd/kpod/create_cli_test.go70
-rw-r--r--cmd/kpod/diff.go128
-rw-r--r--cmd/kpod/docker/types.go271
-rw-r--r--cmd/kpod/exec.go86
-rw-r--r--cmd/kpod/export.go65
-rw-r--r--cmd/kpod/formats/formats.go143
-rw-r--r--cmd/kpod/formats/templates.go78
-rw-r--r--cmd/kpod/history.go246
-rw-r--r--cmd/kpod/images.go337
-rw-r--r--cmd/kpod/import.go190
-rw-r--r--cmd/kpod/info.go84
-rw-r--r--cmd/kpod/inspect.go364
-rw-r--r--cmd/kpod/kill.go80
-rw-r--r--cmd/kpod/load.go123
-rw-r--r--cmd/kpod/login.go110
-rw-r--r--cmd/kpod/logout.go69
-rw-r--r--cmd/kpod/logs.go153
-rw-r--r--cmd/kpod/main.go161
-rw-r--r--cmd/kpod/mount.go125
-rw-r--r--cmd/kpod/parse.go863
-rw-r--r--cmd/kpod/pause.go58
-rw-r--r--cmd/kpod/ps.go606
-rw-r--r--cmd/kpod/pull.go120
-rw-r--r--cmd/kpod/push.go167
-rw-r--r--cmd/kpod/rm.go90
-rw-r--r--cmd/kpod/rmi.go75
-rw-r--r--cmd/kpod/run.go146
-rw-r--r--cmd/kpod/save.go129
-rw-r--r--cmd/kpod/spec.go561
-rw-r--r--cmd/kpod/spec_test.go39
-rw-r--r--cmd/kpod/start.go131
-rw-r--r--cmd/kpod/stats.go226
-rw-r--r--cmd/kpod/stop.go104
-rw-r--r--cmd/kpod/tag.go77
-rw-r--r--cmd/kpod/top.go258
-rw-r--r--cmd/kpod/umount.go40
-rw-r--r--cmd/kpod/unpause.go58
-rw-r--r--cmd/kpod/user.go121
-rw-r--r--cmd/kpod/version.go48
-rw-r--r--cmd/kpod/wait.go61
46 files changed, 0 insertions, 8191 deletions
diff --git a/cmd/kpod/README.md b/cmd/kpod/README.md
deleted file mode 100644
index 7a79e4893..000000000
--- a/cmd/kpod/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# kpod - Simple debugging tool for pods and images
-kpod is a simple client only tool to help with debugging issues when daemons such as CRI runtime and the kubelet are not responding or
-failing. A shared API layer could be created to share code between the daemon and kpod. kpod does not require any daemon running. kpod
-utilizes the same underlying components that crio uses i.e. containers/image, container/storage, oci-runtime-tool/generate, runc or
-any other OCI compatible runtime. kpod shares state with crio and so has the capability to debug pods/images created by crio.
-
-## Use cases
-1. List pods.
-2. Launch simple pods (that require no daemon support).
-3. Exec commands in a container in a pod.
-4. Launch additional containers in a pod.
-5. List images.
-6. Remove images not in use.
-7. Pull images.
-8. Check image size.
-9. Report pod disk resource usage.
diff --git a/cmd/kpod/attach.go b/cmd/kpod/attach.go
deleted file mode 100644
index 700023abe..000000000
--- a/cmd/kpod/attach.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package main
-
-import (
- "sync"
-
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/sirupsen/logrus"
- "github.com/urfave/cli"
-)
-
-var (
- attachFlags = []cli.Flag{
- 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.BoolFlag{
- Name: "no-stdin",
- Usage: "Do not attach STDIN. The default is false.",
- },
- }
- attachDescription = "The kpod attach command allows you to attach to a running container using the container's ID or name, either to view its ongoing output or to control it interactively."
- attachCommand = cli.Command{
- Name: "attach",
- Usage: "Attach to a running container",
- Description: attachDescription,
- Flags: attachFlags,
- Action: attachCmd,
- ArgsUsage: "",
- }
-)
-
-func attachCmd(c *cli.Context) error {
- args := c.Args()
- if err := validateFlags(c, attachFlags); err != nil {
- return err
- }
-
- if len(c.Args()) < 1 || len(c.Args()) > 1 {
- return errors.Errorf("attach requires the name or id of one running container")
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "error creating libpod runtime")
- }
- defer runtime.Shutdown(false)
-
- ctr, err := runtime.LookupContainer(args[0])
-
- if err != nil {
- return errors.Wrapf(err, "unable to exec into %s", args[0])
- }
-
- conState, err := ctr.State()
- if err != nil {
- return errors.Wrapf(err, "unable to determine state of %s", args[0])
- }
- if conState != libpod.ContainerStateRunning {
- return errors.Errorf("you can only attach to running containers")
- }
- // Create a bool channel to track that the console socket attach
- // is successful.
- attached := make(chan bool)
- // Create a waitgroup so we can sync and wait for all goroutines
- // to finish before exiting main
- var wg sync.WaitGroup
-
- // We increment the wg counter because we need to do the attach
- wg.Add(1)
- // Attach to the running container
- go func() {
- logrus.Debugf("trying to attach to the container %s", ctr.ID())
- defer wg.Done()
- if err := ctr.Attach(c.Bool("no-stdin"), c.String("detach-keys"), attached); err != nil {
- logrus.Errorf("unable to attach to container %s: %q", ctr.ID(), err)
- }
- }()
- if !<-attached {
- return errors.Errorf("unable to attach to container %s", ctr.ID())
- }
- wg.Wait()
-
- return nil
-}
diff --git a/cmd/kpod/common.go b/cmd/kpod/common.go
deleted file mode 100644
index 99685107b..000000000
--- a/cmd/kpod/common.go
+++ /dev/null
@@ -1,438 +0,0 @@
-package main
-
-import (
- "os"
- "reflect"
- "regexp"
- "strings"
-
- "github.com/containers/storage"
- "github.com/fatih/camelcase"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libkpod"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
-)
-
-var (
- stores = make(map[storage.Store]struct{})
-)
-
-const crioConfigPath = "/etc/crio/crio.conf"
-
-func getRuntime(c *cli.Context) (*libpod.Runtime, error) {
-
- config, err := getConfig(c)
- if err != nil {
- return nil, errors.Wrapf(err, "could not get config")
- }
-
- options := storage.DefaultStoreOptions
- options.GraphRoot = config.Root
- options.RunRoot = config.RunRoot
- options.GraphDriverName = config.Storage
- options.GraphDriverOptions = config.StorageOptions
-
- return libpod.NewRuntime(libpod.WithStorageConfig(options), libpod.WithConmonPath(config.Conmon), libpod.WithOCIRuntime(config.Runtime), libpod.WithCNIConfigDir(config.NetworkDir))
-}
-
-func shutdownStores() {
- for store := range stores {
- if _, err := store.Shutdown(false); err != nil {
- break
- }
- }
-}
-
-func getConfig(c *cli.Context) (*libkpod.Config, error) {
- config := libkpod.DefaultConfig()
- var configFile string
- if c.GlobalIsSet("config") {
- configFile = c.GlobalString("config")
- } else if _, err := os.Stat(crioConfigPath); err == nil {
- configFile = crioConfigPath
- }
- // load and merge the configfile from the commandline or use
- // the default crio config file
- if configFile != "" {
- err := config.UpdateFromFile(configFile)
- if err != nil {
- return config, err
- }
- }
- if c.GlobalIsSet("root") {
- config.Root = c.GlobalString("root")
- }
- if c.GlobalIsSet("runroot") {
- config.RunRoot = c.GlobalString("runroot")
- }
- if c.GlobalIsSet("conmon") {
- config.Conmon = c.GlobalString("conmon")
- }
- if c.GlobalIsSet("storage-driver") {
- config.Storage = c.GlobalString("storage-driver")
- }
- if c.GlobalIsSet("storage-opt") {
- opts := c.GlobalStringSlice("storage-opt")
- if len(opts) > 0 {
- config.StorageOptions = opts
- }
- }
- if c.GlobalIsSet("runtime") {
- config.Runtime = c.GlobalString("runtime")
- }
- if c.GlobalIsSet("cni-config-dir") {
- config.NetworkDir = c.GlobalString("cni-config-dir")
- }
- return config, nil
-}
-
-func splitCamelCase(src string) string {
- entries := camelcase.Split(src)
- return strings.Join(entries, " ")
-}
-
-// validateFlags searches for StringFlags or StringSlice flags that never had
-// a value set. This commonly occurs when the CLI mistakenly takes the next
-// option and uses it as a value.
-func validateFlags(c *cli.Context, flags []cli.Flag) error {
- for _, flag := range flags {
- switch reflect.TypeOf(flag).String() {
- case "cli.StringSliceFlag":
- {
- f := flag.(cli.StringSliceFlag)
- name := strings.Split(f.Name, ",")
- val := c.StringSlice(name[0])
- for _, v := range val {
- if ok, _ := regexp.MatchString("^-.+", v); ok {
- return errors.Errorf("option --%s requires a value", name[0])
- }
- }
- }
- case "cli.StringFlag":
- {
- f := flag.(cli.StringFlag)
- name := strings.Split(f.Name, ",")
- val := c.String(name[0])
- if ok, _ := regexp.MatchString("^-.+", val); ok {
- return errors.Errorf("option --%s requires a value", name[0])
- }
- }
- }
- }
- 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.StringFlag{
- 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.StringFlag{
- Name: "cidfile",
- Usage: "Write the container ID to the file",
- },
- cli.Uint64Flag{
- 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.Uint64Flag{
- 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.Uint64Flag{
- 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.Int64Flag{
- Name: "memory-swappiness",
- Usage: "Tune container memory swappiness (0 to 100) (default -1)",
- Value: -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: "/",
- },
-}
diff --git a/cmd/kpod/common_test.go b/cmd/kpod/common_test.go
deleted file mode 100644
index 8a3bfd181..000000000
--- a/cmd/kpod/common_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package main
-
-import (
- "os/user"
- "testing"
-
- "flag"
-
- "github.com/urfave/cli"
-)
-
-func TestGetStore(t *testing.T) {
- t.Skip("FIX THIS!")
-
- //cmd/kpod/common_test.go:27: cannot use c (type *cli.Context) as type *libkpod.Config in argument to getStore
-
- // Make sure the tests are running as root
- skipTestIfNotRoot(t)
-
- set := flag.NewFlagSet("test", 0)
- globalSet := flag.NewFlagSet("test", 0)
- globalSet.String("root", "", "path to the root directory in which data, including images, is stored")
- globalCtx := cli.NewContext(nil, globalSet, nil)
- command := cli.Command{Name: "imagesCommand"}
- c := cli.NewContext(nil, set, globalCtx)
- c.Command = command
-
- //_, err := getStore(c)
- //if err != nil {
- //t.Error(err)
- //}
-}
-
-func skipTestIfNotRoot(t *testing.T) {
- u, err := user.Current()
- if err != nil {
- t.Skip("Could not determine user. Running without root may cause tests to fail")
- } else if u.Uid != "0" {
- t.Skip("tests will fail unless run as root")
- }
-}
diff --git a/cmd/kpod/create.go b/cmd/kpod/create.go
deleted file mode 100644
index afed70eaa..000000000
--- a/cmd/kpod/create.go
+++ /dev/null
@@ -1,507 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "strconv"
- "strings"
-
- "github.com/docker/docker/api/types/container"
- "github.com/docker/go-units"
- "github.com/opencontainers/selinux/go-selinux/label"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/sirupsen/logrus"
- "github.com/urfave/cli"
- pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
-)
-
-type mountType string
-
-// Type constants
-const (
- // TypeBind is the type for mounting host dir
- TypeBind mountType = "bind"
- // TypeVolume is the type for remote storage volumes
- // TypeVolume mountType = "volume" // re-enable upon use
- // TypeTmpfs is the type for mounting tmpfs
- TypeTmpfs mountType = "tmpfs"
-)
-
-var (
- defaultEnvVariables = map[string]string{
- "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
- "TERM": "xterm",
- }
-)
-
-type createResourceConfig struct {
- BlkioWeight uint16 // blkio-weight
- BlkioWeightDevice []string // blkio-weight-device
- CPUPeriod uint64 // cpu-period
- CPUQuota int64 // cpu-quota
- CPURtPeriod uint64 // cpu-rt-period
- CPURtRuntime int64 // cpu-rt-runtime
- CPUShares uint64 // cpu-shares
- CPUs string // cpus
- CPUsetCPUs string
- CPUsetMems string // cpuset-mems
- DeviceReadBps []string // device-read-bps
- DeviceReadIOps []string // device-read-iops
- DeviceWriteBps []string // device-write-bps
- DeviceWriteIOps []string // device-write-iops
- DisableOomKiller bool // oom-kill-disable
- KernelMemory int64 // kernel-memory
- Memory int64 //memory
- MemoryReservation int64 // memory-reservation
- MemorySwap int64 //memory-swap
- MemorySwappiness int // memory-swappiness
- OomScoreAdj int //oom-score-adj
- PidsLimit int64 // pids-limit
- ShmSize string
- Ulimit []string //ulimit
-}
-
-type createConfig struct {
- Runtime *libpod.Runtime
- Args []string
- CapAdd []string // cap-add
- CapDrop []string // cap-drop
- CidFile string
- CgroupParent string // cgroup-parent
- Command []string
- Detach bool // detach
- Devices []*pb.Device // device
- DNSOpt []string //dns-opt
- DNSSearch []string //dns-search
- DNSServers []string //dns
- Entrypoint string //entrypoint
- Env map[string]string //env
- Expose []string //expose
- GroupAdd []uint32 // group-add
- Hostname string //hostname
- Image string
- Interactive bool //interactive
- IpcMode container.IpcMode //ipc
- IP6Address string //ipv6
- IPAddress string //ip
- Labels map[string]string //label
- LinkLocalIP []string // link-local-ip
- LogDriver string // log-driver
- LogDriverOpt []string // log-opt
- MacAddress string //mac-address
- Name string //name
- NetMode container.NetworkMode //net
- Network string //network
- NetworkAlias []string //network-alias
- PidMode container.PidMode //pid
- NsUser string
- Pod string //pod
- Privileged bool //privileged
- Publish []string //publish
- PublishAll bool //publish-all
- ReadOnlyRootfs bool //read-only
- Resources createResourceConfig
- Rm bool //rm
- ShmDir string
- SigProxy bool //sig-proxy
- StopSignal string // stop-signal
- StopTimeout int64 // stop-timeout
- StorageOpts []string //storage-opt
- Sysctl map[string]string //sysctl
- Tmpfs []string // tmpfs
- Tty bool //tty
- User uint32 //user
- Group uint32 // group
- UtsMode container.UTSMode //uts
- Volumes []string //volume
- WorkDir string //workdir
- MountLabel string //SecurityOpts
- ProcessLabel string //SecurityOpts
- NoNewPrivileges bool //SecurityOpts
- ApparmorProfile string //SecurityOpts
- SeccompProfilePath string //SecurityOpts
- SecurityOpts []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...]]",
- SkipArgReorder: true,
- UseShortOptionHandling: true,
-}
-
-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
- var imageName string
- if err := validateFlags(c, createFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "error creating libpod runtime")
- }
- defer runtime.Shutdown(false)
-
- createConfig, err := parseCreateOpts(c, runtime)
- if err != nil {
- return err
- }
-
- // Deal with the image after all the args have been checked
- createImage := runtime.NewImage(createConfig.Image)
- createImage.LocalName, _ = createImage.GetLocalImageName()
- if createImage.LocalName == "" {
- // The image wasnt found by the user input'd name or its fqname
- // Pull the image
- fmt.Printf("Trying to pull %s...", createImage.PullName)
- createImage.Pull()
- }
-
- runtimeSpec, err := createConfigToOCISpec(createConfig)
- if err != nil {
- return err
- }
- if createImage.LocalName != "" {
- nameIsID, err := runtime.IsImageID(createImage.LocalName)
- if err != nil {
- return err
- }
- if nameIsID {
- // If the input from the user is an ID, then we need to get the image
- // name for cstorage
- createImage.LocalName, err = createImage.GetNameByID()
- if err != nil {
- return err
- }
- }
- imageName = createImage.LocalName
- } else {
- imageName, err = createImage.GetFQName()
- }
- if err != nil {
- return err
- }
- imageID, err := createImage.GetImageID()
- if err != nil {
- return err
- }
- options, err := createConfig.GetContainerCreateOptions()
- if err != nil {
- return errors.Wrapf(err, "unable to parse new container options")
- }
- // Gather up the options for NewContainer which consist of With... funcs
- options = append(options, libpod.WithRootFSFromImage(imageID, imageName, false))
- options = append(options, libpod.WithSELinuxLabels(createConfig.ProcessLabel, createConfig.MountLabel))
- options = append(options, libpod.WithShmDir(createConfig.ShmDir))
- ctr, err := runtime.NewContainer(runtimeSpec, options...)
- if err != nil {
- return err
- }
-
- createConfigJSON, err := json.Marshal(createConfig)
- if err != nil {
- return err
- }
- if err := ctr.AddArtifact("create-config", createConfigJSON); err != nil {
- return err
- }
-
- logrus.Debug("new container created ", ctr.ID())
-
- if c.String("cidfile") != "" {
- libpod.WriteFile(ctr.ID(), c.String("cidfile"))
- } else {
- fmt.Printf("%s\n", ctr.ID())
- }
-
- return nil
-}
-
-const seccompDefaultPath = "/etc/crio/seccomp.json"
-
-func parseSecurityOpt(config *createConfig, securityOpts []string) error {
- var (
- labelOpts []string
- err error
- )
-
- if config.PidMode.IsHost() {
- labelOpts = append(labelOpts, label.DisableSecOpt()...)
- } else if config.PidMode.IsContainer() {
- ctr, err := config.Runtime.LookupContainer(config.PidMode.Container())
- if err != nil {
- return errors.Wrapf(err, "container %q not found", config.PidMode.Container())
- }
- labelOpts = append(labelOpts, label.DupSecOpt(ctr.ProcessLabel())...)
- }
-
- if config.IpcMode.IsHost() {
- labelOpts = append(labelOpts, label.DisableSecOpt()...)
- } else if config.IpcMode.IsContainer() {
- ctr, err := config.Runtime.LookupContainer(config.IpcMode.Container())
- if err != nil {
- return errors.Wrapf(err, "container %q not found", config.IpcMode.Container())
- }
- labelOpts = append(labelOpts, label.DupSecOpt(ctr.ProcessLabel())...)
- }
-
- for _, opt := range securityOpts {
- if opt == "no-new-privileges" {
- config.NoNewPrivileges = true
- } else {
- con := strings.SplitN(opt, "=", 2)
- if len(con) != 2 {
- return fmt.Errorf("Invalid --security-opt 1: %q", opt)
- }
-
- switch con[0] {
- case "label":
- labelOpts = append(labelOpts, con[1])
- case "apparmor":
- config.ApparmorProfile = con[1]
- case "seccomp":
- config.SeccompProfilePath = con[1]
- default:
- return fmt.Errorf("Invalid --security-opt 2: %q", opt)
- }
- }
- }
-
- if config.SeccompProfilePath == "" {
- if _, err := os.Stat(seccompDefaultPath); err != nil {
- if !os.IsNotExist(err) {
- return errors.Wrapf(err, "can't check if %q exists", seccompDefaultPath)
- }
- } else {
- config.SeccompProfilePath = seccompDefaultPath
- }
- }
- config.ProcessLabel, config.MountLabel, err = label.InitLabels(labelOpts)
- return err
-}
-
-// Parses CLI options related to container creation into a config which can be
-// parsed into an OCI runtime spec
-func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, error) {
- var command []string
- var memoryLimit, memoryReservation, memorySwap, memoryKernel int64
- var blkioWeight uint16
- var uid, gid uint32
-
- if len(c.Args()) < 1 {
- return nil, errors.Errorf("image name or ID is required")
- }
- image := c.Args()[0]
-
- if len(c.Args()) > 1 {
- command = c.Args()[1:]
- }
-
- // LABEL VARIABLES
- labels, err := getAllLabels(c.StringSlice("label-file"), c.StringSlice("labels"))
- if err != nil {
- return &createConfig{}, errors.Wrapf(err, "unable to process labels")
- }
- // ENVIRONMENT VARIABLES
- env := defaultEnvVariables
- if err := readKVStrings(env, c.StringSlice("env-file"), c.StringSlice("env")); err != nil {
- return &createConfig{}, errors.Wrapf(err, "unable to process environment variables")
- }
-
- sysctl, err := convertStringSliceToMap(c.StringSlice("sysctl"), "=")
- if err != nil {
- return &createConfig{}, errors.Wrapf(err, "sysctl values must be in the form of KEY=VALUE")
- }
-
- groupAdd, err := stringSlicetoUint32Slice(c.StringSlice("group-add"))
- if err != nil {
- return &createConfig{}, errors.Wrapf(err, "invalid value for groups provided")
- }
-
- if c.String("user") != "" {
- // TODO
- // We need to mount the imagefs and get the uid/gid
- // For now, user zeros
- uid = 0
- gid = 0
- }
-
- if c.String("memory") != "" {
- memoryLimit, err = units.RAMInBytes(c.String("memory"))
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for memory")
- }
- }
- if c.String("memory-reservation") != "" {
- memoryReservation, err = units.RAMInBytes(c.String("memory-reservation"))
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for memory-reservation")
- }
- }
- if c.String("memory-swap") != "" {
- memorySwap, err = units.RAMInBytes(c.String("memory-swap"))
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for memory-swap")
- }
- }
- if c.String("kernel-memory") != "" {
- memoryKernel, err = units.RAMInBytes(c.String("kernel-memory"))
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for kernel-memory")
- }
- }
- if c.String("blkio-weight") != "" {
- u, err := strconv.ParseUint(c.String("blkio-weight"), 10, 16)
- if err != nil {
- return nil, errors.Wrapf(err, "invalid value for blkio-weight")
- }
- blkioWeight = uint16(u)
- }
-
- if err = parseVolumes(c.StringSlice("volume")); err != nil {
- return nil, err
- }
-
- // Because we cannot do a non-terminal attach, we need to set tty to true
- // if detach is not false
- // TODO Allow non-terminal attach
- tty := c.Bool("tty")
- if !c.Bool("detach") && !tty {
- tty = true
- }
-
- pidMode := container.PidMode(c.String("pid"))
- if !pidMode.Valid() {
- return nil, errors.Errorf("--pid %q is not valid", c.String("pid"))
- }
-
- if c.Bool("detach") && c.Bool("rm") {
- return nil, errors.Errorf("--rm and --detach can not be specified together")
- }
-
- utsMode := container.UTSMode(c.String("uts"))
- if !utsMode.Valid() {
- return nil, errors.Errorf("--uts %q is not valid", c.String("uts"))
- }
- ipcMode := container.IpcMode(c.String("ipc"))
- if !ipcMode.Valid() {
- return nil, errors.Errorf("--ipc %q is not valid", ipcMode)
- }
- shmDir := ""
- if ipcMode.IsHost() {
- shmDir = "/dev/shm"
- } else if ipcMode.IsContainer() {
- ctr, err := runtime.LookupContainer(ipcMode.Container())
- if err != nil {
- return nil, errors.Wrapf(err, "container %q not found", ipcMode.Container())
- }
- shmDir = ctr.ShmDir()
- }
-
- config := &createConfig{
- Runtime: runtime,
- CapAdd: c.StringSlice("cap-add"),
- CapDrop: c.StringSlice("cap-drop"),
- CgroupParent: c.String("cgroup-parent"),
- Command: command,
- Detach: c.Bool("detach"),
- DNSOpt: c.StringSlice("dns-opt"),
- DNSSearch: c.StringSlice("dns-search"),
- DNSServers: c.StringSlice("dns"),
- Entrypoint: c.String("entrypoint"),
- Env: env,
- Expose: c.StringSlice("expose"),
- GroupAdd: groupAdd,
- Hostname: c.String("hostname"),
- Image: image,
- Interactive: c.Bool("interactive"),
- IP6Address: c.String("ipv6"),
- IPAddress: c.String("ip"),
- Labels: labels,
- LinkLocalIP: c.StringSlice("link-local-ip"),
- LogDriver: c.String("log-driver"),
- LogDriverOpt: c.StringSlice("log-opt"),
- MacAddress: c.String("mac-address"),
- Name: c.String("name"),
- Network: c.String("network"),
- NetworkAlias: c.StringSlice("network-alias"),
- IpcMode: ipcMode,
- NetMode: container.NetworkMode(c.String("network")),
- UtsMode: utsMode,
- PidMode: pidMode,
- Pod: c.String("pod"),
- Privileged: c.Bool("privileged"),
- Publish: c.StringSlice("publish"),
- PublishAll: c.Bool("publish-all"),
- ReadOnlyRootfs: c.Bool("read-only"),
- Resources: createResourceConfig{
- BlkioWeight: blkioWeight,
- BlkioWeightDevice: c.StringSlice("blkio-weight-device"),
- CPUShares: c.Uint64("cpu-shares"),
- CPUPeriod: c.Uint64("cpu-period"),
- CPUsetCPUs: c.String("cpu-period"),
- CPUsetMems: c.String("cpuset-mems"),
- CPUQuota: c.Int64("cpu-quota"),
- CPURtPeriod: c.Uint64("cpu-rt-period"),
- CPURtRuntime: c.Int64("cpu-rt-runtime"),
- CPUs: c.String("cpus"),
- DeviceReadBps: c.StringSlice("device-read-bps"),
- DeviceReadIOps: c.StringSlice("device-read-iops"),
- DeviceWriteBps: c.StringSlice("device-write-bps"),
- DeviceWriteIOps: c.StringSlice("device-write-iops"),
- DisableOomKiller: c.Bool("oom-kill-disable"),
- ShmSize: c.String("shm-size"),
- Memory: memoryLimit,
- MemoryReservation: memoryReservation,
- MemorySwap: memorySwap,
- MemorySwappiness: c.Int("memory-swappiness"),
- KernelMemory: memoryKernel,
- OomScoreAdj: c.Int("oom-score-adj"),
-
- PidsLimit: c.Int64("pids-limit"),
- Ulimit: c.StringSlice("ulimit"),
- },
- Rm: c.Bool("rm"),
- ShmDir: shmDir,
- SigProxy: c.Bool("sig-proxy"),
- StopSignal: c.String("stop-signal"),
- StopTimeout: c.Int64("stop-timeout"),
- StorageOpts: c.StringSlice("storage-opt"),
- Sysctl: sysctl,
- Tmpfs: c.StringSlice("tmpfs"),
- Tty: tty,
- User: uid,
- Group: gid,
- Volumes: c.StringSlice("volume"),
- WorkDir: c.String("workdir"),
- }
-
- if !config.Privileged {
- if err := parseSecurityOpt(config, c.StringSlice("security-opt")); err != nil {
- return nil, err
- }
- }
- config.SecurityOpts = c.StringSlice("security-opt")
- warnings, err := verifyContainerResources(config, false)
- if err != nil {
- return nil, err
- }
- for _, warning := range warnings {
- fmt.Fprintln(os.Stderr, warning)
- }
- return config, nil
-}
diff --git a/cmd/kpod/create_cli.go b/cmd/kpod/create_cli.go
deleted file mode 100644
index 0cc265e92..000000000
--- a/cmd/kpod/create_cli.go
+++ /dev/null
@@ -1,242 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
- "strings"
-
- "github.com/docker/docker/pkg/sysinfo"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-const (
- // It's not kernel limit, we want this 4M limit to supply a reasonable functional container
- linuxMinMemory = 4194304
-)
-
-func getAllLabels(labelFile, inputLabels []string) (map[string]string, error) {
- labels := make(map[string]string)
- labelErr := readKVStrings(labels, labelFile, inputLabels)
- if labelErr != nil {
- return labels, errors.Wrapf(labelErr, "unable to process labels from --label and label-file")
- }
- return labels, nil
-}
-
-func convertStringSliceToMap(strSlice []string, delimiter string) (map[string]string, error) {
- sysctl := make(map[string]string)
- for _, inputSysctl := range strSlice {
- values := strings.Split(inputSysctl, delimiter)
- if len(values) < 2 {
- return sysctl, errors.Errorf("%s in an invalid sysctl value", inputSysctl)
- }
- sysctl[values[0]] = values[1]
- }
- return sysctl, nil
-}
-
-func addWarning(warnings []string, msg string) []string {
- logrus.Warn(msg)
- return append(warnings, msg)
-}
-
-func parseVolumes(volumes []string) error {
- if len(volumes) == 0 {
- return nil
- }
- for _, volume := range volumes {
- arr := strings.SplitN(volume, ":", 3)
- if len(arr) < 2 {
- return errors.Errorf("incorrect volume format %q, should be host-dir:ctr-dir:[option]", volume)
- }
- if err := validateVolumeHostDir(arr[0]); err != nil {
- return err
- }
- if err := validateVolumeCtrDir(arr[1]); err != nil {
- return err
- }
- if len(arr) > 2 {
- if err := validateVolumeOpts(arr[2]); err != nil {
- return err
- }
- }
- }
- return nil
-}
-
-func validateVolumeHostDir(hostDir string) error {
- if _, err := os.Stat(hostDir); err != nil {
- return errors.Wrapf(err, "error checking path %q", hostDir)
- }
- return nil
-}
-
-func validateVolumeCtrDir(ctrDir string) error {
- if ctrDir[0] != '/' {
- return errors.Errorf("invalid container directory path %q", ctrDir)
- }
- return nil
-}
-
-func validateVolumeOpts(option string) error {
- var foundRootPropagation, foundRWRO, foundLabelChange int
- options := strings.Split(option, ",")
- for _, opt := range options {
- switch opt {
- case "rw", "ro":
- if foundRWRO > 1 {
- return errors.Errorf("invalid options %q, can only specify 1 'rw' or 'ro' option", option)
- }
- foundRWRO++
- case "z", "Z":
- if foundLabelChange > 1 {
- return errors.Errorf("invalid options %q, can only specify 1 'z' or 'Z' option", option)
- }
- foundLabelChange++
- case "private", "rprivate", "shared", "rshared", "slave", "rslave":
- if foundRootPropagation > 1 {
- return errors.Errorf("invalid options %q, can only specify 1 '[r]shared', '[r]private' or '[r]slave' option", option)
- }
- foundRootPropagation++
- default:
- return errors.Errorf("invalid option type %q", option)
- }
- }
- return nil
-}
-
-func verifyContainerResources(config *createConfig, update bool) ([]string, error) {
- warnings := []string{}
- sysInfo := sysinfo.New(true)
-
- // memory subsystem checks and adjustments
- if config.Resources.Memory != 0 && config.Resources.Memory < linuxMinMemory {
- return warnings, fmt.Errorf("minimum memory limit allowed is 4MB")
- }
- if config.Resources.Memory > 0 && !sysInfo.MemoryLimit {
- warnings = addWarning(warnings, "Your kernel does not support memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
- config.Resources.Memory = 0
- config.Resources.MemorySwap = -1
- }
- if config.Resources.Memory > 0 && config.Resources.MemorySwap != -1 && !sysInfo.SwapLimit {
- warnings = addWarning(warnings, "Your kernel does not support swap limit capabilities,or the cgroup is not mounted. Memory limited without swap.")
- config.Resources.MemorySwap = -1
- }
- if config.Resources.Memory > 0 && config.Resources.MemorySwap > 0 && config.Resources.MemorySwap < config.Resources.Memory {
- return warnings, fmt.Errorf("minimum memoryswap limit should be larger than memory limit, see usage")
- }
- if config.Resources.Memory == 0 && config.Resources.MemorySwap > 0 && !update {
- return warnings, fmt.Errorf("you should always set the memory limit when using memoryswap limit, see usage")
- }
- if config.Resources.MemorySwappiness != -1 {
- if !sysInfo.MemorySwappiness {
- msg := "Your kernel does not support memory swappiness capabilities, or the cgroup is not mounted. Memory swappiness discarded."
- warnings = addWarning(warnings, msg)
- config.Resources.MemorySwappiness = -1
- } else {
- swappiness := config.Resources.MemorySwappiness
- if swappiness < -1 || swappiness > 100 {
- return warnings, fmt.Errorf("invalid value: %v, valid memory swappiness range is 0-100", swappiness)
- }
- }
- }
- if config.Resources.MemoryReservation > 0 && !sysInfo.MemoryReservation {
- warnings = addWarning(warnings, "Your kernel does not support memory soft limit capabilities or the cgroup is not mounted. Limitation discarded.")
- config.Resources.MemoryReservation = 0
- }
- if config.Resources.MemoryReservation > 0 && config.Resources.MemoryReservation < linuxMinMemory {
- return warnings, fmt.Errorf("minimum memory reservation allowed is 4MB")
- }
- if config.Resources.Memory > 0 && config.Resources.MemoryReservation > 0 && config.Resources.Memory < config.Resources.MemoryReservation {
- return warnings, fmt.Errorf("minimum memory limit can not be less than memory reservation limit, see usage")
- }
- if config.Resources.KernelMemory > 0 && !sysInfo.KernelMemory {
- warnings = addWarning(warnings, "Your kernel does not support kernel memory limit capabilities or the cgroup is not mounted. Limitation discarded.")
- config.Resources.KernelMemory = 0
- }
- if config.Resources.KernelMemory > 0 && config.Resources.KernelMemory < linuxMinMemory {
- return warnings, fmt.Errorf("minimum kernel memory limit allowed is 4MB")
- }
- if config.Resources.DisableOomKiller == true && !sysInfo.OomKillDisable {
- // only produce warnings if the setting wasn't to *disable* the OOM Kill; no point
- // warning the caller if they already wanted the feature to be off
- warnings = addWarning(warnings, "Your kernel does not support OomKillDisable. OomKillDisable discarded.")
- config.Resources.DisableOomKiller = false
- }
-
- if config.Resources.PidsLimit != 0 && !sysInfo.PidsLimit {
- warnings = addWarning(warnings, "Your kernel does not support pids limit capabilities or the cgroup is not mounted. PIDs limit discarded.")
- config.Resources.PidsLimit = 0
- }
-
- if config.Resources.CPUShares > 0 && !sysInfo.CPUShares {
- warnings = addWarning(warnings, "Your kernel does not support CPU shares or the cgroup is not mounted. Shares discarded.")
- config.Resources.CPUShares = 0
- }
- if config.Resources.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod {
- warnings = addWarning(warnings, "Your kernel does not support CPU cfs period or the cgroup is not mounted. Period discarded.")
- config.Resources.CPUPeriod = 0
- }
- if config.Resources.CPUPeriod != 0 && (config.Resources.CPUPeriod < 1000 || config.Resources.CPUPeriod > 1000000) {
- return warnings, fmt.Errorf("CPU cfs period can not be less than 1ms (i.e. 1000) or larger than 1s (i.e. 1000000)")
- }
- if config.Resources.CPUQuota > 0 && !sysInfo.CPUCfsQuota {
- warnings = addWarning(warnings, "Your kernel does not support CPU cfs quota or the cgroup is not mounted. Quota discarded.")
- config.Resources.CPUQuota = 0
- }
- if config.Resources.CPUQuota > 0 && config.Resources.CPUQuota < 1000 {
- return warnings, fmt.Errorf("CPU cfs quota can not be less than 1ms (i.e. 1000)")
- }
- // cpuset subsystem checks and adjustments
- if (config.Resources.CPUsetCPUs != "" || config.Resources.CPUsetMems != "") && !sysInfo.Cpuset {
- warnings = addWarning(warnings, "Your kernel does not support cpuset or the cgroup is not mounted. CPUset discarded.")
- config.Resources.CPUsetCPUs = ""
- config.Resources.CPUsetMems = ""
- }
- cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(config.Resources.CPUsetCPUs)
- if err != nil {
- return warnings, fmt.Errorf("invalid value %s for cpuset cpus", config.Resources.CPUsetCPUs)
- }
- if !cpusAvailable {
- return warnings, fmt.Errorf("requested CPUs are not available - requested %s, available: %s", config.Resources.CPUsetCPUs, sysInfo.Cpus)
- }
- memsAvailable, err := sysInfo.IsCpusetMemsAvailable(config.Resources.CPUsetMems)
- if err != nil {
- return warnings, fmt.Errorf("invalid value %s for cpuset mems", config.Resources.CPUsetMems)
- }
- if !memsAvailable {
- return warnings, fmt.Errorf("requested memory nodes are not available - requested %s, available: %s", config.Resources.CPUsetMems, sysInfo.Mems)
- }
-
- // blkio subsystem checks and adjustments
- if config.Resources.BlkioWeight > 0 && !sysInfo.BlkioWeight {
- warnings = addWarning(warnings, "Your kernel does not support Block I/O weight or the cgroup is not mounted. Weight discarded.")
- config.Resources.BlkioWeight = 0
- }
- if config.Resources.BlkioWeight > 0 && (config.Resources.BlkioWeight < 10 || config.Resources.BlkioWeight > 1000) {
- return warnings, fmt.Errorf("range of blkio weight is from 10 to 1000")
- }
- if len(config.Resources.BlkioWeightDevice) > 0 && !sysInfo.BlkioWeightDevice {
- warnings = addWarning(warnings, "Your kernel does not support Block I/O weight_device or the cgroup is not mounted. Weight-device discarded.")
- config.Resources.BlkioWeightDevice = []string{}
- }
- if len(config.Resources.DeviceReadBps) > 0 && !sysInfo.BlkioReadBpsDevice {
- warnings = addWarning(warnings, "Your kernel does not support BPS Block I/O read limit or the cgroup is not mounted. Block I/O BPS read limit discarded")
- config.Resources.DeviceReadBps = []string{}
- }
- if len(config.Resources.DeviceWriteBps) > 0 && !sysInfo.BlkioWriteBpsDevice {
- warnings = addWarning(warnings, "Your kernel does not support BPS Block I/O write limit or the cgroup is not mounted. Block I/O BPS write limit discarded.")
- config.Resources.DeviceWriteBps = []string{}
- }
- if len(config.Resources.DeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice {
- warnings = addWarning(warnings, "Your kernel does not support IOPS Block read limit or the cgroup is not mounted. Block I/O IOPS read limit discarded.")
- config.Resources.DeviceReadIOps = []string{}
- }
- if len(config.Resources.DeviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice {
- warnings = addWarning(warnings, "Your kernel does not support IOPS Block I/O write limit or the cgroup is not mounted. Block I/O IOPS write limit discarded.")
- config.Resources.DeviceWriteIOps = []string{}
- }
-
- return warnings, nil
-}
diff --git a/cmd/kpod/create_cli_test.go b/cmd/kpod/create_cli_test.go
deleted file mode 100644
index 63a1e5dd3..000000000
--- a/cmd/kpod/create_cli_test.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package main
-
-import (
- "io/ioutil"
- "os"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-var (
- Var1 = []string{"ONE=1", "TWO=2"}
-)
-
-func createTmpFile(content []byte) (string, error) {
- tmpfile, err := ioutil.TempFile(os.TempDir(), "unittest")
- if err != nil {
- return "", err
- }
-
- if _, err := tmpfile.Write(content); err != nil {
- return "", err
-
- }
- if err := tmpfile.Close(); err != nil {
- return "", err
- }
- return tmpfile.Name(), nil
-}
-
-func TestConvertStringSliceToMap(t *testing.T) {
- strSlice := []string{"BLAU=BLUE", "GELB=YELLOW"}
- result, _ := convertStringSliceToMap(strSlice, "=")
- assert.Equal(t, result["BLAU"], "BLUE")
-}
-
-func TestConvertStringSliceToMapBadData(t *testing.T) {
- strSlice := []string{"BLAU=BLUE", "GELB^YELLOW"}
- _, err := convertStringSliceToMap(strSlice, "=")
- assert.Error(t, err)
-}
-
-func TestGetAllLabels(t *testing.T) {
- fileLabels := []string{}
- labels, _ := getAllLabels(fileLabels, Var1)
- assert.Equal(t, len(labels), 2)
-}
-
-func TestGetAllLabelsBadKeyValue(t *testing.T) {
- inLabels := []string{"ONE1", "TWO=2"}
- fileLabels := []string{}
- _, err := getAllLabels(fileLabels, inLabels)
- assert.Error(t, err, assert.AnError)
-}
-
-func TestGetAllLabelsBadLabelFile(t *testing.T) {
- fileLabels := []string{"/foobar5001/be"}
- _, err := getAllLabels(fileLabels, Var1)
- assert.Error(t, err, assert.AnError)
-}
-
-func TestGetAllLabelsFile(t *testing.T) {
- content := []byte("THREE=3")
- tFile, err := createTmpFile(content)
- defer os.Remove(tFile)
- assert.NoError(t, err)
- fileLabels := []string{tFile}
- result, _ := getAllLabels(fileLabels, Var1)
- assert.Equal(t, len(result), 3)
-}
diff --git a/cmd/kpod/diff.go b/cmd/kpod/diff.go
deleted file mode 100644
index 3a3b82e15..000000000
--- a/cmd/kpod/diff.go
+++ /dev/null
@@ -1,128 +0,0 @@
-package main
-
-import (
- "fmt"
-
- "github.com/containers/storage/pkg/archive"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/cmd/kpod/formats"
- "github.com/urfave/cli"
-)
-
-type diffJSONOutput struct {
- Changed []string `json:"changed,omitempty"`
- Added []string `json:"added,omitempty"`
- Deleted []string `json:"deleted,omitempty"`
-}
-
-type diffOutputParams struct {
- Change archive.ChangeType
- Path string
-}
-
-type stdoutStruct struct {
- output []diffOutputParams
-}
-
-func (so stdoutStruct) Out() error {
- for _, d := range so.output {
- fmt.Printf("%s %s\n", d.Change, d.Path)
- }
- return nil
-}
-
-var (
- diffFlags = []cli.Flag{
- cli.BoolFlag{
- Name: "archive",
- Usage: "Save the diff as a tar archive",
- Hidden: true,
- },
- cli.StringFlag{
- Name: "format",
- Usage: "Change the output format.",
- },
- }
- diffDescription = fmt.Sprint(`Displays changes on a container or image's filesystem. The
- container or image will be compared to its parent layer`)
-
- diffCommand = cli.Command{
- Name: "diff",
- Usage: "Inspect changes on container's file systems",
- Description: diffDescription,
- Flags: diffFlags,
- Action: diffCmd,
- ArgsUsage: "ID-NAME",
- }
-)
-
-func formatJSON(output []diffOutputParams) (diffJSONOutput, error) {
- jsonStruct := diffJSONOutput{}
- for _, output := range output {
- switch output.Change {
- case archive.ChangeModify:
- jsonStruct.Changed = append(jsonStruct.Changed, output.Path)
- case archive.ChangeAdd:
- jsonStruct.Added = append(jsonStruct.Added, output.Path)
- case archive.ChangeDelete:
- jsonStruct.Deleted = append(jsonStruct.Deleted, output.Path)
- default:
- return jsonStruct, errors.Errorf("output kind %q not recognized", output.Change.String())
- }
- }
- return jsonStruct, nil
-}
-
-func diffCmd(c *cli.Context) error {
- if err := validateFlags(c, diffFlags); err != nil {
- return err
- }
-
- if len(c.Args()) != 1 {
- return errors.Errorf("container, image, or layer name must be specified: kpod diff [options [...]] ID-NAME")
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- to := c.Args().Get(0)
- changes, err := runtime.GetDiff("", to)
- if err != nil {
- return errors.Wrapf(err, "could not get changes for %q", to)
- }
-
- diffOutput := []diffOutputParams{}
- outputFormat := c.String("format")
-
- for _, change := range changes {
-
- params := diffOutputParams{
- Change: change.Kind,
- Path: change.Path,
- }
- diffOutput = append(diffOutput, params)
- }
-
- var out formats.Writer
-
- if outputFormat != "" {
- switch outputFormat {
- case formats.JSONString:
- data, err := formatJSON(diffOutput)
- if err != nil {
- return err
- }
- out = formats.JSONStruct{Output: data}
- default:
- return errors.New("only valid format for diff is 'json'")
- }
- } else {
- out = stdoutStruct{output: diffOutput}
- }
- formats.Writer(out).Out()
-
- return nil
-}
diff --git a/cmd/kpod/docker/types.go b/cmd/kpod/docker/types.go
deleted file mode 100644
index a7e456554..000000000
--- a/cmd/kpod/docker/types.go
+++ /dev/null
@@ -1,271 +0,0 @@
-package docker
-
-//
-// Types extracted from Docker
-//
-
-import (
- "time"
-
- "github.com/containers/image/pkg/strslice"
- "github.com/opencontainers/go-digest"
-)
-
-// TypeLayers github.com/docker/docker/image/rootfs.go
-const TypeLayers = "layers"
-
-// V2S2MediaTypeManifest github.com/docker/distribution/manifest/schema2/manifest.go
-const V2S2MediaTypeManifest = "application/vnd.docker.distribution.manifest.v2+json"
-
-// V2S2MediaTypeImageConfig github.com/docker/distribution/manifest/schema2/manifest.go
-const V2S2MediaTypeImageConfig = "application/vnd.docker.container.image.v1+json"
-
-// V2S2MediaTypeLayer github.com/docker/distribution/manifest/schema2/manifest.go
-const V2S2MediaTypeLayer = "application/vnd.docker.image.rootfs.diff.tar.gzip"
-
-// V2S2MediaTypeUncompressedLayer github.com/docker/distribution/manifest/schema2/manifest.go
-const V2S2MediaTypeUncompressedLayer = "application/vnd.docker.image.rootfs.diff.tar"
-
-// V2S2RootFS describes images root filesystem
-// This is currently a placeholder that only supports layers. In the future
-// this can be made into an interface that supports different implementations.
-// github.com/docker/docker/image/rootfs.go
-type V2S2RootFS struct {
- Type string `json:"type"`
- DiffIDs []digest.Digest `json:"diff_ids,omitempty"`
-}
-
-// V2S2History stores build commands that were used to create an image
-// github.com/docker/docker/image/image.go
-type V2S2History struct {
- // Created is the timestamp at which the image was created
- Created time.Time `json:"created"`
- // Author is the name of the author that was specified when committing the image
- Author string `json:"author,omitempty"`
- // CreatedBy keeps the Dockerfile command used while building the image
- CreatedBy string `json:"created_by,omitempty"`
- // Comment is the commit message that was set when committing the image
- Comment string `json:"comment,omitempty"`
- // EmptyLayer is set to true if this history item did not generate a
- // layer. Otherwise, the history item is associated with the next
- // layer in the RootFS section.
- EmptyLayer bool `json:"empty_layer,omitempty"`
-}
-
-// ID is the content-addressable ID of an image.
-// github.com/docker/docker/image/image.go
-type ID digest.Digest
-
-// HealthConfig holds configuration settings for the HEALTHCHECK feature.
-// github.com/docker/docker/api/types/container/config.go
-type HealthConfig struct {
- // Test is the test to perform to check that the container is healthy.
- // An empty slice means to inherit the default.
- // The options are:
- // {} : inherit healthcheck
- // {"NONE"} : disable healthcheck
- // {"CMD", args...} : exec arguments directly
- // {"CMD-SHELL", command} : run command with system's default shell
- Test []string `json:",omitempty"`
-
- // Zero means to inherit. Durations are expressed as integer nanoseconds.
- Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks.
- Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung.
-
- // Retries is the number of consecutive failures needed to consider a container as unhealthy.
- // Zero means inherit.
- Retries int `json:",omitempty"`
-}
-
-// PortSet is a collection of structs indexed by Port
-// github.com/docker/go-connections/nat/nat.go
-type PortSet map[Port]struct{}
-
-// Port is a string containing port number and protocol in the format "80/tcp"
-// github.com/docker/go-connections/nat/nat.go
-type Port string
-
-// Config contains the configuration data about a container.
-// It should hold only portable information about the container.
-// Here, "portable" means "independent from the host we are running on".
-// Non-portable information *should* appear in HostConfig.
-// All fields added to this struct must be marked `omitempty` to keep getting
-// predictable hashes from the old `v1Compatibility` configuration.
-// github.com/docker/docker/api/types/container/config.go
-type Config struct {
- Hostname string // Hostname
- Domainname string // Domainname
- User string // User that will run the command(s) inside the container, also support user:group
- AttachStdin bool // Attach the standard input, makes possible user interaction
- AttachStdout bool // Attach the standard output
- AttachStderr bool // Attach the standard error
- ExposedPorts PortSet `json:",omitempty"` // List of exposed ports
- Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
- OpenStdin bool // Open stdin
- StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
- Env []string // List of environment variable to set in the container
- Cmd strslice.StrSlice // Command to run when starting the container
- Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
- ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (Windows specific)
- Image string // Name of the image as it was passed by the operator (e.g. could be symbolic)
- Volumes map[string]struct{} // List of volumes (mounts) used for the container
- WorkingDir string // Current directory (PWD) in the command will be launched
- Entrypoint strslice.StrSlice // Entrypoint to run when starting the container
- NetworkDisabled bool `json:",omitempty"` // Is network disabled
- MacAddress string `json:",omitempty"` // Mac Address of the container
- OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile
- Labels map[string]string // List of labels set to this container
- StopSignal string `json:",omitempty"` // Signal to stop a container
- StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container
- Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
-}
-
-// V1Compatibility - For non-top-level layers, create fake V1Compatibility
-// strings that fit the format and don't collide with anything else, but
-// don't result in runnable images on their own.
-// github.com/docker/distribution/manifest/schema1/config_builder.go
-type V1Compatibility struct {
- ID string `json:"id"`
- Parent string `json:"parent,omitempty"`
- Comment string `json:"comment,omitempty"`
- Created time.Time `json:"created"`
- ContainerConfig struct {
- Cmd []string
- } `json:"container_config,omitempty"`
- Author string `json:"author,omitempty"`
- ThrowAway bool `json:"throwaway,omitempty"`
-}
-
-// V1Image stores the V1 image configuration.
-// github.com/docker/docker/image/image.go
-type V1Image struct {
- // ID is a unique 64 character identifier of the image
- ID string `json:"id,omitempty"`
- // Parent is the ID of the parent image
- Parent string `json:"parent,omitempty"`
- // Comment is the commit message that was set when committing the image
- Comment string `json:"comment,omitempty"`
- // Created is the timestamp at which the image was created
- Created time.Time `json:"created"`
- // Container is the id of the container used to commit
- Container string `json:"container,omitempty"`
- // ContainerConfig is the configuration of the container that is committed into the image
- ContainerConfig Config `json:"container_config,omitempty"`
- // DockerVersion specifies the version of Docker that was used to build the image
- DockerVersion string `json:"docker_version,omitempty"`
- // Author is the name of the author that was specified when committing the image
- Author string `json:"author,omitempty"`
- // Config is the configuration of the container received from the client
- Config *Config `json:"config,omitempty"`
- // Architecture is the hardware that the image is build and runs on
- Architecture string `json:"architecture,omitempty"`
- // OS is the operating system used to build and run the image
- OS string `json:"os,omitempty"`
- // Size is the total size of the image including all layers it is composed of
- Size int64 `json:",omitempty"`
-}
-
-// V2Image stores the image configuration
-// github.com/docker/docker/image/image.go
-type V2Image struct {
- V1Image
- Parent ID `json:"parent,omitempty"`
- RootFS *V2S2RootFS `json:"rootfs,omitempty"`
- History []V2S2History `json:"history,omitempty"`
- OSVersion string `json:"os.version,omitempty"`
- OSFeatures []string `json:"os.features,omitempty"`
-
- // rawJSON caches the immutable JSON associated with this image.
- //rawJSON []byte
-
- // computedID is the ID computed from the hash of the image config.
- // Not to be confused with the legacy V1 ID in V1Image.
- //computedID ID
-}
-
-// V2Versioned provides a struct with the manifest schemaVersion and mediaType.
-// Incoming content with unknown schema version can be decoded against this
-// struct to check the version.
-// github.com/docker/distribution/manifest/versioned.go
-type V2Versioned struct {
- // SchemaVersion is the image manifest schema that this image follows
- SchemaVersion int `json:"schemaVersion"`
-
- // MediaType is the media type of this schema.
- MediaType string `json:"mediaType,omitempty"`
-}
-
-// V2S1FSLayer is a container struct for BlobSums defined in an image manifest
-// github.com/docker/distribution/manifest/schema1/manifest.go
-type V2S1FSLayer struct {
- // BlobSum is the tarsum of the referenced filesystem image layer
- BlobSum digest.Digest `json:"blobSum"`
-}
-
-// V2S1History stores unstructured v1 compatibility information
-// github.com/docker/distribution/manifest/schema1/manifest.go
-type V2S1History struct {
- // V1Compatibility is the raw v1 compatibility information
- V1Compatibility string `json:"v1Compatibility"`
-}
-
-// V2S1Manifest provides the base accessible fields for working with V2 image
-// format in the registry.
-// github.com/docker/distribution/manifest/schema1/manifest.go
-type V2S1Manifest struct {
- V2Versioned
-
- // Name is the name of the image's repository
- Name string `json:"name"`
-
- // Tag is the tag of the image specified by this manifest
- Tag string `json:"tag"`
-
- // Architecture is the host architecture on which this image is intended to
- // run
- Architecture string `json:"architecture"`
-
- // FSLayers is a list of filesystem layer blobSums contained in this image
- FSLayers []V2S1FSLayer `json:"fsLayers"`
-
- // History is a list of unstructured historical data for v1 compatibility
- History []V2S1History `json:"history"`
-}
-
-// V2S2Descriptor describes targeted content. Used in conjunction with a blob
-// store, a descriptor can be used to fetch, store and target any kind of
-// blob. The struct also describes the wire protocol format. Fields should
-// only be added but never changed.
-// github.com/docker/distribution/blobs.go
-type V2S2Descriptor struct {
- // MediaType describe the type of the content. All text based formats are
- // encoded as utf-8.
- MediaType string `json:"mediaType,omitempty"`
-
- // Size in bytes of content.
- Size int64 `json:"size,omitempty"`
-
- // Digest uniquely identifies the content. A byte stream can be verified
- // against against this digest.
- Digest digest.Digest `json:"digest,omitempty"`
-
- // URLs contains the source URLs of this content.
- URLs []string `json:"urls,omitempty"`
-
- // NOTE: Before adding a field here, please ensure that all
- // other options have been exhausted. Much of the type relationships
- // depend on the simplicity of this type.
-}
-
-// V2S2Manifest defines a schema2 manifest.
-// github.com/docker/distribution/manifest/schema2/manifest.go
-type V2S2Manifest struct {
- V2Versioned
-
- // Config references the image configuration as a blob.
- Config V2S2Descriptor `json:"config"`
-
- // Layers lists descriptors for the layers referenced by the
- // configuration.
- Layers []V2S2Descriptor `json:"layers"`
-}
diff --git a/cmd/kpod/exec.go b/cmd/kpod/exec.go
deleted file mode 100644
index f76983810..000000000
--- a/cmd/kpod/exec.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package main
-
-import (
- "fmt"
- "strings"
-
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
-)
-
-var (
- execFlags = []cli.Flag{
- cli.StringSliceFlag{
- Name: "env, e",
- Usage: "Set environment variables",
- },
- cli.BoolFlag{
- Name: "privileged",
- Usage: "Give the process extended Linux capabilities inside the container. The default is false",
- },
- cli.BoolFlag{
- Name: "tty, t",
- Usage: "Allocate a pseudo-TTY. The default is false",
- },
- cli.StringFlag{
- Name: "user, u",
- Usage: "Sets the username or UID used and optionally the groupname or GID for the specified command",
- },
- }
- execDescription = `
- kpod exec
-
- Run a command in a running container
-`
-
- execCommand = cli.Command{
- Name: "exec",
- Usage: "Run a process in a running container",
- Description: execDescription,
- Flags: execFlags,
- Action: execCmd,
- ArgsUsage: "CONTAINER-NAME",
- }
-)
-
-func execCmd(c *cli.Context) error {
- var envs []string
- args := c.Args()
- if len(args) < 1 {
- return errors.Errorf("you must provide one container name or id")
- }
- if len(args) < 2 {
- return errors.Errorf("you must provide a command to exec")
- }
- cmd := args[1:]
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "error creating libpod runtime")
- }
- defer runtime.Shutdown(false)
-
- ctr, err := runtime.LookupContainer(args[0])
- if err != nil {
- return errors.Wrapf(err, "unable to exec into %s", args[0])
- }
- // Create a list of keys provided by the user
- var userEnvKeys []string
- for _, env := range c.StringSlice("env") {
- splitEnv := strings.Split(env, "=")
- userEnvKeys = append(userEnvKeys, splitEnv[0])
- }
-
- envs = append(envs, c.StringSlice("env")...)
-
- // if the default key isnt in the user-provided list, add the default
- // key and value to the environment variables. this is needed to set
- // PATH for example.
- for k, v := range defaultEnvVariables {
- if !libpod.StringInSlice(k, userEnvKeys) {
- envs = append(envs, fmt.Sprintf("%s=%s", k, v))
- }
- }
-
- return ctr.Exec(c.Bool("tty"), c.Bool("privileged"), envs, cmd, c.String("user"))
-}
diff --git a/cmd/kpod/export.go b/cmd/kpod/export.go
deleted file mode 100644
index 9b498562e..000000000
--- a/cmd/kpod/export.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package main
-
-import (
- "os"
-
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "github.com/urfave/cli"
-)
-
-var (
- exportFlags = []cli.Flag{
- cli.StringFlag{
- Name: "output, o",
- Usage: "Write to a file, default is STDOUT",
- Value: "/dev/stdout",
- },
- }
- exportDescription = "Exports container's filesystem contents as a tar archive" +
- " and saves it on the local machine."
- exportCommand = cli.Command{
- Name: "export",
- Usage: "Export container's filesystem contents as a tar archive",
- Description: exportDescription,
- Flags: exportFlags,
- Action: exportCmd,
- ArgsUsage: "CONTAINER",
- }
-)
-
-// exportCmd saves a container to a tarball on disk
-func exportCmd(c *cli.Context) error {
- if err := validateFlags(c, exportFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- args := c.Args()
- if len(args) == 0 {
- return errors.Errorf("container id must be specified")
- }
- if len(args) > 1 {
- return errors.Errorf("too many arguments given, need 1 at most.")
- }
-
- output := c.String("output")
- if output == "/dev/stdout" {
- file := os.Stdout
- if logrus.IsTerminal(file) {
- return errors.Errorf("refusing to export to terminal. Use -o flag or redirect")
- }
- }
-
- ctr, err := runtime.LookupContainer(args[0])
- if err != nil {
- return errors.Wrapf(err, "error looking up container %q", args[0])
- }
-
- return ctr.Export(output)
-}
diff --git a/cmd/kpod/formats/formats.go b/cmd/kpod/formats/formats.go
deleted file mode 100644
index 4b6527b30..000000000
--- a/cmd/kpod/formats/formats.go
+++ /dev/null
@@ -1,143 +0,0 @@
-package formats
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "os"
- "strings"
- "text/tabwriter"
- "text/template"
-
- "github.com/ghodss/yaml"
- "github.com/pkg/errors"
-)
-
-const (
- // JSONString const to save on duplicate variable names
- JSONString = "json"
- // IDString const to save on duplicates for Go templates
- IDString = "{{.ID}}"
-)
-
-// Writer interface for outputs
-type Writer interface {
- Out() error
-}
-
-// JSONStructArray for JSON output
-type JSONStructArray struct {
- Output []interface{}
-}
-
-// StdoutTemplateArray for Go template output
-type StdoutTemplateArray struct {
- Output []interface{}
- Template string
- Fields map[string]string
-}
-
-// JSONStruct for JSON output
-type JSONStruct struct {
- Output interface{}
-}
-
-// StdoutTemplate for Go template output
-type StdoutTemplate struct {
- Output interface{}
- Template string
- Fields map[string]string
-}
-
-// YAMLStruct for YAML output
-type YAMLStruct struct {
- Output interface{}
-}
-
-// Out method for JSON Arrays
-func (j JSONStructArray) Out() error {
- data, err := json.MarshalIndent(j.Output, "", " ")
- if err != nil {
- return err
- }
-
- // JSON returns a byte array with a literal null [110 117 108 108] in it
- // if it is passed empty data. We used bytes.Compare to see if that is
- // the case.
- if diff := bytes.Compare(data, []byte("null")); diff == 0 {
- data = []byte("[]")
- }
-
- // If the we did get NULL back, we should spit out {} which is
- // at least valid JSON for the consumer.
- fmt.Printf("%s\n", data)
- return nil
-}
-
-// Out method for Go templates
-func (t StdoutTemplateArray) Out() error {
- w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
- if strings.HasPrefix(t.Template, "table") {
- // replace any spaces with tabs in template so that tabwriter can align it
- t.Template = strings.Replace(strings.TrimSpace(t.Template[5:]), " ", "\t", -1)
- headerTmpl, err := template.New("header").Funcs(headerFunctions).Parse(t.Template)
- if err != nil {
- return errors.Wrapf(err, "Template parsing error")
- }
- err = headerTmpl.Execute(w, t.Fields)
- if err != nil {
- return err
- }
- fmt.Fprintln(w, "")
- }
- t.Template = strings.Replace(t.Template, " ", "\t", -1)
- tmpl, err := template.New("image").Funcs(basicFunctions).Parse(t.Template)
- if err != nil {
- return errors.Wrapf(err, "Template parsing error")
- }
- for _, img := range t.Output {
- basicTmpl := tmpl.Funcs(basicFunctions)
- err = basicTmpl.Execute(w, img)
- if err != nil {
- return err
- }
- fmt.Fprintln(w, "")
- }
- return w.Flush()
-}
-
-// Out method for JSON struct
-func (j JSONStruct) Out() error {
- data, err := json.MarshalIndent(j.Output, "", " ")
- if err != nil {
- return err
- }
- fmt.Printf("%s\n", data)
- return nil
-}
-
-//Out method for Go templates
-func (t StdoutTemplate) Out() error {
- tmpl, err := template.New("image").Parse(t.Template)
- if err != nil {
- return errors.Wrapf(err, "template parsing error")
- }
- err = tmpl.Execute(os.Stdout, t.Output)
- if err != nil {
- return err
- }
- fmt.Println()
- return nil
-}
-
-// Out method for YAML
-func (y YAMLStruct) Out() error {
- var buf []byte
- var err error
- buf, err = yaml.Marshal(y.Output)
- if err != nil {
- return err
- }
- fmt.Println(string(buf))
- return nil
-}
diff --git a/cmd/kpod/formats/templates.go b/cmd/kpod/formats/templates.go
deleted file mode 100644
index c2582552a..000000000
--- a/cmd/kpod/formats/templates.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package formats
-
-import (
- "bytes"
- "encoding/json"
- "strings"
- "text/template"
-)
-
-// basicFunctions are the set of initial
-// functions provided to every template.
-var basicFunctions = template.FuncMap{
- "json": func(v interface{}) string {
- buf := &bytes.Buffer{}
- enc := json.NewEncoder(buf)
- enc.SetEscapeHTML(false)
- _ = enc.Encode(v)
- // Remove the trailing new line added by the encoder
- return strings.TrimSpace(buf.String())
- },
- "split": strings.Split,
- "join": strings.Join,
- "title": strings.Title,
- "lower": strings.ToLower,
- "upper": strings.ToUpper,
- "pad": padWithSpace,
- "truncate": truncateWithLength,
-}
-
-// HeaderFunctions are used to created headers of a table.
-// This is a replacement of basicFunctions for header generation
-// because we want the header to remain intact.
-// Some functions like `split` are irrelevant so not added.
-var headerFunctions = template.FuncMap{
- "json": func(v string) string {
- return v
- },
- "title": func(v string) string {
- return v
- },
- "lower": func(v string) string {
- return v
- },
- "upper": func(v string) string {
- return v
- },
- "truncate": func(v string, l int) string {
- return v
- },
-}
-
-// Parse creates a new anonymous template with the basic functions
-// and parses the given format.
-func Parse(format string) (*template.Template, error) {
- return NewParse("", format)
-}
-
-// NewParse creates a new tagged template with the basic functions
-// and parses the given format.
-func NewParse(tag, format string) (*template.Template, error) {
- return template.New(tag).Funcs(basicFunctions).Parse(format)
-}
-
-// padWithSpace adds whitespace to the input if the input is non-empty
-func padWithSpace(source string, prefix, suffix int) string {
- if source == "" {
- return source
- }
- return strings.Repeat(" ", prefix) + source + strings.Repeat(" ", suffix)
-}
-
-// truncateWithLength truncates the source string up to the length provided by the input
-func truncateWithLength(source string, length int) string {
- if len(source) < length {
- return source
- }
- return source[:length]
-}
diff --git a/cmd/kpod/history.go b/cmd/kpod/history.go
deleted file mode 100644
index 20422b7c3..000000000
--- a/cmd/kpod/history.go
+++ /dev/null
@@ -1,246 +0,0 @@
-package main
-
-import (
- "reflect"
- "strconv"
- "strings"
- "time"
-
- "github.com/containers/image/types"
- units "github.com/docker/go-units"
- "github.com/opencontainers/image-spec/specs-go/v1"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/cmd/kpod/formats"
- "github.com/urfave/cli"
-)
-
-const (
- createdByTruncLength = 45
- idTruncLength = 12
-)
-
-// historyTemplateParams stores info about each layer
-type historyTemplateParams struct {
- ID string
- Created string
- CreatedBy string
- Size string
- Comment string
-}
-
-// historyJSONParams is only used when the JSON format is specified,
-// and is better for data processing from JSON.
-// historyJSONParams will be populated by data from v1.History and types.BlobInfo,
-// the members of the struct are the sama data types as their sources.
-type historyJSONParams struct {
- ID string `json:"id"`
- Created *time.Time `json:"created"`
- CreatedBy string `json:"createdBy"`
- Size int64 `json:"size"`
- Comment string `json:"comment"`
-}
-
-// historyOptions stores cli flag values
-type historyOptions struct {
- human bool
- noTrunc bool
- quiet bool
- format string
-}
-
-var (
- historyFlags = []cli.Flag{
- cli.BoolTFlag{
- Name: "human, H",
- Usage: "Display sizes and dates in human readable format",
- },
- cli.BoolFlag{
- Name: "no-trunc, notruncate",
- Usage: "Do not truncate the output",
- },
- cli.BoolFlag{
- Name: "quiet, q",
- Usage: "Display the numeric IDs only",
- },
- cli.StringFlag{
- Name: "format",
- Usage: "Change the output to JSON or a Go template",
- },
- }
-
- historyDescription = "Displays the history of an image. The information can be printed out in an easy to read, " +
- "or user specified format, and can be truncated."
- historyCommand = cli.Command{
- Name: "history",
- Usage: "Show history of a specified image",
- Description: historyDescription,
- Flags: historyFlags,
- Action: historyCmd,
- ArgsUsage: "",
- UseShortOptionHandling: true,
- }
-)
-
-func historyCmd(c *cli.Context) error {
- if err := validateFlags(c, historyFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- format := genHistoryFormat(c.String("format"), c.Bool("quiet"))
-
- args := c.Args()
- if len(args) == 0 {
- return errors.Errorf("an image name must be specified")
- }
- if len(args) > 1 {
- return errors.Errorf("Kpod history takes at most 1 argument")
- }
- imgName := args[0]
-
- opts := historyOptions{
- human: c.BoolT("human"),
- noTrunc: c.Bool("no-trunc"),
- quiet: c.Bool("quiet"),
- format: format,
- }
-
- history, layers, imageID, err := runtime.GetHistory(imgName)
- if err != nil {
- return errors.Wrapf(err, "error getting history of image %q", imgName)
- }
-
- return generateHistoryOutput(history, layers, imageID, opts)
-}
-
-func genHistoryFormat(format string, quiet bool) string {
- if format != "" {
- // "\t" from the command line is not being recognized as a tab
- // replacing the string "\t" to a tab character if the user passes in "\t"
- return strings.Replace(format, `\t`, "\t", -1)
- }
- if quiet {
- return formats.IDString
- }
- return "table {{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\t"
-}
-
-// historyToGeneric makes an empty array of interfaces for output
-func historyToGeneric(templParams []historyTemplateParams, JSONParams []historyJSONParams) (genericParams []interface{}) {
- if len(templParams) > 0 {
- for _, v := range templParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
- }
- for _, v := range JSONParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
-}
-
-// generate the header based on the template provided
-func (h *historyTemplateParams) headerMap() map[string]string {
- v := reflect.Indirect(reflect.ValueOf(h))
- values := make(map[string]string)
- for h := 0; h < v.NumField(); h++ {
- key := v.Type().Field(h).Name
- value := key
- values[key] = strings.ToUpper(splitCamelCase(value))
- }
- return values
-}
-
-// getHistorytemplateOutput gets the modified history information to be printed in human readable format
-func getHistoryTemplateOutput(history []v1.History, layers []types.BlobInfo, imageID string, opts historyOptions) (historyOutput []historyTemplateParams) {
- var (
- outputSize string
- createdTime string
- createdBy string
- count = 1
- )
- for i := len(history) - 1; i >= 0; i-- {
- if i != len(history)-1 {
- imageID = "<missing>"
- }
- if !opts.noTrunc && i == len(history)-1 {
- imageID = imageID[:idTruncLength]
- }
-
- var size int64
- if !history[i].EmptyLayer {
- size = layers[len(layers)-count].Size
- count++
- }
-
- if opts.human {
- createdTime = units.HumanDuration(time.Since((*history[i].Created))) + " ago"
- outputSize = units.HumanSize(float64(size))
- } else {
- createdTime = (history[i].Created).Format(time.RFC3339)
- outputSize = strconv.FormatInt(size, 10)
- }
-
- createdBy = strings.Join(strings.Fields(history[i].CreatedBy), " ")
- if !opts.noTrunc && len(createdBy) > createdByTruncLength {
- createdBy = createdBy[:createdByTruncLength-3] + "..."
- }
-
- params := historyTemplateParams{
- ID: imageID,
- Created: createdTime,
- CreatedBy: createdBy,
- Size: outputSize,
- Comment: history[i].Comment,
- }
- historyOutput = append(historyOutput, params)
- }
- return
-}
-
-// getHistoryJSONOutput returns the history information in its raw form
-func getHistoryJSONOutput(history []v1.History, layers []types.BlobInfo, imageID string) (historyOutput []historyJSONParams) {
- count := 1
- for i := len(history) - 1; i >= 0; i-- {
- var size int64
- if !history[i].EmptyLayer {
- size = layers[len(layers)-count].Size
- count++
- }
-
- params := historyJSONParams{
- ID: imageID,
- Created: history[i].Created,
- CreatedBy: history[i].CreatedBy,
- Size: size,
- Comment: history[i].Comment,
- }
- historyOutput = append(historyOutput, params)
- }
- return
-}
-
-// generateHistoryOutput generates the history based on the format given
-func generateHistoryOutput(history []v1.History, layers []types.BlobInfo, imageID string, opts historyOptions) error {
- if len(history) == 0 {
- return nil
- }
-
- var out formats.Writer
-
- switch opts.format {
- case formats.JSONString:
- historyOutput := getHistoryJSONOutput(history, layers, imageID)
- out = formats.JSONStructArray{Output: historyToGeneric([]historyTemplateParams{}, historyOutput)}
- default:
- historyOutput := getHistoryTemplateOutput(history, layers, imageID, opts)
- out = formats.StdoutTemplateArray{Output: historyToGeneric(historyOutput, []historyJSONParams{}), Template: opts.format, Fields: historyOutput[0].headerMap()}
- }
-
- return formats.Writer(out).Out()
-}
diff --git a/cmd/kpod/images.go b/cmd/kpod/images.go
deleted file mode 100644
index 2b1003ebd..000000000
--- a/cmd/kpod/images.go
+++ /dev/null
@@ -1,337 +0,0 @@
-package main
-
-import (
- "fmt"
- "reflect"
- "strings"
- "time"
-
- "github.com/containers/storage"
- "github.com/docker/go-units"
- digest "github.com/opencontainers/go-digest"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/cmd/kpod/formats"
- "github.com/projectatomic/libpod/libpod"
- "github.com/projectatomic/libpod/libpod/common"
- "github.com/urfave/cli"
-)
-
-type imagesTemplateParams struct {
- Repository string
- Tag string
- ID string
- Digest digest.Digest
- Created string
- Size string
-}
-
-type imagesJSONParams struct {
- ID string `json:"id"`
- Name []string `json:"names"`
- Digest digest.Digest `json:"digest"`
- Created time.Time `json:"created"`
- Size int64 `json:"size"`
-}
-
-type imagesOptions struct {
- quiet bool
- noHeading bool
- noTrunc bool
- digests bool
- format string
-}
-
-var (
- imagesFlags = []cli.Flag{
- cli.BoolFlag{
- Name: "quiet, q",
- Usage: "display only image IDs",
- },
- cli.BoolFlag{
- Name: "noheading, n",
- Usage: "do not print column headings",
- },
- cli.BoolFlag{
- Name: "no-trunc, notruncate",
- Usage: "do not truncate output",
- },
- cli.BoolFlag{
- Name: "digests",
- Usage: "show digests",
- },
- cli.StringFlag{
- Name: "format",
- Usage: "Change the output format to JSON or a Go template",
- },
- cli.StringFlag{
- Name: "filter, f",
- Usage: "filter output based on conditions provided (default [])",
- },
- }
-
- imagesDescription = "lists locally stored images."
- imagesCommand = cli.Command{
- Name: "images",
- Usage: "list images in local storage",
- Description: imagesDescription,
- Flags: imagesFlags,
- Action: imagesCmd,
- ArgsUsage: "",
- UseShortOptionHandling: true,
- }
-)
-
-func imagesCmd(c *cli.Context) error {
- if err := validateFlags(c, imagesFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "Could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- format := genImagesFormat(c.String("format"), c.Bool("quiet"), c.Bool("noheading"), c.Bool("digests"))
-
- opts := imagesOptions{
- quiet: c.Bool("quiet"),
- noHeading: c.Bool("noheading"),
- noTrunc: c.Bool("no-trunc"),
- digests: c.Bool("digests"),
- format: format,
- }
-
- var imageInput string
- if len(c.Args()) == 1 {
- imageInput = c.Args().Get(0)
- }
- if len(c.Args()) > 1 {
- return errors.New("'kpod images' requires at most 1 argument")
- }
-
- params, err := runtime.ParseImageFilter(imageInput, c.String("filter"))
- if err != nil {
- return errors.Wrapf(err, "error parsing filter")
- }
-
- // generate the different filters
- labelFilter := generateImagesFilter(params, "label")
- beforeImageFilter := generateImagesFilter(params, "before-image")
- sinceImageFilter := generateImagesFilter(params, "since-image")
- danglingFilter := generateImagesFilter(params, "dangling")
- referenceFilter := generateImagesFilter(params, "reference")
- imageInputFilter := generateImagesFilter(params, "image-input")
-
- images, err := runtime.GetImages(params, labelFilter, beforeImageFilter, sinceImageFilter, danglingFilter, referenceFilter, imageInputFilter)
- if err != nil {
- return errors.Wrapf(err, "could not get list of images matching filter")
- }
-
- return generateImagesOutput(runtime, images, opts)
-}
-
-func genImagesFormat(format string, quiet, noHeading, digests bool) string {
- if format != "" {
- // "\t" from the command line is not being recognized as a tab
- // replacing the string "\t" to a tab character if the user passes in "\t"
- return strings.Replace(format, `\t`, "\t", -1)
- }
- if quiet {
- return formats.IDString
- }
- format = "table {{.Repository}}\t{{.Tag}}\t"
- if noHeading {
- format = "{{.Repository}}\t{{.Tag}}\t"
- }
- if digests {
- format += "{{.Digest}}\t"
- }
- format += "{{.ID}}\t{{.Created}}\t{{.Size}}\t"
- return format
-}
-
-// imagesToGeneric creates an empty array of interfaces for output
-func imagesToGeneric(templParams []imagesTemplateParams, JSONParams []imagesJSONParams) (genericParams []interface{}) {
- if len(templParams) > 0 {
- for _, v := range templParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
- }
- for _, v := range JSONParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
-}
-
-// generate the header based on the template provided
-func (i *imagesTemplateParams) headerMap() map[string]string {
- v := reflect.Indirect(reflect.ValueOf(i))
- values := make(map[string]string)
-
- for i := 0; i < v.NumField(); i++ {
- key := v.Type().Field(i).Name
- value := key
- if value == "ID" {
- value = "Image" + value
- }
- values[key] = strings.ToUpper(splitCamelCase(value))
- }
- return values
-}
-
-// getImagesTemplateOutput returns the images information to be printed in human readable format
-func getImagesTemplateOutput(runtime *libpod.Runtime, images []*storage.Image, opts imagesOptions) (imagesOutput []imagesTemplateParams) {
- var (
- lastID string
- )
- for _, img := range images {
- if opts.quiet && lastID == img.ID {
- continue // quiet should not show the same ID multiple times
- }
- createdTime := img.Created
-
- imageID := "sha256:" + img.ID
- if !opts.noTrunc {
- imageID = img.ID[:idTruncLength]
- }
-
- repository := "<none>"
- tag := "<none>"
- if len(img.Names) > 0 {
- arr := strings.Split(img.Names[0], ":")
- repository = arr[0]
- if len(arr) == 2 {
- tag = arr[1]
- }
- }
-
- imgData, _ := runtime.GetImageInspectInfo(*img)
- if imgData != nil {
- createdTime = *imgData.Created
- }
-
- params := imagesTemplateParams{
- Repository: repository,
- Tag: tag,
- ID: imageID,
- Digest: imgData.Digest,
- Created: units.HumanDuration(time.Since((createdTime))) + " ago",
- Size: units.HumanSizeWithPrecision(float64(imgData.Size), 3),
- }
- imagesOutput = append(imagesOutput, params)
- }
- return
-}
-
-// getImagesJSONOutput returns the images information in its raw form
-func getImagesJSONOutput(runtime *libpod.Runtime, images []*storage.Image) (imagesOutput []imagesJSONParams) {
- for _, img := range images {
- createdTime := img.Created
-
- imgData, _ := runtime.GetImageInspectInfo(*img)
- if imgData != nil {
- createdTime = *imgData.Created
- }
-
- params := imagesJSONParams{
- ID: img.ID,
- Name: img.Names,
- Digest: imgData.Digest,
- Created: createdTime,
- Size: imgData.Size,
- }
- imagesOutput = append(imagesOutput, params)
- }
- return
-}
-
-// generateImagesOutput generates the images based on the format provided
-func generateImagesOutput(runtime *libpod.Runtime, images []*storage.Image, opts imagesOptions) error {
- if len(images) == 0 {
- return nil
- }
-
- var out formats.Writer
-
- switch opts.format {
- case formats.JSONString:
- imagesOutput := getImagesJSONOutput(runtime, images)
- out = formats.JSONStructArray{Output: imagesToGeneric([]imagesTemplateParams{}, imagesOutput)}
- default:
- imagesOutput := getImagesTemplateOutput(runtime, images, opts)
- out = formats.StdoutTemplateArray{Output: imagesToGeneric(imagesOutput, []imagesJSONParams{}), Template: opts.format, Fields: imagesOutput[0].headerMap()}
-
- }
-
- return formats.Writer(out).Out()
-}
-
-// generateImagesFilter returns an ImageFilter based on filterType
-// to add more filters, define a new case and write what the ImageFilter function should do
-func generateImagesFilter(params *libpod.ImageFilterParams, filterType string) libpod.ImageFilter {
- switch filterType {
- case "label":
- return func(image *storage.Image, info *libpod.ImageData) bool {
- if params == nil || params.Label == "" {
- return true
- }
-
- pair := strings.SplitN(params.Label, "=", 2)
- if val, ok := info.Labels[pair[0]]; ok {
- if len(pair) == 2 && val == pair[1] {
- return true
- }
- if len(pair) == 1 {
- return true
- }
- }
- return false
- }
- case "before-image":
- return func(image *storage.Image, info *libpod.ImageData) bool {
- if params == nil || params.BeforeImage.IsZero() {
- return true
- }
- return info.Created.Before(params.BeforeImage)
- }
- case "since-image":
- return func(image *storage.Image, info *libpod.ImageData) bool {
- if params == nil || params.SinceImage.IsZero() {
- return true
- }
- return info.Created.After(params.SinceImage)
- }
- case "dangling":
- return func(image *storage.Image, info *libpod.ImageData) bool {
- if params == nil || params.Dangling == "" {
- return true
- }
- if common.IsFalse(params.Dangling) && params.ImageName != "<none>" {
- return true
- }
- if common.IsTrue(params.Dangling) && params.ImageName == "<none>" {
- return true
- }
- return false
- }
- case "reference":
- return func(image *storage.Image, info *libpod.ImageData) bool {
- if params == nil || params.ReferencePattern == "" {
- return true
- }
- return libpod.MatchesReference(params.ImageName, params.ReferencePattern)
- }
- case "image-input":
- return func(image *storage.Image, info *libpod.ImageData) bool {
- if params == nil || params.ImageInput == "" {
- return true
- }
- return libpod.MatchesReference(params.ImageName, params.ImageInput)
- }
- default:
- fmt.Println("invalid filter type", filterType)
- return nil
- }
-}
diff --git a/cmd/kpod/import.go b/cmd/kpod/import.go
deleted file mode 100644
index 2e8702c3d..000000000
--- a/cmd/kpod/import.go
+++ /dev/null
@@ -1,190 +0,0 @@
-package main
-
-import (
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "os"
- "strings"
-
- "github.com/opencontainers/image-spec/specs-go/v1"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
-)
-
-var (
- importFlags = []cli.Flag{
- cli.StringSliceFlag{
- Name: "change, c",
- Usage: "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR",
- },
- cli.StringFlag{
- Name: "message, m",
- Usage: "Set commit message for imported image",
- },
- }
- importDescription = `Create a container image from the contents of the specified tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz).
- Note remote tar balls can be specified, via web address.
- Optionally tag the image. You can specify the Dockerfile instructions using the --change option.
- `
- importCommand = cli.Command{
- Name: "import",
- Usage: "Import a tarball to create a filesystem image",
- Description: importDescription,
- Flags: importFlags,
- Action: importCmd,
- ArgsUsage: "TARBALL [REFERENCE]",
- }
-)
-
-func importCmd(c *cli.Context) error {
- if err := validateFlags(c, importFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- var opts libpod.CopyOptions
- var source string
- args := c.Args()
- switch len(args) {
- case 0:
- return errors.Errorf("need to give the path to the tarball, or must specify a tarball of '-' for stdin")
- case 1:
- source = args[0]
- case 2:
- source = args[0]
- opts.Reference = args[1]
- default:
- return errors.Errorf("too many arguments. Usage TARBALL [REFERENCE]")
- }
-
- changes := v1.ImageConfig{}
- if c.IsSet("change") {
- changes, err = getImageConfig(c.StringSlice("change"))
- if err != nil {
- return errors.Wrapf(err, "error adding config changes to image %q", source)
- }
- }
-
- history := []v1.History{
- {Comment: c.String("message")},
- }
-
- config := v1.Image{
- Config: changes,
- History: history,
- }
-
- opts.ImageConfig = config
-
- // if source is a url, download it and save to a temp file
- u, err := url.ParseRequestURI(source)
- if err == nil && u.Scheme != "" {
- file, err := downloadFromURL(source)
- if err != nil {
- return err
- }
- defer os.Remove(file)
- source = file
- }
-
- return runtime.ImportImage(source, opts)
-}
-
-// donwloadFromURL downloads an image in the format "https:/example.com/myimage.tar"
-// and tempoarily saves in it /var/tmp/importxyz, which is deleted after the image is imported
-func downloadFromURL(source string) (string, error) {
- fmt.Printf("Downloading from %q\n", source)
-
- outFile, err := ioutil.TempFile("/var/tmp", "import")
- if err != nil {
- return "", errors.Wrap(err, "error creating file")
- }
- defer outFile.Close()
-
- response, err := http.Get(source)
- if err != nil {
- return "", errors.Wrapf(err, "error downloading %q", source)
- }
- defer response.Body.Close()
-
- _, err = io.Copy(outFile, response.Body)
- if err != nil {
- return "", errors.Wrapf(err, "error saving %q to %q", source, outFile)
- }
-
- return outFile.Name(), nil
-}
-
-// getImageConfig converts the --change flag values in the format "CMD=/bin/bash USER=example"
-// to a type v1.ImageConfig
-func getImageConfig(changes []string) (v1.ImageConfig, error) {
- // USER=value | EXPOSE=value | ENV=value | ENTRYPOINT=value |
- // CMD=value | VOLUME=value | WORKDIR=value | LABEL=key=value | STOPSIGNAL=value
-
- var (
- user string
- env []string
- entrypoint []string
- cmd []string
- workingDir string
- stopSignal string
- )
-
- exposedPorts := make(map[string]struct{})
- volumes := make(map[string]struct{})
- labels := make(map[string]string)
-
- for _, ch := range changes {
- pair := strings.Split(ch, "=")
- if len(pair) == 1 {
- return v1.ImageConfig{}, errors.Errorf("no value given for instruction %q", ch)
- }
- switch pair[0] {
- case "USER":
- user = pair[1]
- case "EXPOSE":
- var st struct{}
- exposedPorts[pair[1]] = st
- case "ENV":
- env = append(env, pair[1])
- case "ENTRYPOINT":
- entrypoint = append(entrypoint, pair[1])
- case "CMD":
- cmd = append(cmd, pair[1])
- case "VOLUME":
- var st struct{}
- volumes[pair[1]] = st
- case "WORKDIR":
- workingDir = pair[1]
- case "LABEL":
- if len(pair) == 3 {
- labels[pair[1]] = pair[2]
- } else {
- labels[pair[1]] = ""
- }
- case "STOPSIGNAL":
- stopSignal = pair[1]
- }
- }
-
- return v1.ImageConfig{
- User: user,
- ExposedPorts: exposedPorts,
- Env: env,
- Entrypoint: entrypoint,
- Cmd: cmd,
- Volumes: volumes,
- WorkingDir: workingDir,
- Labels: labels,
- StopSignal: stopSignal,
- }, nil
-}
diff --git a/cmd/kpod/info.go b/cmd/kpod/info.go
deleted file mode 100644
index c491b4585..000000000
--- a/cmd/kpod/info.go
+++ /dev/null
@@ -1,84 +0,0 @@
-package main
-
-import (
- "runtime"
-
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/cmd/kpod/formats"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
-)
-
-var (
- infoDescription = "display system information"
- infoCommand = cli.Command{
- Name: "info",
- Usage: infoDescription,
- Description: `Information display here pertain to the host, current storage stats, and build of kpod. Useful for the user and when reporting issues.`,
- Flags: infoFlags,
- Action: infoCmd,
- ArgsUsage: "",
- }
- infoFlags = []cli.Flag{
- cli.BoolFlag{
- Name: "debug, D",
- Usage: "display additional debug information",
- },
- cli.StringFlag{
- Name: "format",
- Usage: "Change the output format to JSON or a Go template",
- },
- }
-)
-
-func infoCmd(c *cli.Context) error {
- if err := validateFlags(c, infoFlags); err != nil {
- return err
- }
- info := map[string]interface{}{}
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- infoArr, err := runtime.Info()
- if err != nil {
- return errors.Wrapf(err, "error getting info")
- }
-
- if c.Bool("debug") {
- debugInfo := debugInfo(c)
- infoArr = append(infoArr, libpod.InfoData{Type: "debug", Data: debugInfo})
- }
-
- for _, currInfo := range infoArr {
- info[currInfo.Type] = currInfo.Data
- }
-
- var out formats.Writer
- infoOutputFormat := c.String("format")
- switch infoOutputFormat {
- case formats.JSONString:
- out = formats.JSONStruct{Output: info}
- case "":
- out = formats.YAMLStruct{Output: info}
- default:
- out = formats.StdoutTemplate{Output: info, Template: infoOutputFormat}
- }
-
- formats.Writer(out).Out()
-
- return nil
-}
-
-// top-level "debug" info
-func debugInfo(c *cli.Context) map[string]interface{} {
- info := map[string]interface{}{}
- info["compiler"] = runtime.Compiler
- info["go version"] = runtime.Version()
- info["kpod version"] = c.App.Version
- info["git commit"] = gitCommit
- return info
-}
diff --git a/cmd/kpod/inspect.go b/cmd/kpod/inspect.go
deleted file mode 100644
index 3f9da8d83..000000000
--- a/cmd/kpod/inspect.go
+++ /dev/null
@@ -1,364 +0,0 @@
-package main
-
-import (
- "encoding/json"
-
- specs "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/cmd/kpod/formats"
- "github.com/projectatomic/libpod/libpod"
- "github.com/sirupsen/logrus"
- "github.com/urfave/cli"
-)
-
-const (
- inspectTypeContainer = "container"
- inspectTypeImage = "image"
- inspectAll = "all"
-)
-
-var (
- inspectFlags = []cli.Flag{
- cli.StringFlag{
- Name: "type, t",
- Value: inspectAll,
- Usage: "Return JSON for specified type, (e.g image, container or task)",
- },
- cli.StringFlag{
- Name: "format, f",
- Usage: "Change the output format to a Go template",
- },
- cli.BoolFlag{
- Name: "size",
- Usage: "Display total file size if the type is container",
- },
- }
- inspectDescription = "This displays the low-level information on containers and images identified by name or ID. By default, this will render all results in a JSON array. If the container and image have the same name, this will return container JSON for unspecified type."
- inspectCommand = cli.Command{
- Name: "inspect",
- Usage: "Displays the configuration of a container or image",
- Description: inspectDescription,
- Flags: inspectFlags,
- Action: inspectCmd,
- ArgsUsage: "CONTAINER-OR-IMAGE",
- }
-)
-
-func inspectCmd(c *cli.Context) error {
- args := c.Args()
- if len(args) == 0 {
- return errors.Errorf("container or image name must be specified: kpod inspect [options [...]] name")
- }
- if len(args) > 1 {
- return errors.Errorf("too many arguments specified")
- }
- if err := validateFlags(c, inspectFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "error creating libpod runtime")
- }
- defer runtime.Shutdown(false)
-
- if c.String("type") != inspectTypeContainer && c.String("type") != inspectTypeImage && c.String("type") != inspectAll {
- return errors.Errorf("the only recognized types are %q, %q, and %q", inspectTypeContainer, inspectTypeImage, inspectAll)
- }
-
- name := args[0]
-
- outputFormat := c.String("format")
- var data interface{}
- switch c.String("type") {
- case inspectTypeContainer:
- ctr, err := runtime.LookupContainer(name)
- if err != nil {
- return errors.Wrapf(err, "error looking up container %q", name)
- }
- libpodInspectData, err := ctr.Inspect(c.Bool("size"))
- if err != nil {
- return errors.Wrapf(err, "error getting libpod container inspect data %q", ctr.ID)
- }
- data, err = getCtrInspectInfo(ctr, libpodInspectData)
- if err != nil {
- return errors.Wrapf(err, "error parsing container data %q", ctr.ID())
- }
- case inspectTypeImage:
- image, err := runtime.GetImage(name)
- if err != nil {
- return errors.Wrapf(err, "error getting image %q", name)
- }
- data, err = runtime.GetImageInspectInfo(*image)
- if err != nil {
- return errors.Wrapf(err, "error parsing image data %q", image.ID)
- }
- case inspectAll:
- ctr, err := runtime.LookupContainer(name)
- if err != nil {
- image, err := runtime.GetImage(name)
- if err != nil {
- return errors.Wrapf(err, "error getting image %q", name)
- }
- data, err = runtime.GetImageInspectInfo(*image)
- if err != nil {
- return errors.Wrapf(err, "error parsing image data %q", image.ID)
- }
- } else {
- libpodInspectData, err := ctr.Inspect(c.Bool("size"))
- if err != nil {
- return errors.Wrapf(err, "error getting libpod container inspect data %q", ctr.ID)
- }
- data, err = getCtrInspectInfo(ctr, libpodInspectData)
- if err != nil {
- return errors.Wrapf(err, "error parsing container data %q", ctr.ID)
- }
- }
- }
-
- var out formats.Writer
- if outputFormat != "" && outputFormat != formats.JSONString {
- //template
- out = formats.StdoutTemplate{Output: data, Template: outputFormat}
- } else {
- // default is json output
- out = formats.JSONStruct{Output: data}
- }
-
- formats.Writer(out).Out()
- return nil
-}
-
-func getCtrInspectInfo(ctr *libpod.Container, ctrInspectData *libpod.ContainerInspectData) (*ContainerData, error) {
- config := ctr.Config()
- spec := config.Spec
-
- cpus, mems, period, quota, realtimePeriod, realtimeRuntime, shares := getCPUInfo(spec)
- blkioWeight, blkioWeightDevice, blkioReadBps, blkioWriteBps, blkioReadIOPS, blkioeWriteIOPS := getBLKIOInfo(spec)
- memKernel, memReservation, memSwap, memSwappiness, memDisableOOMKiller := getMemoryInfo(spec)
- pidsLimit := getPidsInfo(spec)
- cgroup := getCgroup(spec)
-
- var createArtifact createConfig
- artifact, err := ctr.GetArtifact("create-config")
- if err == nil {
- if err := json.Unmarshal(artifact, &createArtifact); err != nil {
- return nil, err
- }
- } else {
- logrus.Errorf("couldn't get some inspect information, error getting artifact %q: %v", ctr.ID(), err)
- }
-
- data := &ContainerData{
- CtrInspectData: ctrInspectData,
- HostConfig: &HostConfig{
- ConsoleSize: spec.Process.ConsoleSize,
- OomScoreAdj: spec.Process.OOMScoreAdj,
- CPUShares: shares,
- BlkioWeight: blkioWeight,
- BlkioWeightDevice: blkioWeightDevice,
- BlkioDeviceReadBps: blkioReadBps,
- BlkioDeviceWriteBps: blkioWriteBps,
- BlkioDeviceReadIOps: blkioReadIOPS,
- BlkioDeviceWriteIOps: blkioeWriteIOPS,
- CPUPeriod: period,
- CPUQuota: quota,
- CPURealtimePeriod: realtimePeriod,
- CPURealtimeRuntime: realtimeRuntime,
- CPUSetCPUs: cpus,
- CPUSetMems: mems,
- Devices: spec.Linux.Devices,
- KernelMemory: memKernel,
- MemoryReservation: memReservation,
- MemorySwap: memSwap,
- MemorySwappiness: memSwappiness,
- OomKillDisable: memDisableOOMKiller,
- PidsLimit: pidsLimit,
- Privileged: spec.Process.NoNewPrivileges,
- ReadonlyRootfs: spec.Root.Readonly,
- Runtime: ctr.RuntimeName(),
- NetworkMode: string(createArtifact.NetMode),
- IpcMode: string(createArtifact.IpcMode),
- Cgroup: cgroup,
- UTSMode: string(createArtifact.UtsMode),
- UsernsMode: createArtifact.NsUser,
- GroupAdd: spec.Process.User.AdditionalGids,
- ContainerIDFile: createArtifact.CidFile,
- AutoRemove: createArtifact.Rm,
- CapAdd: createArtifact.CapAdd,
- CapDrop: createArtifact.CapDrop,
- DNS: createArtifact.DNSServers,
- DNSOptions: createArtifact.DNSOpt,
- DNSSearch: createArtifact.DNSSearch,
- PidMode: string(createArtifact.PidMode),
- CgroupParent: createArtifact.CgroupParent,
- ShmSize: createArtifact.Resources.ShmSize,
- Memory: createArtifact.Resources.Memory,
- Ulimits: createArtifact.Resources.Ulimit,
- SecurityOpt: createArtifact.SecurityOpts,
- },
- Config: &CtrConfig{
- Hostname: spec.Hostname,
- User: spec.Process.User,
- Env: spec.Process.Env,
- Image: config.RootfsImageName,
- WorkingDir: spec.Process.Cwd,
- Labels: config.Labels,
- Annotations: spec.Annotations,
- Tty: spec.Process.Terminal,
- OpenStdin: config.Stdin,
- StopSignal: config.StopSignal,
- Cmd: config.Spec.Process.Args,
- Entrypoint: createArtifact.Entrypoint,
- },
- }
- return data, nil
-}
-
-func getCPUInfo(spec *specs.Spec) (string, string, *uint64, *int64, *uint64, *int64, *uint64) {
- if spec.Linux.Resources == nil {
- return "", "", nil, nil, nil, nil, nil
- }
- cpu := spec.Linux.Resources.CPU
- if cpu == nil {
- return "", "", nil, nil, nil, nil, nil
- }
- return cpu.Cpus, cpu.Mems, cpu.Period, cpu.Quota, cpu.RealtimePeriod, cpu.RealtimeRuntime, cpu.Shares
-}
-
-func getBLKIOInfo(spec *specs.Spec) (*uint16, []specs.LinuxWeightDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice) {
- if spec.Linux.Resources == nil {
- return nil, nil, nil, nil, nil, nil
- }
- blkio := spec.Linux.Resources.BlockIO
- if blkio == nil {
- return nil, nil, nil, nil, nil, nil
- }
- return blkio.Weight, blkio.WeightDevice, blkio.ThrottleReadBpsDevice, blkio.ThrottleWriteBpsDevice, blkio.ThrottleReadIOPSDevice, blkio.ThrottleWriteIOPSDevice
-}
-
-func getMemoryInfo(spec *specs.Spec) (*int64, *int64, *int64, *uint64, *bool) {
- if spec.Linux.Resources == nil {
- return nil, nil, nil, nil, nil
- }
- memory := spec.Linux.Resources.Memory
- if memory == nil {
- return nil, nil, nil, nil, nil
- }
- return memory.Kernel, memory.Reservation, memory.Swap, memory.Swappiness, memory.DisableOOMKiller
-}
-
-func getPidsInfo(spec *specs.Spec) *int64 {
- if spec.Linux.Resources == nil {
- return nil
- }
- pids := spec.Linux.Resources.Pids
- if pids == nil {
- return nil
- }
- return &pids.Limit
-}
-
-func getCgroup(spec *specs.Spec) string {
- cgroup := "host"
- for _, ns := range spec.Linux.Namespaces {
- if ns.Type == specs.CgroupNamespace && ns.Path != "" {
- cgroup = "container"
- }
- }
- return cgroup
-}
-
-// ContainerData holds the kpod inspect data for a container
-type ContainerData struct {
- CtrInspectData *libpod.ContainerInspectData `json:"CtrInspectData"`
- HostConfig *HostConfig `json:"HostConfig"`
- Config *CtrConfig `json:"Config"`
-}
-
-// LogConfig holds the log information for a container
-type LogConfig struct {
- Type string `json:"Type"` // TODO
- Config map[string]string `json:"Config"` //idk type, TODO
-}
-
-// HostConfig represents the host configuration for the container
-type HostConfig struct {
- ContainerIDFile string `json:"ContainerIDFile"`
- LogConfig *LogConfig `json:"LogConfig"` //TODO
- NetworkMode string `json:"NetworkMode"`
- PortBindings map[string]struct{} `json:"PortBindings"` //TODO
- AutoRemove bool `json:"AutoRemove"`
- CapAdd []string `json:"CapAdd"`
- CapDrop []string `json:"CapDrop"`
- DNS []string `json:"DNS"`
- DNSOptions []string `json:"DNSOptions"`
- DNSSearch []string `json:"DNSSearch"`
- ExtraHosts []string `json:"ExtraHosts"`
- GroupAdd []uint32 `json:"GroupAdd"`
- IpcMode string `json:"IpcMode"`
- Cgroup string `json:"Cgroup"`
- OomScoreAdj *int `json:"OomScoreAdj"`
- PidMode string `json:"PidMode"`
- Privileged bool `json:"Privileged"`
- PublishAllPorts bool `json:"PublishAllPorts"` //TODO
- ReadonlyRootfs bool `json:"ReadonlyRootfs"`
- SecurityOpt []string `json:"SecurityOpt"`
- UTSMode string `json:"UTSMode"`
- UsernsMode string `json:"UsernsMode"`
- ShmSize string `json:"ShmSize"`
- Runtime string `json:"Runtime"`
- ConsoleSize *specs.Box `json:"ConsoleSize"`
- Isolation string `json:"Isolation"` //TODO
- CPUShares *uint64 `json:"CPUSShares"`
- Memory int64 `json:"Memory"`
- NanoCPUs int `json:"NanoCPUs"` //check type, TODO
- CgroupParent string `json:"CgroupParent"`
- BlkioWeight *uint16 `json:"BlkioWeight"`
- BlkioWeightDevice []specs.LinuxWeightDevice `json:"BlkioWeightDevice"`
- BlkioDeviceReadBps []specs.LinuxThrottleDevice `json:"BlkioDeviceReadBps"`
- BlkioDeviceWriteBps []specs.LinuxThrottleDevice `json:"BlkioDeviceWriteBps"`
- BlkioDeviceReadIOps []specs.LinuxThrottleDevice `json:"BlkioDeviceReadIOps"`
- BlkioDeviceWriteIOps []specs.LinuxThrottleDevice `json:"BlkioDeviceWriteIOps"`
- CPUPeriod *uint64 `json:"CPUPeriod"`
- CPUQuota *int64 `json:"CPUQuota"`
- CPURealtimePeriod *uint64 `json:"CPURealtimePeriod"`
- CPURealtimeRuntime *int64 `json:"CPURealtimeRuntime"`
- CPUSetCPUs string `json:"CPUSetCPUs"`
- CPUSetMems string `json:"CPUSetMems"`
- Devices []specs.LinuxDevice `json:"Devices"`
- DiskQuota int `json:"DiskQuota"` //check type, TODO
- KernelMemory *int64 `json:"KernelMemory"`
- MemoryReservation *int64 `json:"MemoryReservation"`
- MemorySwap *int64 `json:"MemorySwap"`
- MemorySwappiness *uint64 `json:"MemorySwappiness"`
- OomKillDisable *bool `json:"OomKillDisable"`
- PidsLimit *int64 `json:"PidsLimit"`
- Ulimits []string `json:"Ulimits"`
- CPUCount int `json:"CPUCount"` //check type, TODO
- CPUPercent int `json:"CPUPercent"` //check type, TODO
- IOMaximumIOps int `json:"IOMaximumIOps"` //check type, TODO
- IOMaximumBandwidth int `json:"IOMaximumBandwidth"` //check type, TODO
-}
-
-// CtrConfig holds information about the container configuration
-type CtrConfig struct {
- Hostname string `json:"Hostname"`
- DomainName string `json:"Domainname"` //TODO
- User specs.User `json:"User"`
- AttachStdin bool `json:"AttachStdin"` //TODO
- AttachStdout bool `json:"AttachStdout"` //TODO
- AttachStderr bool `json:"AttachStderr"` //TODO
- Tty bool `json:"Tty"`
- OpenStdin bool `json:"OpenStdin"`
- StdinOnce bool `json:"StdinOnce"` //TODO
- Env []string `json:"Env"`
- Cmd []string `json:"Cmd"`
- Image string `json:"Image"`
- Volumes map[string]struct{} `json:"Volumes"`
- WorkingDir string `json:"WorkingDir"`
- Entrypoint string `json:"Entrypoint"`
- Labels map[string]string `json:"Labels"`
- Annotations map[string]string `json:"Annotations"`
- StopSignal uint `json:"StopSignal"`
-}
diff --git a/cmd/kpod/kill.go b/cmd/kpod/kill.go
deleted file mode 100644
index 776c7ef20..000000000
--- a/cmd/kpod/kill.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
- "syscall"
-
- "github.com/docker/docker/pkg/signal"
- "github.com/pkg/errors"
- "github.com/urfave/cli"
-)
-
-var (
- killFlags = []cli.Flag{
- cli.StringFlag{
- Name: "signal, s",
- Usage: "Signal to send to the container",
- Value: "KILL",
- },
- }
- killDescription = "The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal."
- killCommand = cli.Command{
- Name: "kill",
- Usage: "Kill one or more running containers with a specific signal",
- Description: killDescription,
- Flags: killFlags,
- Action: killCmd,
- ArgsUsage: "[CONTAINER_NAME_OR_ID]",
- }
-)
-
-// killCmd kills one or more containers with a signal
-func killCmd(c *cli.Context) error {
- args := c.Args()
- if len(args) == 0 {
- return errors.Errorf("specify one or more containers to kill")
- }
- if err := validateFlags(c, killFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- var killSignal uint = uint(syscall.SIGTERM)
- if c.String("signal") != "" {
- // Check if the signalString provided by the user is valid
- // Invalid signals will return err
- sysSignal, err := signal.ParseSignal(c.String("signal"))
- if err != nil {
- return err
- }
- killSignal = uint(sysSignal)
- }
-
- var lastError error
- for _, container := range c.Args() {
- ctr, err := runtime.LookupContainer(container)
- if err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "unable to find container %v", container)
- continue
- }
-
- if err := ctr.Kill(killSignal); err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "unable to find container %v", container)
- } else {
- fmt.Println(ctr.ID())
- }
- }
- return lastError
-}
diff --git a/cmd/kpod/load.go b/cmd/kpod/load.go
deleted file mode 100644
index 5ae75a7a2..000000000
--- a/cmd/kpod/load.go
+++ /dev/null
@@ -1,123 +0,0 @@
-package main
-
-import (
- "fmt"
- "io"
- "io/ioutil"
- "os"
-
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
-)
-
-var (
- loadFlags = []cli.Flag{
- cli.StringFlag{
- Name: "input, i",
- Usage: "Read from archive file, default is STDIN",
- Value: "/dev/stdin",
- },
- cli.BoolFlag{
- Name: "quiet, q",
- Usage: "Suppress the output",
- },
- cli.StringFlag{
- Name: "signature-policy",
- Usage: "`pathname` of signature policy file (not usually used)",
- },
- }
- loadDescription = "Loads the image from docker-archive stored on the local machine."
- loadCommand = cli.Command{
- Name: "load",
- Usage: "load an image from docker archive",
- Description: loadDescription,
- Flags: loadFlags,
- Action: loadCmd,
- ArgsUsage: "",
- }
-)
-
-// loadCmd gets the image/file to be loaded from the command line
-// and calls loadImage to load the image to containers-storage
-func loadCmd(c *cli.Context) error {
-
- args := c.Args()
- var image string
- if len(args) == 1 {
- image = args[0]
- }
- if len(args) > 1 {
- return errors.New("too many arguments. Requires exactly 1")
- }
- if err := validateFlags(c, loadFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- input := c.String("input")
-
- if input == "/dev/stdin" {
- fi, err := os.Stdin.Stat()
- if err != nil {
- return err
- }
- // checking if loading from pipe
- if !fi.Mode().IsRegular() {
- outFile, err := ioutil.TempFile("/var/tmp", "kpod")
- if err != nil {
- return errors.Errorf("error creating file %v", err)
- }
- defer outFile.Close()
- defer os.Remove(outFile.Name())
-
- inFile, err := os.OpenFile(input, 0, 0666)
- if err != nil {
- return errors.Errorf("error reading file %v", err)
- }
- defer inFile.Close()
-
- _, err = io.Copy(outFile, inFile)
- if err != nil {
- return errors.Errorf("error copying file %v", err)
- }
-
- input = outFile.Name()
- }
- }
-
- var writer io.Writer
- if !c.Bool("quiet") {
- writer = os.Stdout
- }
-
- options := libpod.CopyOptions{
- SignaturePolicyPath: c.String("signature-policy"),
- Writer: writer,
- }
-
- src := libpod.DockerArchive + ":" + input
- imgName, err := runtime.PullImage(src, options)
- if err != nil {
- // generate full src name with specified image:tag
- fullSrc := libpod.OCIArchive + ":" + input
- if image != "" {
- fullSrc = fullSrc + ":" + image
- }
- imgName, err = runtime.PullImage(fullSrc, options)
- if err != nil {
- src = libpod.DirTransport + ":" + input
- imgName, err = runtime.PullImage(src, options)
- if err != nil {
- return errors.Wrapf(err, "error pulling %q", src)
- }
- }
- }
- fmt.Println("Loaded image: ", imgName)
- return nil
-}
diff --git a/cmd/kpod/login.go b/cmd/kpod/login.go
deleted file mode 100644
index 8984d069c..000000000
--- a/cmd/kpod/login.go
+++ /dev/null
@@ -1,110 +0,0 @@
-package main
-
-import (
- "bufio"
- "context"
- "fmt"
- "os"
- "strings"
-
- "github.com/containers/image/docker"
- "github.com/containers/image/pkg/docker/config"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod/common"
- "github.com/urfave/cli"
- "golang.org/x/crypto/ssh/terminal"
-)
-
-var (
- loginFlags = []cli.Flag{
- cli.StringFlag{
- Name: "password, p",
- Usage: "Password for registry",
- },
- cli.StringFlag{
- Name: "username, u",
- Usage: "Username for registry",
- },
- cli.StringFlag{
- Name: "authfile",
- Usage: "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
- },
- }
- loginDescription = "Login to a container registry on a specified server."
- loginCommand = cli.Command{
- Name: "login",
- Usage: "login to a container registry",
- Description: loginDescription,
- Flags: loginFlags,
- Action: loginCmd,
- ArgsUsage: "REGISTRY",
- }
-)
-
-// loginCmd uses the authentication package to store a user's authenticated credentials
-// in an auth.json file for future use
-func loginCmd(c *cli.Context) error {
- args := c.Args()
- if len(args) > 1 {
- return errors.Errorf("too many arguments, login takes only 1 argument")
- }
- if len(args) == 0 {
- return errors.Errorf("registry must be given")
- }
- var server string
- if len(args) == 1 {
- server = args[0]
- }
-
- sc := common.GetSystemContext("", c.String("authfile"), false)
-
- // username of user logged in to server (if one exists)
- userFromAuthFile := config.GetUserLoggedIn(sc, server)
- username, password, err := getUserAndPass(c.String("username"), c.String("password"), userFromAuthFile)
- if err != nil {
- return errors.Wrapf(err, "error getting username and password")
- }
-
- if err = docker.CheckAuth(context.TODO(), sc, username, password, server); err == nil {
- if err := config.SetAuthentication(sc, server, username, password); err != nil {
- return err
- }
- }
- switch err {
- case nil:
- fmt.Println("Login Succeeded!")
- return nil
- case docker.ErrUnauthorizedForCredentials:
- return errors.Errorf("error logging into %q: invalid username/password\n", server)
- default:
- return errors.Wrapf(err, "error authenticating creds for %q", server)
- }
-}
-
-// getUserAndPass gets the username and password from STDIN if not given
-// using the -u and -p flags
-func getUserAndPass(username, password, userFromAuthFile string) (string, string, error) {
- var err error
- reader := bufio.NewReader(os.Stdin)
- if username == "" {
- if userFromAuthFile != "" {
- fmt.Printf("Username (%s): ", userFromAuthFile)
- } else {
- fmt.Print("Username: ")
- }
- username, err = reader.ReadString('\n')
- if err != nil {
- return "", "", errors.Wrapf(err, "error reading username")
- }
- }
- if password == "" {
- fmt.Print("Password: ")
- pass, err := terminal.ReadPassword(0)
- if err != nil {
- return "", "", errors.Wrapf(err, "error reading password")
- }
- password = string(pass)
- fmt.Println()
- }
- return strings.TrimSpace(username), password, err
-}
diff --git a/cmd/kpod/logout.go b/cmd/kpod/logout.go
deleted file mode 100644
index cae8ddfb2..000000000
--- a/cmd/kpod/logout.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package main
-
-import (
- "fmt"
-
- "github.com/containers/image/pkg/docker/config"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod/common"
- "github.com/urfave/cli"
-)
-
-var (
- logoutFlags = []cli.Flag{
- cli.StringFlag{
- Name: "authfile",
- Usage: "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
- },
- cli.BoolFlag{
- Name: "all, a",
- Usage: "Remove the cached credentials for all registries in the auth file",
- },
- }
- logoutDescription = "Remove the cached username and password for the registry."
- logoutCommand = cli.Command{
- Name: "logout",
- Usage: "logout of a container registry",
- Description: logoutDescription,
- Flags: logoutFlags,
- Action: logoutCmd,
- ArgsUsage: "REGISTRY",
- }
-)
-
-// logoutCmd uses the authentication package to remove the authenticated of a registry
-// stored in the auth.json file
-func logoutCmd(c *cli.Context) error {
- args := c.Args()
- if len(args) > 1 {
- return errors.Errorf("too many arguments, logout takes only 1 argument")
- }
- if len(args) == 0 {
- return errors.Errorf("registry must be given")
- }
- var server string
- if len(args) == 1 {
- server = args[0]
- }
-
- sc := common.GetSystemContext("", c.String("authfile"), false)
-
- if c.Bool("all") {
- if err := config.RemoveAllAuthentication(sc); err != nil {
- return err
- }
- fmt.Println("Remove login credentials for all registries")
- return nil
- }
-
- err := config.RemoveAuthentication(sc, server)
- switch err {
- case nil:
- fmt.Printf("Remove login credentials for %s\n", server)
- return nil
- case config.ErrNotLoggedIn:
- return errors.Errorf("Not logged into %s\n", server)
- default:
- return errors.Wrapf(err, "error logging out of %q", server)
- }
-}
diff --git a/cmd/kpod/logs.go b/cmd/kpod/logs.go
deleted file mode 100644
index 726ba4a65..000000000
--- a/cmd/kpod/logs.go
+++ /dev/null
@@ -1,153 +0,0 @@
-package main
-
-import (
- "fmt"
- "strings"
- "time"
-
- "github.com/hpcloud/tail"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
-)
-
-type logOptions struct {
- details bool
- follow bool
- sinceTime time.Time
- tail uint64
-}
-
-var (
- logsFlags = []cli.Flag{
- cli.BoolFlag{
- Name: "details",
- Usage: "Show extra details provided to the logs",
- Hidden: true,
- },
- cli.BoolFlag{
- Name: "follow, f",
- Usage: "Follow log output. The default is false",
- },
- cli.StringFlag{
- Name: "since",
- Usage: "Show logs since TIMESTAMP",
- },
- cli.Uint64Flag{
- Name: "tail",
- Usage: "Output the specified number of LINES at the end of the logs. Defaults to 0, which prints all lines",
- },
- }
- logsDescription = "The kpod logs command batch-retrieves whatever logs are present for a container at the time of execution. This does not guarantee execution" +
- "order when combined with kpod run (i.e. your run may not have generated any logs at the time you execute kpod logs"
- logsCommand = cli.Command{
- Name: "logs",
- Usage: "Fetch the logs of a container",
- Description: logsDescription,
- Flags: logsFlags,
- Action: logsCmd,
- ArgsUsage: "CONTAINER",
- }
-)
-
-func logsCmd(c *cli.Context) error {
- if err := validateFlags(c, logsFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- args := c.Args()
- if len(args) != 1 {
- return errors.Errorf("'kpod logs' requires exactly one container name/ID")
- }
-
- sinceTime := time.Time{}
- if c.IsSet("since") {
- // parse time, error out if something is wrong
- since, err := time.Parse("2006-01-02T15:04:05.999999999-07:00", c.String("since"))
- if err != nil {
- return errors.Wrapf(err, "could not parse time: %q", c.String("since"))
- }
- sinceTime = since
- }
-
- opts := logOptions{
- details: c.Bool("details"),
- follow: c.Bool("follow"),
- sinceTime: sinceTime,
- tail: c.Uint64("tail"),
- }
-
- ctr, err := runtime.LookupContainer(args[0])
- if err != nil {
- return err
- }
-
- logs := make(chan string)
- go func() {
- err = getLogs(ctr, logs, opts)
- }()
- printLogs(logs)
- return err
-}
-
-// getLogs returns the logs of a container from the log file
-// log file is created when the container is started/ran
-func getLogs(container *libpod.Container, logChan chan string, opts logOptions) error {
- defer close(logChan)
-
- seekInfo := &tail.SeekInfo{Offset: 0, Whence: 0}
- if opts.tail > 0 {
- // seek to correct position in log files
- seekInfo.Offset = int64(opts.tail)
- seekInfo.Whence = 2
- }
-
- t, err := tail.TailFile(container.LogPath(), tail.Config{Follow: opts.follow, ReOpen: false, Location: seekInfo})
- for line := range t.Lines {
- if since, err := logSinceTime(opts.sinceTime, line.Text); err != nil || !since {
- continue
- }
- logMessage := line.Text[secondSpaceIndex(line.Text):]
- logChan <- logMessage
- }
- return err
-}
-
-func printLogs(logs chan string) {
- for line := range logs {
- fmt.Println(line)
- }
-}
-
-// returns true if the time stamps of the logs are equal to or after the
-// timestamp comparing to
-func logSinceTime(sinceTime time.Time, logStr string) (bool, error) {
- timestamp := strings.Split(logStr, " ")[0]
- logTime, err := time.Parse("2006-01-02T15:04:05.999999999-07:00", timestamp)
- if err != nil {
- return false, err
- }
- return logTime.After(sinceTime) || logTime.Equal(sinceTime), nil
-}
-
-// secondSpaceIndex returns the index of the second space in a string
-// In a line of the logs, the first two tokens are a timestamp and stdout/stderr,
-// followed by the message itself. This allows us to get the index of the message
-// and avoid sending the other information back to the caller of GetLogs()
-func secondSpaceIndex(line string) int {
- index := strings.Index(line, " ")
- if index == -1 {
- return 0
- }
- index = strings.Index(line[index:], " ")
- if index == -1 {
- return 0
- }
- return index
-}
diff --git a/cmd/kpod/main.go b/cmd/kpod/main.go
deleted file mode 100644
index a2a81c8b6..000000000
--- a/cmd/kpod/main.go
+++ /dev/null
@@ -1,161 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
- "runtime/pprof"
-
- "github.com/containers/storage/pkg/reexec"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "github.com/urfave/cli"
-)
-
-// This is populated by the Makefile from the VERSION file
-// in the repository
-var kpodVersion = ""
-
-func main() {
- debug := false
- cpuProfile := false
-
- if reexec.Init() {
- return
- }
-
- app := cli.NewApp()
- app.Name = "kpod"
- app.Usage = "manage pods and images"
-
- var v string
- if kpodVersion != "" {
- v = kpodVersion
- }
- app.Version = v
-
- app.Commands = []cli.Command{
- attachCommand,
- createCommand,
- diffCommand,
- execCommand,
- exportCommand,
- historyCommand,
- imagesCommand,
- importCommand,
- infoCommand,
- inspectCommand,
- killCommand,
- loadCommand,
- loginCommand,
- logoutCommand,
- logsCommand,
- mountCommand,
- pauseCommand,
- psCommand,
- pullCommand,
- pushCommand,
- rmCommand,
- rmiCommand,
- runCommand,
- saveCommand,
- startCommand,
- statsCommand,
- stopCommand,
- tagCommand,
- topCommand,
- umountCommand,
- unpauseCommand,
- versionCommand,
- waitCommand,
- }
- app.Before = func(c *cli.Context) error {
- logLevel := c.GlobalString("log-level")
- if logLevel != "" {
- level, err := logrus.ParseLevel(logLevel)
- if err != nil {
- return err
- }
-
- logrus.SetLevel(level)
- }
-
- if logLevel == "debug" {
- debug = true
-
- }
- if c.GlobalIsSet("cpu-profile") {
- f, err := os.Create(c.GlobalString("cpu-profile"))
- if err != nil {
- return errors.Wrapf(err, "unable to create cpu profiling file %s",
- c.GlobalString("cpu-profile"))
- }
- cpuProfile = true
- pprof.StartCPUProfile(f)
- }
- return nil
- }
- app.After = func(*cli.Context) error {
- // called by Run() when the command handler succeeds
- shutdownStores()
- if cpuProfile {
- pprof.StopCPUProfile()
- }
- return nil
- }
- cli.OsExiter = func(code int) {
- // called by Run() when the command fails, bypassing After()
- shutdownStores()
- os.Exit(code)
- }
- app.Flags = []cli.Flag{
- cli.StringFlag{
- Name: "cni-config-dir",
- Usage: "path of the configuration directory for CNI networks",
- },
- cli.StringFlag{
- Name: "config, c",
- Usage: "path of a config file detailing container server configuration options",
- },
- cli.StringFlag{
- Name: "conmon",
- Usage: "path of the conmon binary",
- },
- cli.StringFlag{
- Name: "cpu-profile",
- Usage: "path for the cpu profiling results",
- },
- cli.StringFlag{
- Name: "log-level",
- Usage: "log messages above specified level: debug, info, warn, error (default), fatal or panic",
- Value: "error",
- },
- cli.StringFlag{
- Name: "root",
- Usage: "path to the root directory in which data, including images, is stored",
- },
- cli.StringFlag{
- Name: "runroot",
- Usage: "path to the 'run directory' where all state information is stored",
- },
- cli.StringFlag{
- Name: "runtime",
- Usage: "path to the OCI-compatible binary used to run containers, default is /usr/bin/runc",
- },
- cli.StringFlag{
- Name: "storage-driver, s",
- Usage: "select which storage driver is used to manage storage of images and containers (default is overlay)",
- },
- cli.StringSliceFlag{
- Name: "storage-opt",
- Usage: "used to pass an option to the storage driver",
- },
- }
- if err := app.Run(os.Args); err != nil {
- if debug {
- logrus.Errorf(err.Error())
- } else {
- fmt.Fprintln(os.Stderr, err.Error())
- }
- cli.OsExiter(1)
- }
-}
diff --git a/cmd/kpod/mount.go b/cmd/kpod/mount.go
deleted file mode 100644
index e90f54537..000000000
--- a/cmd/kpod/mount.go
+++ /dev/null
@@ -1,125 +0,0 @@
-package main
-
-import (
- js "encoding/json"
- "fmt"
-
- "github.com/pkg/errors"
- of "github.com/projectatomic/libpod/cmd/kpod/formats"
- "github.com/urfave/cli"
-)
-
-var (
- mountDescription = `
- kpod mount
- Lists all mounted containers mount points
-
- kpod mount CONTAINER-NAME-OR-ID
- Mounts the specified container and outputs the mountpoint
-`
-
- mountFlags = []cli.Flag{
- cli.BoolFlag{
- Name: "notruncate",
- Usage: "do not truncate output",
- },
- cli.StringFlag{
- Name: "label",
- Usage: "SELinux label for the mount point",
- },
- cli.StringFlag{
- Name: "format",
- Usage: "Change the output format to Go template",
- },
- }
- mountCommand = cli.Command{
- Name: "mount",
- Usage: "Mount a working container's root filesystem",
- Description: mountDescription,
- Action: mountCmd,
- ArgsUsage: "[CONTAINER-NAME-OR-ID]",
- Flags: mountFlags,
- }
-)
-
-// jsonMountPoint stores info about each container
-type jsonMountPoint struct {
- ID string `json:"id"`
- Names []string `json:"names"`
- MountPoint string `json:"mountpoint"`
-}
-
-func mountCmd(c *cli.Context) error {
- if err := validateFlags(c, mountFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- formats := map[string]bool{
- "": true,
- of.JSONString: true,
- }
-
- args := c.Args()
- json := c.String("format") == of.JSONString
- if !formats[c.String("format")] {
- return errors.Errorf("%q is not a supported format", c.String("format"))
- }
-
- if len(args) > 1 {
- return errors.Errorf("too many arguments specified")
- }
-
- if len(args) == 1 {
- if json {
- return errors.Wrapf(err, "json option can not be used with a container id")
- }
- ctr, err := runtime.LookupContainer(args[0])
- if err != nil {
- return errors.Wrapf(err, "error looking up container %q", args[0])
- }
- mountPoint, err := ctr.Mount(c.String("label"))
- if err != nil {
- return errors.Wrapf(err, "error mounting container %q", ctr.ID())
- }
- fmt.Printf("%s\n", mountPoint)
- } else {
- jsonMountPoints := []jsonMountPoint{}
- containers, err2 := runtime.GetContainers()
- if err2 != nil {
- return errors.Wrapf(err2, "error reading list of all containers")
- }
- for _, container := range containers {
- mountPoint, err := container.MountPoint()
- if err != nil {
- return errors.Wrapf(err, "error getting mountpoint for %q", container.ID())
- }
- if mountPoint == "" {
- continue
- }
- if json {
- jsonMountPoints = append(jsonMountPoints, jsonMountPoint{ID: container.ID(), Names: []string{container.Name()}, MountPoint: mountPoint})
- continue
- }
-
- if c.Bool("notruncate") {
- fmt.Printf("%-64s %s\n", container.ID(), mountPoint)
- } else {
- fmt.Printf("%-12.12s %s\n", container.ID(), mountPoint)
- }
- }
- if json {
- data, err := js.MarshalIndent(jsonMountPoints, "", " ")
- if err != nil {
- return err
- }
- fmt.Printf("%s\n", data)
- }
- }
- return nil
-}
diff --git a/cmd/kpod/parse.go b/cmd/kpod/parse.go
deleted file mode 100644
index 53d49c36c..000000000
--- a/cmd/kpod/parse.go
+++ /dev/null
@@ -1,863 +0,0 @@
-//nolint
-// most of these validate and parse functions have been taken from projectatomic/docker
-// and modified for cri-o
-package main
-
-import (
- "bufio"
- "bytes"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net"
- "os"
- "os/user"
- "path"
- "regexp"
- "strconv"
- "strings"
-
- units "github.com/docker/go-units"
- specs "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
- pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
-)
-
-// Note: for flags that are in the form <number><unit>, use the RAMInBytes function
-// from the units package in docker/go-units/size.go
-
-var (
- whiteSpaces = " \t"
- alphaRegexp = regexp.MustCompile(`[a-zA-Z]`)
- domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`)
-)
-
-// validateExtraHost validates that the specified string is a valid extrahost and returns it.
-// ExtraHost is in the form of name:ip where the ip has to be a valid ip (ipv4 or ipv6).
-// for add-host flag
-func validateExtraHost(val string) (string, error) { //nolint
- // allow for IPv6 addresses in extra hosts by only splitting on first ":"
- arr := strings.SplitN(val, ":", 2)
- if len(arr) != 2 || len(arr[0]) == 0 {
- return "", fmt.Errorf("bad format for add-host: %q", val)
- }
- if _, err := validateIPAddress(arr[1]); err != nil {
- return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1])
- }
- return val, nil
-}
-
-// validateIPAddress validates an Ip address.
-// for dns, ip, and ip6 flags also
-func validateIPAddress(val string) (string, error) {
- var ip = net.ParseIP(strings.TrimSpace(val))
- if ip != nil {
- return ip.String(), nil
- }
- return "", fmt.Errorf("%s is not an ip address", val)
-}
-
-// validateAttach validates that the specified string is a valid attach option.
-// for attach flag
-func validateAttach(val string) (string, error) { //nolint
- s := strings.ToLower(val)
- for _, str := range []string{"stdin", "stdout", "stderr"} {
- if s == str {
- return s, nil
- }
- }
- return val, fmt.Errorf("valid streams are STDIN, STDOUT and STDERR")
-}
-
-// validate the blkioWeight falls in the range of 10 to 1000
-// for blkio-weight flag
-func validateBlkioWeight(val int64) (int64, error) { //nolint
- if val >= 10 && val <= 1000 {
- return val, nil
- }
- return -1, errors.Errorf("invalid blkio weight %q, should be between 10 and 1000", val)
-}
-
-// weightDevice is a structure that holds device:weight pair
-type weightDevice struct {
- path string
- weight uint16
-}
-
-func (w *weightDevice) String() string {
- return fmt.Sprintf("%s:%d", w.path, w.weight)
-}
-
-// validateweightDevice validates that the specified string has a valid device-weight format
-// for blkio-weight-device flag
-func validateweightDevice(val string) (*weightDevice, error) {
- split := strings.SplitN(val, ":", 2)
- if len(split) != 2 {
- return nil, fmt.Errorf("bad format: %s", val)
- }
- if !strings.HasPrefix(split[0], "/dev/") {
- return nil, fmt.Errorf("bad format for device path: %s", val)
- }
- weight, err := strconv.ParseUint(split[1], 10, 0)
- if err != nil {
- return nil, fmt.Errorf("invalid weight for device: %s", val)
- }
- if weight > 0 && (weight < 10 || weight > 1000) {
- return nil, fmt.Errorf("invalid weight for device: %s", val)
- }
-
- return &weightDevice{
- path: split[0],
- weight: uint16(weight),
- }, nil
-}
-
-// parseDevice parses a device mapping string to a container.DeviceMapping struct
-// for device flag
-func parseDevice(device string) (*pb.Device, error) { //nolint
- _, err := validateDevice(device)
- if err != nil {
- return nil, errors.Wrapf(err, "device string not valid %q", device)
- }
-
- src := ""
- dst := ""
- permissions := "rwm"
- arr := strings.Split(device, ":")
- switch len(arr) {
- case 3:
- permissions = arr[2]
- fallthrough
- case 2:
- if validDeviceMode(arr[1]) {
- permissions = arr[1]
- } else {
- dst = arr[1]
- }
- fallthrough
- case 1:
- src = arr[0]
- default:
- return nil, fmt.Errorf("invalid device specification: %s", device)
- }
-
- if dst == "" {
- dst = src
- }
-
- deviceMapping := &pb.Device{
- ContainerPath: dst,
- HostPath: src,
- Permissions: permissions,
- }
- return deviceMapping, nil
-}
-
-// validDeviceMode checks if the mode for device is valid or not.
-// Valid mode is a composition of r (read), w (write), and m (mknod).
-func validDeviceMode(mode string) bool {
- var legalDeviceMode = map[rune]bool{
- 'r': true,
- 'w': true,
- 'm': true,
- }
- if mode == "" {
- return false
- }
- for _, c := range mode {
- if !legalDeviceMode[c] {
- return false
- }
- legalDeviceMode[c] = false
- }
- return true
-}
-
-// validateDevice validates a path for devices
-// It will make sure 'val' is in the form:
-// [host-dir:]container-path[:mode]
-// It also validates the device mode.
-func validateDevice(val string) (string, error) {
- return validatePath(val, validDeviceMode)
-}
-
-func validatePath(val string, validator func(string) bool) (string, error) {
- var containerPath string
- var mode string
-
- if strings.Count(val, ":") > 2 {
- return val, fmt.Errorf("bad format for path: %s", val)
- }
-
- split := strings.SplitN(val, ":", 3)
- if split[0] == "" {
- return val, fmt.Errorf("bad format for path: %s", val)
- }
- switch len(split) {
- case 1:
- containerPath = split[0]
- val = path.Clean(containerPath)
- case 2:
- if isValid := validator(split[1]); isValid {
- containerPath = split[0]
- mode = split[1]
- val = fmt.Sprintf("%s:%s", path.Clean(containerPath), mode)
- } else {
- containerPath = split[1]
- val = fmt.Sprintf("%s:%s", split[0], path.Clean(containerPath))
- }
- case 3:
- containerPath = split[1]
- mode = split[2]
- if isValid := validator(split[2]); !isValid {
- return val, fmt.Errorf("bad mode specified: %s", mode)
- }
- val = fmt.Sprintf("%s:%s:%s", split[0], containerPath, mode)
- }
-
- if !path.IsAbs(containerPath) {
- return val, fmt.Errorf("%s is not an absolute path", containerPath)
- }
- return val, nil
-}
-
-// throttleDevice is a structure that holds device:rate_per_second pair
-type throttleDevice struct {
- path string
- rate uint64
-}
-
-func (t *throttleDevice) String() string {
- return fmt.Sprintf("%s:%d", t.path, t.rate)
-}
-
-// validateBpsDevice validates that the specified string has a valid device-rate format
-// for device-read-bps and device-write-bps flags
-func validateBpsDevice(val string) (*throttleDevice, error) {
- split := strings.SplitN(val, ":", 2)
- if len(split) != 2 {
- return nil, fmt.Errorf("bad format: %s", val)
- }
- if !strings.HasPrefix(split[0], "/dev/") {
- return nil, fmt.Errorf("bad format for device path: %s", val)
- }
- rate, err := units.RAMInBytes(split[1])
- if err != nil {
- return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>[<unit>]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val)
- }
- if rate < 0 {
- return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>[<unit>]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val)
- }
-
- return &throttleDevice{
- path: split[0],
- rate: uint64(rate),
- }, nil
-}
-
-// validateIOpsDevice validates that the specified string has a valid device-rate format
-// for device-write-iops and device-read-iops flags
-func validateIOpsDevice(val string) (*throttleDevice, error) { //nolint
- split := strings.SplitN(val, ":", 2)
- if len(split) != 2 {
- return nil, fmt.Errorf("bad format: %s", val)
- }
- if !strings.HasPrefix(split[0], "/dev/") {
- return nil, fmt.Errorf("bad format for device path: %s", val)
- }
- rate, err := strconv.ParseUint(split[1], 10, 64)
- if err != nil {
- return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
- }
- if rate < 0 {
- return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
- }
-
- return &throttleDevice{
- path: split[0],
- rate: uint64(rate),
- }, nil
-}
-
-// validateDNSSearch validates domain for resolvconf search configuration.
-// A zero length domain is represented by a dot (.).
-// for dns-search flag
-func validateDNSSearch(val string) (string, error) { //nolint
- if val = strings.Trim(val, " "); val == "." {
- return val, nil
- }
- return validateDomain(val)
-}
-
-func validateDomain(val string) (string, error) {
- if alphaRegexp.FindString(val) == "" {
- return "", fmt.Errorf("%s is not a valid domain", val)
- }
- ns := domainRegexp.FindSubmatch([]byte(val))
- if len(ns) > 0 && len(ns[1]) < 255 {
- return string(ns[1]), nil
- }
- return "", fmt.Errorf("%s is not a valid domain", val)
-}
-
-// validateEnv validates an environment variable and returns it.
-// If no value is specified, it returns the current value using os.Getenv.
-// for env flag
-func validateEnv(val string) (string, error) { //nolint
- arr := strings.Split(val, "=")
- if len(arr) > 1 {
- return val, nil
- }
- if !doesEnvExist(val) {
- return val, nil
- }
- return fmt.Sprintf("%s=%s", val, os.Getenv(val)), nil
-}
-
-func doesEnvExist(name string) bool {
- for _, entry := range os.Environ() {
- parts := strings.SplitN(entry, "=", 2)
- if parts[0] == name {
- return true
- }
- }
- return false
-}
-
-// reads a file of line terminated key=value pairs, and overrides any keys
-// present in the file with additional pairs specified in the override parameter
-// for env-file and labels-file flags
-func readKVStrings(env map[string]string, files []string, override []string) error {
- for _, ef := range files {
- if err := parseEnvFile(env, ef); err != nil {
- return err
- }
- }
- for _, line := range override {
- if err := parseEnv(env, line); err != nil {
- return err
- }
- }
- return nil
-}
-
-func parseEnv(env map[string]string, line string) error {
- data := strings.SplitN(line, "=", 2)
-
- // trim the front of a variable, but nothing else
- name := strings.TrimLeft(data[0], whiteSpaces)
- if strings.ContainsAny(name, whiteSpaces) {
- return errors.Errorf("name %q has white spaces, poorly formatted name", name)
- }
-
- if len(data) > 1 {
- env[name] = data[1]
- } else {
- // if only a pass-through variable is given, clean it up.
- val, exists := os.LookupEnv(name)
- if !exists {
- return errors.Errorf("environment variable %q does not exist", name)
- }
- env[name] = val
- }
- return nil
-}
-
-// parseEnvFile reads a file with environment variables enumerated by lines
-func parseEnvFile(env map[string]string, filename string) error {
- fh, err := os.Open(filename)
- if err != nil {
- return err
- }
- defer fh.Close()
-
- scanner := bufio.NewScanner(fh)
- for scanner.Scan() {
- // trim the line from all leading whitespace first
- line := strings.TrimLeft(scanner.Text(), whiteSpaces)
- // line is not empty, and not starting with '#'
- if len(line) > 0 && !strings.HasPrefix(line, "#") {
- if err := parseEnv(env, line); err != nil {
- return err
- }
- }
- }
- return scanner.Err()
-}
-
-// NsIpc represents the container ipc stack.
-// for ipc flag
-type NsIpc string
-
-// IsPrivate indicates whether the container uses its private ipc stack.
-func (n NsIpc) IsPrivate() bool {
- return !(n.IsHost() || n.IsContainer())
-}
-
-// IsHost indicates whether the container uses the host's ipc stack.
-func (n NsIpc) IsHost() bool {
- return n == "host"
-}
-
-// IsContainer indicates whether the container uses a container's ipc stack.
-func (n NsIpc) IsContainer() bool {
- parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
-}
-
-// Valid indicates whether the ipc stack is valid.
-func (n NsIpc) Valid() bool {
- parts := strings.Split(string(n), ":")
- switch mode := parts[0]; mode {
- case "", "host":
- case "container":
- if len(parts) != 2 || parts[1] == "" {
- return false
- }
- default:
- return false
- }
- return true
-}
-
-// Container returns the name of the container ipc stack is going to be used.
-func (n NsIpc) Container() string {
- parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
- return parts[1]
- }
- return ""
-}
-
-// validateLabel validates that the specified string is a valid label, and returns it.
-// Labels are in the form on key=value.
-// for label flag
-func validateLabel(val string) (string, error) { //nolint
- if strings.Count(val, "=") < 1 {
- return "", fmt.Errorf("bad attribute format: %s", val)
- }
- return val, nil
-}
-
-// validateMACAddress validates a MAC address.
-// for mac-address flag
-func validateMACAddress(val string) (string, error) { //nolint
- _, err := net.ParseMAC(strings.TrimSpace(val))
- if err != nil {
- return "", err
- }
- return val, nil
-}
-
-// parseLoggingOpts validates the logDriver and logDriverOpts
-// for log-opt and log-driver flags
-func parseLoggingOpts(logDriver string, logDriverOpt []string) (map[string]string, error) { //nolint
- logOptsMap := convertKVStringsToMap(logDriverOpt)
- if logDriver == "none" && len(logDriverOpt) > 0 {
- return map[string]string{}, errors.Errorf("invalid logging opts for driver %s", logDriver)
- }
- return logOptsMap, nil
-}
-
-// NsPid represents the pid namespace of the container.
-//for pid flag
-type NsPid string
-
-// IsPrivate indicates whether the container uses its own new pid namespace.
-func (n NsPid) IsPrivate() bool {
- return !(n.IsHost() || n.IsContainer())
-}
-
-// IsHost indicates whether the container uses the host's pid namespace.
-func (n NsPid) IsHost() bool {
- return n == "host"
-}
-
-// IsContainer indicates whether the container uses a container's pid namespace.
-func (n NsPid) IsContainer() bool {
- parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
-}
-
-// Valid indicates whether the pid namespace is valid.
-func (n NsPid) Valid() bool {
- parts := strings.Split(string(n), ":")
- switch mode := parts[0]; mode {
- case "", "host":
- case "container":
- if len(parts) != 2 || parts[1] == "" {
- return false
- }
- default:
- return false
- }
- return true
-}
-
-// Container returns the name of the container whose pid namespace is going to be used.
-func (n NsPid) Container() string {
- parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
- return parts[1]
- }
- return ""
-}
-
-// parsePortSpecs receives port specs in the format of ip:public:private/proto and parses
-// these in to the internal types
-// for publish, publish-all, and expose flags
-func parsePortSpecs(ports []string) ([]*pb.PortMapping, error) { //nolint
- var portMappings []*pb.PortMapping
- for _, rawPort := range ports {
- portMapping, err := parsePortSpec(rawPort)
- if err != nil {
- return nil, err
- }
-
- portMappings = append(portMappings, portMapping...)
- }
- return portMappings, nil
-}
-
-func validateProto(proto string) bool {
- for _, availableProto := range []string{"tcp", "udp"} {
- if availableProto == proto {
- return true
- }
- }
- return false
-}
-
-// parsePortSpec parses a port specification string into a slice of PortMappings
-func parsePortSpec(rawPort string) ([]*pb.PortMapping, error) {
- var proto string
- rawIP, hostPort, containerPort := splitParts(rawPort)
- proto, containerPort = splitProtoPort(containerPort)
-
- // Strip [] from IPV6 addresses
- ip, _, err := net.SplitHostPort(rawIP + ":")
- if err != nil {
- return nil, fmt.Errorf("Invalid ip address %v: %s", rawIP, err)
- }
- if ip != "" && net.ParseIP(ip) == nil {
- return nil, fmt.Errorf("Invalid ip address: %s", ip)
- }
- if containerPort == "" {
- return nil, fmt.Errorf("No port specified: %s<empty>", rawPort)
- }
-
- startPort, endPort, err := parsePortRange(containerPort)
- if err != nil {
- return nil, fmt.Errorf("Invalid containerPort: %s", containerPort)
- }
-
- var startHostPort, endHostPort uint64 = 0, 0
- if len(hostPort) > 0 {
- startHostPort, endHostPort, err = parsePortRange(hostPort)
- if err != nil {
- return nil, fmt.Errorf("Invalid hostPort: %s", hostPort)
- }
- }
-
- if hostPort != "" && (endPort-startPort) != (endHostPort-startHostPort) {
- // Allow host port range iff containerPort is not a range.
- // In this case, use the host port range as the dynamic
- // host port range to allocate into.
- if endPort != startPort {
- return nil, fmt.Errorf("Invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort)
- }
- }
-
- if !validateProto(strings.ToLower(proto)) {
- return nil, fmt.Errorf("invalid proto: %s", proto)
- }
-
- protocol := pb.Protocol_TCP
- if strings.ToLower(proto) == "udp" {
- protocol = pb.Protocol_UDP
- }
-
- var ports []*pb.PortMapping
- for i := uint64(0); i <= (endPort - startPort); i++ {
- containerPort = strconv.FormatUint(startPort+i, 10)
- if len(hostPort) > 0 {
- hostPort = strconv.FormatUint(startHostPort+i, 10)
- }
- // Set hostPort to a range only if there is a single container port
- // and a dynamic host port.
- if startPort == endPort && startHostPort != endHostPort {
- hostPort = fmt.Sprintf("%s-%s", hostPort, strconv.FormatUint(endHostPort, 10))
- }
-
- ctrPort, err := strconv.ParseInt(containerPort, 10, 32)
- if err != nil {
- return nil, err
- }
- hPort, err := strconv.ParseInt(hostPort, 10, 32)
- if err != nil {
- return nil, err
- }
-
- port := &pb.PortMapping{
- Protocol: protocol,
- ContainerPort: int32(ctrPort),
- HostPort: int32(hPort),
- HostIp: ip,
- }
-
- ports = append(ports, port)
- }
- return ports, nil
-}
-
-// parsePortRange parses and validates the specified string as a port-range (8000-9000)
-func parsePortRange(ports string) (uint64, uint64, error) {
- if ports == "" {
- return 0, 0, fmt.Errorf("empty string specified for ports")
- }
- if !strings.Contains(ports, "-") {
- start, err := strconv.ParseUint(ports, 10, 16)
- end := start
- return start, end, err
- }
-
- parts := strings.Split(ports, "-")
- start, err := strconv.ParseUint(parts[0], 10, 16)
- if err != nil {
- return 0, 0, err
- }
- end, err := strconv.ParseUint(parts[1], 10, 16)
- if err != nil {
- return 0, 0, err
- }
- if end < start {
- return 0, 0, fmt.Errorf("Invalid range specified for the Port: %s", ports)
- }
- return start, end, nil
-}
-
-// splitParts separates the different parts of rawPort
-func splitParts(rawport string) (string, string, string) {
- parts := strings.Split(rawport, ":")
- n := len(parts)
- containerport := parts[n-1]
-
- switch n {
- case 1:
- return "", "", containerport
- case 2:
- return "", parts[0], containerport
- case 3:
- return parts[0], parts[1], containerport
- default:
- return strings.Join(parts[:n-2], ":"), parts[n-2], containerport
- }
-}
-
-// splitProtoPort splits a port in the format of port/proto
-func splitProtoPort(rawPort string) (string, string) {
- parts := strings.Split(rawPort, "/")
- l := len(parts)
- if len(rawPort) == 0 || l == 0 || len(parts[0]) == 0 {
- return "", ""
- }
- if l == 1 {
- return "tcp", rawPort
- }
- if len(parts[1]) == 0 {
- return "tcp", parts[0]
- }
- return parts[1], parts[0]
-}
-
-// takes a local seccomp file and reads its file contents
-// for security-opt flag
-func parseSecurityOpts(securityOpts []string) ([]string, error) { //nolint
- for key, opt := range securityOpts {
- con := strings.SplitN(opt, "=", 2)
- if len(con) == 1 && con[0] != "no-new-privileges" {
- if strings.Index(opt, ":") != -1 {
- con = strings.SplitN(opt, ":", 2)
- } else {
- return securityOpts, fmt.Errorf("Invalid --security-opt: %q", opt)
- }
- }
- if con[0] == "seccomp" && con[1] != "unconfined" {
- f, err := ioutil.ReadFile(con[1])
- if err != nil {
- return securityOpts, fmt.Errorf("opening seccomp profile (%s) failed: %v", con[1], err)
- }
- b := bytes.NewBuffer(nil)
- if err := json.Compact(b, f); err != nil {
- return securityOpts, fmt.Errorf("compacting json for seccomp profile (%s) failed: %v", con[1], err)
- }
- securityOpts[key] = fmt.Sprintf("seccomp=%s", b.Bytes())
- }
- }
-
- return securityOpts, nil
-}
-
-// parses storage options per container into a map
-// for storage-opt flag
-func parseStorageOpts(storageOpts []string) (map[string]string, error) { //nolint
- m := make(map[string]string)
- for _, option := range storageOpts {
- if strings.Contains(option, "=") {
- opt := strings.SplitN(option, "=", 2)
- m[opt[0]] = opt[1]
- } else {
- return nil, errors.Errorf("invalid storage option %q", option)
- }
- }
- return m, nil
-}
-
-// parseUser parses the the uid and gid in the format <name|uid>[:<group|gid>]
-// for user flag
-// FIXME: Issue from https://github.com/projectatomic/buildah/issues/66
-func parseUser(rootdir, userspec string) (specs.User, error) { //nolint
- var gid64 uint64
- var gerr error = user.UnknownGroupError("error looking up group")
-
- spec := strings.SplitN(userspec, ":", 2)
- userspec = spec[0]
- groupspec := ""
- if userspec == "" {
- return specs.User{}, nil
- }
- if len(spec) > 1 {
- groupspec = spec[1]
- }
-
- uid64, uerr := strconv.ParseUint(userspec, 10, 32)
- if uerr == nil && groupspec == "" {
- // We parsed the user name as a number, and there's no group
- // component, so we need to look up the user's primary GID.
- var name string
- name, gid64, gerr = lookupGroupForUIDInContainer(rootdir, uid64)
- if gerr == nil {
- userspec = name
- } else {
- if userrec, err := user.LookupId(userspec); err == nil {
- gid64, gerr = strconv.ParseUint(userrec.Gid, 10, 32)
- userspec = userrec.Name
- }
- }
- }
- if uerr != nil {
- uid64, gid64, uerr = lookupUserInContainer(rootdir, userspec)
- gerr = uerr
- }
- if uerr != nil {
- if userrec, err := user.Lookup(userspec); err == nil {
- uid64, uerr = strconv.ParseUint(userrec.Uid, 10, 32)
- gid64, gerr = strconv.ParseUint(userrec.Gid, 10, 32)
- }
- }
-
- if groupspec != "" {
- gid64, gerr = strconv.ParseUint(groupspec, 10, 32)
- if gerr != nil {
- gid64, gerr = lookupGroupInContainer(rootdir, groupspec)
- }
- if gerr != nil {
- if group, err := user.LookupGroup(groupspec); err == nil {
- gid64, gerr = strconv.ParseUint(group.Gid, 10, 32)
- }
- }
- }
-
- if uerr == nil && gerr == nil {
- u := specs.User{
- UID: uint32(uid64),
- GID: uint32(gid64),
- Username: userspec,
- }
- return u, nil
- }
-
- err := errors.Wrapf(uerr, "error determining run uid")
- if uerr == nil {
- err = errors.Wrapf(gerr, "error determining run gid")
- }
- return specs.User{}, err
-}
-
-// convertKVStringsToMap converts ["key=value"] to {"key":"value"}
-func convertKVStringsToMap(values []string) map[string]string {
- result := make(map[string]string, len(values))
- for _, value := range values {
- kv := strings.SplitN(value, "=", 2)
- if len(kv) == 1 {
- result[kv[0]] = ""
- } else {
- result[kv[0]] = kv[1]
- }
- }
-
- return result
-}
-
-// NsUser represents userns mode in the container.
-// for userns flag
-type NsUser string
-
-// IsHost indicates whether the container uses the host's userns.
-func (n NsUser) IsHost() bool {
- return n == "host"
-}
-
-// IsPrivate indicates whether the container uses the a private userns.
-func (n NsUser) IsPrivate() bool {
- return !(n.IsHost())
-}
-
-// Valid indicates whether the userns is valid.
-func (n NsUser) Valid() bool {
- parts := strings.Split(string(n), ":")
- switch mode := parts[0]; mode {
- case "", "host":
- default:
- return false
- }
- return true
-}
-
-// NsUts represents the UTS namespace of the container.
-// for uts flag
-type NsUts string
-
-// IsPrivate indicates whether the container uses its private UTS namespace.
-func (n NsUts) IsPrivate() bool {
- return !(n.IsHost())
-}
-
-// IsHost indicates whether the container uses the host's UTS namespace.
-func (n NsUts) IsHost() bool {
- return n == "host"
-}
-
-// Valid indicates whether the UTS namespace is valid.
-func (n NsUts) Valid() bool {
- parts := strings.Split(string(n), ":")
- switch mode := parts[0]; mode {
- case "", "host":
- default:
- return false
- }
- return true
-}
-
-// Takes a stringslice and converts to a uint32slice
-func stringSlicetoUint32Slice(inputSlice []string) ([]uint32, error) {
- var outputSlice []uint32
- for _, v := range inputSlice {
- u, err := strconv.ParseUint(v, 10, 32)
- if err != nil {
- return outputSlice, err
- }
- outputSlice = append(outputSlice, uint32(u))
- }
- return outputSlice, nil
-}
diff --git a/cmd/kpod/pause.go b/cmd/kpod/pause.go
deleted file mode 100644
index dede89443..000000000
--- a/cmd/kpod/pause.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
-
- "github.com/pkg/errors"
- "github.com/urfave/cli"
-)
-
-var (
- pauseDescription = `
- kpod pause
-
- Pauses one or more running containers. The container name or ID can be used.
-`
- pauseCommand = cli.Command{
- Name: "pause",
- Usage: "Pauses all the processes in one or more containers",
- Description: pauseDescription,
- Action: pauseCmd,
- ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
- }
-)
-
-func pauseCmd(c *cli.Context) error {
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- args := c.Args()
- if len(args) < 1 {
- return errors.Errorf("you must provide at least one container name or id")
- }
-
- var lastError error
- for _, arg := range args {
- ctr, err := runtime.LookupContainer(arg)
- if err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "error looking up container %q", arg)
- continue
- }
- if err = ctr.Pause(); err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "failed to pause container %v", ctr.ID())
- } else {
- fmt.Println(ctr.ID())
- }
- }
- return lastError
-}
diff --git a/cmd/kpod/ps.go b/cmd/kpod/ps.go
deleted file mode 100644
index 6b807671e..000000000
--- a/cmd/kpod/ps.go
+++ /dev/null
@@ -1,606 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "reflect"
- "regexp"
- "strconv"
- "strings"
- "time"
-
- "github.com/docker/go-units"
- specs "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/cmd/kpod/formats"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
- "k8s.io/apimachinery/pkg/fields"
-)
-
-type psOptions struct {
- all bool
- filter string
- format string
- last int
- latest bool
- noTrunc bool
- quiet bool
- size bool
- label string
- namespace bool
-}
-
-type psTemplateParams struct {
- ID string
- Image string
- Command string
- CreatedAt string
- RunningFor string
- Status string
- Ports string
- Size string
- Names string
- Labels string
- Mounts string
- PID int
- Cgroup string
- IPC string
- MNT string
- NET string
- PIDNS string
- User string
- UTS string
-}
-
-// psJSONParams is only used when the JSON format is specified,
-// and is better for data processing from JSON.
-// psJSONParams will be populated by data from libpod.Container,
-// the members of the struct are the sama data types as their sources.
-type psJSONParams struct {
- ID string `json:"id"`
- Image string `json:"image"`
- ImageID string `json:"image_id"`
- Command string `json:"command"`
- CreatedAt time.Time `json:"createdAt"`
- RunningFor time.Duration `json:"runningFor"`
- Status string `json:"status"`
- Ports map[string]struct{} `json:"ports"`
- Size uint `json:"size"`
- Names string `json:"names"`
- Labels fields.Set `json:"labels"`
- Mounts []specs.Mount `json:"mounts"`
- ContainerRunning bool `json:"ctrRunning"`
- Namespaces *namespace `json:"namespace,omitempty"`
-}
-
-type namespace struct {
- PID string `json:"pid,omitempty"`
- Cgroup string `json:"cgroup,omitempty"`
- IPC string `json:"ipc,omitempty"`
- MNT string `json:"mnt,omitempty"`
- NET string `json:"net,omitempty"`
- PIDNS string `json:"pidns,omitempty"`
- User string `json:"user,omitempty"`
- UTS string `json:"uts,omitempty"`
-}
-
-var (
- psFlags = []cli.Flag{
- cli.BoolFlag{
- Name: "all, a",
- Usage: "Show all the containers, default is only running containers",
- },
- cli.StringFlag{
- Name: "filter, f",
- Usage: "Filter output based on conditions given",
- },
- cli.StringFlag{
- Name: "format",
- Usage: "Pretty-print containers to JSON or using a Go template",
- },
- cli.IntFlag{
- Name: "last, n",
- Usage: "Print the n last created containers (all states)",
- Value: -1,
- },
- cli.BoolFlag{
- Name: "latest, l",
- Usage: "Show the latest container created (all states)",
- },
- cli.BoolFlag{
- Name: "no-trunc",
- Usage: "Display the extended information",
- },
- cli.BoolFlag{
- Name: "quiet, q",
- Usage: "Print the numeric IDs of the containers only",
- },
- cli.BoolFlag{
- Name: "size, s",
- Usage: "Display the total file sizes",
- },
- cli.BoolFlag{
- Name: "namespace, ns",
- Usage: "Display namespace information",
- },
- }
- psDescription = "Prints out information about the containers"
- psCommand = cli.Command{
- Name: "ps",
- Usage: "List containers",
- Description: psDescription,
- Flags: psFlags,
- Action: psCmd,
- ArgsUsage: "",
- UseShortOptionHandling: true,
- }
-)
-
-func psCmd(c *cli.Context) error {
- if err := validateFlags(c, psFlags); err != nil {
- return err
- }
-
- if err := checkFlagsPassed(c); err != nil {
- return errors.Wrapf(err, "error with flags passed")
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "error creating libpod runtime")
- }
-
- defer runtime.Shutdown(false)
-
- if len(c.Args()) > 0 {
- return errors.Errorf("too many arguments, ps takes no arguments")
- }
-
- format := genPsFormat(c.String("format"), c.Bool("quiet"), c.Bool("size"), c.Bool("namespace"))
-
- opts := psOptions{
- all: c.Bool("all"),
- filter: c.String("filter"),
- format: format,
- last: c.Int("last"),
- latest: c.Bool("latest"),
- noTrunc: c.Bool("no-trunc"),
- quiet: c.Bool("quiet"),
- size: c.Bool("size"),
- namespace: c.Bool("namespace"),
- }
-
- var filterFuncs []libpod.ContainerFilter
- // When we are dealing with latest or last=n, we need to
- // get all containers.
- if !opts.all && !opts.latest && opts.last < 1 {
- // only get running containers
- filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
- state, _ := c.State()
- return state == libpod.ContainerStateRunning
- })
- }
-
- if opts.filter != "" {
- filters := strings.Split(opts.filter, ",")
- for _, f := range filters {
- filterSplit := strings.Split(f, "=")
- if len(filterSplit) < 2 {
- return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
- }
- generatedFunc, err := generateContainerFilterFuncs(filterSplit[0], filterSplit[1], runtime)
- if err != nil {
- return errors.Wrapf(err, "invalid filter")
- }
- filterFuncs = append(filterFuncs, generatedFunc)
- }
- }
-
- containers, err := runtime.GetContainers(filterFuncs...)
- var outputContainers []*libpod.Container
- if opts.latest && len(containers) > 0 {
- outputContainers = append(outputContainers, containers[0])
- } else if opts.last > 0 && opts.last <= len(containers) {
- outputContainers = append(outputContainers, containers[:opts.last]...)
- } else {
- outputContainers = containers
- }
-
- return generatePsOutput(outputContainers, opts)
-}
-
-// checkFlagsPassed checks if mutually exclusive flags are passed together
-func checkFlagsPassed(c *cli.Context) error {
- // latest, and last are mutually exclusive.
- if c.Int("last") >= 0 && c.Bool("latest") {
- return errors.Errorf("last and latest are mutually exclusive")
- }
- // quiet, size, namespace, and format with Go template are mutually exclusive
- flags := 0
- if c.Bool("quiet") {
- flags++
- }
- if c.Bool("size") {
- flags++
- }
- if c.Bool("namespace") {
- flags++
- }
- if c.IsSet("format") && c.String("format") != formats.JSONString {
- flags++
- }
- if flags > 1 {
- return errors.Errorf("quiet, size, namespace, and format with Go template are mutually exclusive")
- }
- return nil
-}
-
-func generateContainerFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) (func(container *libpod.Container) bool, error) {
- switch filter {
- case "id":
- return func(c *libpod.Container) bool {
- return c.ID() == filterValue
- }, nil
- case "label":
- return func(c *libpod.Container) bool {
- for _, label := range c.Labels() {
- if label == filterValue {
- return true
- }
- }
- return false
- }, nil
- case "name":
- return func(c *libpod.Container) bool {
- return c.Name() == filterValue
- }, nil
- case "exited":
- exitCode, err := strconv.ParseInt(filterValue, 10, 32)
- if err != nil {
- return nil, errors.Wrapf(err, "exited code out of range %q", filterValue)
- }
- return func(c *libpod.Container) bool {
- ec, err := c.ExitCode()
- if ec == int32(exitCode) && err == nil {
- return true
- }
- return false
- }, nil
- case "status":
- if !libpod.StringInSlice(filterValue, []string{"created", "restarting", "running", "paused", "exited", "unknown"}) {
- return nil, errors.Errorf("%s is not a valid status", filterValue)
- }
- return func(c *libpod.Container) bool {
- status, err := c.State()
- if err != nil {
- return false
- }
- return status.String() == filterValue
- }, nil
- case "ancestor":
- // This needs to refine to match docker
- // - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩) - containers created from an image or a descendant.
- return func(c *libpod.Container) bool {
- containerConfig := c.Config()
- if containerConfig.RootfsImageID == filterValue || containerConfig.RootfsImageName == filterValue {
- return true
- }
- return false
- }, nil
- case "before":
- ctr, err := runtime.LookupContainer(filterValue)
- if err != nil {
- return nil, errors.Errorf("unable to find container by name or id of %s", filterValue)
- }
- containerConfig := ctr.Config()
- createTime := containerConfig.CreatedTime
- return func(c *libpod.Container) bool {
- cc := c.Config()
- return createTime.After(cc.CreatedTime)
- }, nil
- case "since":
- ctr, err := runtime.LookupContainer(filterValue)
- if err != nil {
- return nil, errors.Errorf("unable to find container by name or id of %s", filterValue)
- }
- containerConfig := ctr.Config()
- createTime := containerConfig.CreatedTime
- return func(c *libpod.Container) bool {
- cc := c.Config()
- return createTime.Before(cc.CreatedTime)
- }, nil
- case "volume":
- //- volume=(<volume-name>|<mount-point-destination>)
- return func(c *libpod.Container) bool {
- containerConfig := c.Config()
- //TODO We need to still lookup against volumes too
- return containerConfig.MountLabel == filterValue
- }, nil
- }
- return nil, errors.Errorf("%s is an invalid filter", filter)
-}
-
-// generate the template based on conditions given
-func genPsFormat(format string, quiet, size, namespace bool) string {
- if format != "" {
- // "\t" from the command line is not being recognized as a tab
- // replacing the string "\t" to a tab character if the user passes in "\t"
- return strings.Replace(format, `\t`, "\t", -1)
- }
- if quiet {
- return formats.IDString
- }
- if namespace {
- return "table {{.ID}}\t{{.Names}}\t{{.PID}}\t{{.Cgroup}}\t{{.IPC}}\t{{.MNT}}\t{{.NET}}\t{{.PIDNS}}\t{{.User}}\t{{.UTS}}\t"
- }
- format = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.CreatedAt}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}\t"
- if size {
- format += "{{.Size}}\t"
- }
- return format
-}
-
-func psToGeneric(templParams []psTemplateParams, JSONParams []psJSONParams) (genericParams []interface{}) {
- if len(templParams) > 0 {
- for _, v := range templParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
- }
- for _, v := range JSONParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
-}
-
-// generate the accurate header based on template given
-func (p *psTemplateParams) headerMap() map[string]string {
- v := reflect.Indirect(reflect.ValueOf(p))
- values := make(map[string]string)
-
- for i := 0; i < v.NumField(); i++ {
- key := v.Type().Field(i).Name
- value := key
- if value == "ID" {
- value = "Container" + value
- }
- values[key] = strings.ToUpper(splitCamelCase(value))
- }
- return values
-}
-
-// getTemplateOutput returns the modified container information
-func getTemplateOutput(containers []*libpod.Container, opts psOptions) ([]psTemplateParams, error) {
- var psOutput []psTemplateParams
- var status string
- for _, ctr := range containers {
- ctrID := ctr.ID()
- conConfig := ctr.Config()
- conState, err := ctr.State()
- if err != nil {
- return psOutput, errors.Wrapf(err, "unable to obtain container state")
- }
- exitCode, err := ctr.ExitCode()
- if err != nil {
- return psOutput, errors.Wrapf(err, "unable to obtain container exit code")
- }
- pid, err := ctr.PID()
- if err != nil {
- return psOutput, errors.Wrapf(err, "unable to obtain container pid")
- }
- runningFor := units.HumanDuration(time.Since(conConfig.CreatedTime))
- createdAt := runningFor + " ago"
- imageName := conConfig.RootfsImageName
-
- // TODO We currently dont have the ability to get many of
- // these data items. Uncomment as progress is made
-
- //command := getStrFromSquareBrackets(ctr.ImageCreatedBy)
- command := strings.Join(ctr.Spec().Process.Args, " ")
- //mounts := getMounts(ctr.Mounts, opts.noTrunc)
- //ports := getPorts(ctr.Config.ExposedPorts)
- //size := units.HumanSize(float64(ctr.SizeRootFs))
- labels := formatLabels(ctr.Labels())
- ns := getNamespaces(pid)
-
- switch conState {
- case libpod.ContainerStateStopped:
- status = fmt.Sprintf("Exited (%d) %s ago", exitCode, runningFor)
- case libpod.ContainerStateRunning:
- status = "Up " + runningFor + " ago"
- case libpod.ContainerStatePaused:
- status = "Paused"
- case libpod.ContainerStateCreated:
- status = "Created"
- default:
- status = "Dead"
- }
-
- if !opts.noTrunc {
- ctrID = ctr.ID()[:idTruncLength]
- imageName = conConfig.RootfsImageName
- }
-
- // TODO We currently dont have the ability to get many of
- // these data items. Uncomment as progress is made
-
- params := psTemplateParams{
- ID: ctrID,
- Image: imageName,
- Command: command,
- CreatedAt: createdAt,
- RunningFor: runningFor,
- Status: status,
- //Ports: ports,
- //Size: size,
- Names: ctr.Name(),
- Labels: labels,
- //Mounts: mounts,
- PID: pid,
- Cgroup: ns.Cgroup,
- IPC: ns.IPC,
- MNT: ns.MNT,
- NET: ns.NET,
- PIDNS: ns.PID,
- User: ns.User,
- UTS: ns.UTS,
- }
- psOutput = append(psOutput, params)
- }
- return psOutput, nil
-}
-
-func getNamespaces(pid int) *namespace {
- ctrPID := strconv.Itoa(pid)
- cgroup, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "cgroup"))
- ipc, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "ipc"))
- mnt, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "mnt"))
- net, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "net"))
- pidns, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "pid"))
- user, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "user"))
- uts, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "uts"))
-
- return &namespace{
- PID: ctrPID,
- Cgroup: cgroup,
- IPC: ipc,
- MNT: mnt,
- NET: net,
- PIDNS: pidns,
- User: user,
- UTS: uts,
- }
-}
-
-func getNamespaceInfo(path string) (string, error) {
- val, err := os.Readlink(path)
- if err != nil {
- return "", errors.Wrapf(err, "error getting info from %q", path)
- }
- return getStrFromSquareBrackets(val), nil
-}
-
-// getJSONOutput returns the container info in its raw form
-func getJSONOutput(containers []*libpod.Container, nSpace bool) ([]psJSONParams, error) {
- var psOutput []psJSONParams
- var ns *namespace
- for _, ctr := range containers {
- pid, err := ctr.PID()
- if err != nil {
- return psOutput, errors.Wrapf(err, "unable to obtain container pid")
- }
- if nSpace {
- ns = getNamespaces(pid)
- }
- cc := ctr.Config()
- conState, err := ctr.State()
- if err != nil {
- return psOutput, errors.Wrapf(err, "unable to obtain container state for JSON output")
- }
- params := psJSONParams{
- // TODO When we have ability to obtain the commented out data, we need
- // TODO to add it
- ID: ctr.ID(),
- Image: cc.RootfsImageName,
- ImageID: cc.RootfsImageID,
- //Command: getStrFromSquareBrackets(ctr.ImageCreatedBy),
- Command: strings.Join(ctr.Spec().Process.Args, " "),
- CreatedAt: cc.CreatedTime,
- RunningFor: time.Since(cc.CreatedTime),
- Status: conState.String(),
- //Ports: cc.Spec.Linux.Resources.Network.
- //Size: ctr.SizeRootFs,
- Names: cc.Name,
- Labels: cc.Labels,
- Mounts: cc.Spec.Mounts,
- ContainerRunning: conState == libpod.ContainerStateRunning,
- Namespaces: ns,
- }
- psOutput = append(psOutput, params)
- }
- return psOutput, nil
-}
-
-func generatePsOutput(containers []*libpod.Container, opts psOptions) error {
- if len(containers) == 0 && opts.format != formats.JSONString {
- return nil
- }
- var out formats.Writer
-
- switch opts.format {
- case formats.JSONString:
- psOutput, err := getJSONOutput(containers, opts.namespace)
- if err != nil {
- return errors.Wrapf(err, "unable to create JSON for output")
- }
- out = formats.JSONStructArray{Output: psToGeneric([]psTemplateParams{}, psOutput)}
- default:
- psOutput, err := getTemplateOutput(containers, opts)
- if err != nil {
- return errors.Wrapf(err, "unable to create output")
- }
- out = formats.StdoutTemplateArray{Output: psToGeneric(psOutput, []psJSONParams{}), Template: opts.format, Fields: psOutput[0].headerMap()}
- }
-
- return formats.Writer(out).Out()
-}
-
-// getStrFromSquareBrackets gets the string inside [] from a string
-func getStrFromSquareBrackets(cmd string) string {
- reg, err := regexp.Compile(".*\\[|\\].*")
- if err != nil {
- return ""
- }
- arr := strings.Split(reg.ReplaceAllLiteralString(cmd, ""), ",")
- return strings.Join(arr, ",")
-}
-
-// getLabels converts the labels to a string of the form "key=value, key2=value2"
-func formatLabels(labels map[string]string) string {
- var arr []string
- if len(labels) > 0 {
- for key, val := range labels {
- temp := key + "=" + val
- arr = append(arr, temp)
- }
- return strings.Join(arr, ",")
- }
- return ""
-}
-
-/*
-// getMounts converts the volumes mounted to a string of the form "mount1, mount2"
-// it truncates it if noTrunc is false
-func getMounts(mounts []specs.Mount, noTrunc bool) string {
- var arr []string
- if len(mounts) == 0 {
- return ""
- }
- for _, mount := range mounts {
- if noTrunc {
- arr = append(arr, mount.Source)
- continue
- }
- tempArr := strings.SplitAfter(mount.Source, "/")
- if len(tempArr) >= 3 {
- arr = append(arr, strings.Join(tempArr[:3], ""))
- } else {
- arr = append(arr, mount.Source)
- }
- }
- return strings.Join(arr, ",")
-}
-// getPorts converts the ports used to a string of the from "port1, port2"
-func getPorts(ports map[string]struct{}) string {
- var arr []string
- if len(ports) == 0 {
- return ""
- }
- for key := range ports {
- arr = append(arr, key)
- }
- return strings.Join(arr, ",")
-}
-*/
diff --git a/cmd/kpod/pull.go b/cmd/kpod/pull.go
deleted file mode 100644
index 5726b20f1..000000000
--- a/cmd/kpod/pull.go
+++ /dev/null
@@ -1,120 +0,0 @@
-package main
-
-import (
- "fmt"
- "io"
- "os"
-
- "golang.org/x/crypto/ssh/terminal"
-
- "github.com/containers/image/types"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/projectatomic/libpod/libpod/common"
- "github.com/sirupsen/logrus"
- "github.com/urfave/cli"
-)
-
-var (
- pullFlags = []cli.Flag{
- cli.StringFlag{
- Name: "authfile",
- Usage: "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
- },
- cli.StringFlag{
- Name: "cert-dir",
- Usage: "`pathname` of a directory containing TLS certificates and keys",
- },
- cli.StringFlag{
- Name: "creds",
- Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry",
- },
- cli.BoolFlag{
- Name: "quiet, q",
- Usage: "Suppress output information when pulling images",
- },
- cli.StringFlag{
- Name: "signature-policy",
- Usage: "`pathname` of signature policy file (not usually used)",
- },
- cli.BoolTFlag{
- Name: "tls-verify",
- Usage: "require HTTPS and verify certificates when contacting registries (default: true)",
- },
- }
-
- pullDescription = "Pulls an image from a registry and stores it locally.\n" +
- "An image can be pulled using its tag or digest. If a tag is not\n" +
- "specified, the image with the 'latest' tag (if it exists) is pulled."
- pullCommand = cli.Command{
- Name: "pull",
- Usage: "pull an image from a registry",
- Description: pullDescription,
- Flags: pullFlags,
- Action: pullCmd,
- ArgsUsage: "",
- }
-)
-
-// pullCmd gets the data from the command line and calls pullImage
-// to copy an image from a registry to a local machine
-func pullCmd(c *cli.Context) error {
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- args := c.Args()
- if len(args) == 0 {
- logrus.Errorf("an image name must be specified")
- return nil
- }
- if len(args) > 1 {
- logrus.Errorf("too many arguments. Requires exactly 1")
- return nil
- }
- if err := validateFlags(c, pullFlags); err != nil {
- return err
- }
- image := args[0]
-
- var registryCreds *types.DockerAuthConfig
- if c.String("creds") != "" {
- creds, err := common.ParseRegistryCreds(c.String("creds"))
- if err != nil {
- if err == common.ErrNoPassword {
- fmt.Print("Password: ")
- password, err := terminal.ReadPassword(0)
- if err != nil {
- return errors.Wrapf(err, "could not read password from terminal")
- }
- creds.Password = string(password)
- } else {
- return err
- }
- }
- registryCreds = creds
- }
-
- var writer io.Writer
- if !c.Bool("quiet") {
- writer = os.Stdout
- }
-
- options := libpod.CopyOptions{
- SignaturePolicyPath: c.String("signature-policy"),
- AuthFile: c.String("authfile"),
- DockerRegistryOptions: common.DockerRegistryOptions{
- DockerRegistryCreds: registryCreds,
- DockerCertPath: c.String("cert-dir"),
- DockerInsecureSkipTLSVerify: !c.BoolT("tls-verify"),
- },
- Writer: writer,
- }
-
- if _, err := runtime.PullImage(image, options); err != nil {
- return errors.Wrapf(err, "error pulling image %q", image)
- }
- return nil
-}
diff --git a/cmd/kpod/push.go b/cmd/kpod/push.go
deleted file mode 100644
index d3d42e0ee..000000000
--- a/cmd/kpod/push.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package main
-
-import (
- "fmt"
- "io"
- "os"
- "strings"
-
- "github.com/containers/image/manifest"
- "github.com/containers/image/types"
- "github.com/containers/storage/pkg/archive"
- imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/projectatomic/libpod/libpod/common"
- "github.com/urfave/cli"
- "golang.org/x/crypto/ssh/terminal"
-)
-
-var (
- pushFlags = []cli.Flag{
- cli.StringFlag{
- Name: "signature-policy",
- Usage: "`pathname` of signature policy file (not usually used)",
- Hidden: true,
- },
- cli.StringFlag{
- Name: "creds",
- Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry",
- },
- cli.StringFlag{
- Name: "cert-dir",
- Usage: "`pathname` of a directory containing TLS certificates and keys",
- },
- cli.BoolFlag{
- Name: "compress",
- Usage: "compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)",
- },
- cli.StringFlag{
- Name: "format, f",
- Usage: "manifest type (oci, v2s1, or v2s2) to use when pushing an image using the 'dir:' transport (default is manifest type of source)",
- },
- cli.BoolTFlag{
- Name: "tls-verify",
- Usage: "require HTTPS and verify certificates when contacting registries (default: true)",
- },
- cli.BoolFlag{
- Name: "remove-signatures",
- Usage: "discard any pre-existing signatures in the image",
- },
- cli.StringFlag{
- Name: "sign-by",
- Usage: "add a signature at the destination using the specified key",
- },
- cli.BoolFlag{
- Name: "quiet, q",
- Usage: "don't output progress information when pushing images",
- },
- cli.StringFlag{
- Name: "authfile",
- Usage: "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
- },
- }
- pushDescription = fmt.Sprintf(`
- Pushes an image to a specified location.
- The Image "DESTINATION" uses a "transport":"details" format.
- See kpod-push(1) section "DESTINATION" for the expected format`)
-
- pushCommand = cli.Command{
- Name: "push",
- Usage: "push an image to a specified destination",
- Description: pushDescription,
- Flags: pushFlags,
- Action: pushCmd,
- ArgsUsage: "IMAGE DESTINATION",
- }
-)
-
-func pushCmd(c *cli.Context) error {
- var registryCreds *types.DockerAuthConfig
-
- args := c.Args()
- if len(args) < 2 {
- return errors.New("kpod push requires exactly 2 arguments")
- }
- if err := validateFlags(c, pushFlags); err != nil {
- return err
- }
- srcName := args[0]
- destName := args[1]
-
- // --compress and --format can only be used for the "dir" transport
- splitArg := strings.SplitN(destName, ":", 2)
- if c.IsSet("compress") || c.IsSet("format") {
- if splitArg[0] != libpod.DirTransport {
- return errors.Errorf("--compress and --format can be set only when pushing to a directory using the 'dir' transport")
- }
- }
-
- registryCredsString := c.String("creds")
- certPath := c.String("cert-dir")
- skipVerify := !c.BoolT("tls-verify")
- removeSignatures := c.Bool("remove-signatures")
- signBy := c.String("sign-by")
-
- if registryCredsString != "" {
- creds, err := common.ParseRegistryCreds(registryCredsString)
- if err != nil {
- if err == common.ErrNoPassword {
- fmt.Print("Password: ")
- password, err := terminal.ReadPassword(0)
- if err != nil {
- return errors.Wrapf(err, "could not read password from terminal")
- }
- creds.Password = string(password)
- } else {
- return err
- }
- }
- registryCreds = creds
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not create runtime")
- }
- defer runtime.Shutdown(false)
-
- var writer io.Writer
- if !c.Bool("quiet") {
- writer = os.Stdout
- }
-
- var manifestType string
- if c.IsSet("format") {
- switch c.String("format") {
- case "oci":
- manifestType = imgspecv1.MediaTypeImageManifest
- case "v2s1":
- manifestType = manifest.DockerV2Schema1SignedMediaType
- case "v2s2", "docker":
- manifestType = manifest.DockerV2Schema2MediaType
- default:
- return fmt.Errorf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", c.String("format"))
- }
- }
-
- options := libpod.CopyOptions{
- Compression: archive.Uncompressed,
- SignaturePolicyPath: c.String("signature-policy"),
- DockerRegistryOptions: common.DockerRegistryOptions{
- DockerRegistryCreds: registryCreds,
- DockerCertPath: certPath,
- DockerInsecureSkipTLSVerify: skipVerify,
- },
- SigningOptions: common.SigningOptions{
- RemoveSignatures: removeSignatures,
- SignBy: signBy,
- },
- AuthFile: c.String("authfile"),
- Writer: writer,
- ManifestMIMEType: manifestType,
- ForceCompress: c.Bool("compress"),
- }
-
- return runtime.PushImage(srcName, destName, options)
-}
diff --git a/cmd/kpod/rm.go b/cmd/kpod/rm.go
deleted file mode 100644
index 2f767457f..000000000
--- a/cmd/kpod/rm.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
-
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
-)
-
-var (
- rmFlags = []cli.Flag{
- cli.BoolFlag{
- Name: "force, f",
- Usage: "Force removal of a running container. The default is false",
- },
- cli.BoolFlag{
- Name: "all, a",
- Usage: "Remove all containers",
- },
- }
- rmDescription = "Remove one or more containers"
- rmCommand = cli.Command{
- Name: "rm",
- Usage: fmt.Sprintf(`kpod rm will remove one or more containers from the host. The container name or ID can be used.
- This does not remove images. Running containers will not be removed without the -f option.`),
- Description: rmDescription,
- Flags: rmFlags,
- Action: rmCmd,
- ArgsUsage: "",
- UseShortOptionHandling: true,
- }
-)
-
-// saveCmd saves the image to either docker-archive or oci
-func rmCmd(c *cli.Context) error {
- if err := validateFlags(c, rmFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- args := c.Args()
- if len(args) == 0 && !c.Bool("all") {
- return errors.Errorf("specify one or more containers to remove")
- }
-
- var delContainers []*libpod.Container
- var lastError error
- if c.Bool("all") {
- delContainers, err = runtime.GetContainers()
- if err != nil {
- return errors.Wrapf(err, "unable to get container list")
- }
- } else {
- for _, i := range args {
- container, err := runtime.LookupContainer(i)
- if err != nil {
- fmt.Fprintln(os.Stderr, err)
- lastError = errors.Wrapf(err, "unable to find container %s", i)
- continue
- }
- delContainers = append(delContainers, container)
- }
- }
- for _, container := range delContainers {
- if err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "failed to find container %s", container.ID())
- continue
- }
- err = runtime.RemoveContainer(container, c.Bool("force"))
- if err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "failed to delete container %v", container.ID())
- } else {
- fmt.Println(container.ID())
- }
- }
- return lastError
-}
diff --git a/cmd/kpod/rmi.go b/cmd/kpod/rmi.go
deleted file mode 100644
index 1b4cb7390..000000000
--- a/cmd/kpod/rmi.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package main
-
-import (
- "fmt"
-
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
-)
-
-var (
- rmiDescription = "removes one or more locally stored images."
- rmiFlags = []cli.Flag{
- cli.BoolFlag{
- Name: "all, a",
- Usage: "remove all images",
- },
- cli.BoolFlag{
- Name: "force, f",
- Usage: "force removal of the image",
- },
- }
- rmiCommand = cli.Command{
- Name: "rmi",
- Usage: "removes one or more images from local storage",
- Description: rmiDescription,
- Action: rmiCmd,
- ArgsUsage: "IMAGE-NAME-OR-ID [...]",
- Flags: rmiFlags,
- UseShortOptionHandling: true,
- }
-)
-
-func rmiCmd(c *cli.Context) error {
- if err := validateFlags(c, rmiFlags); err != nil {
- return err
- }
- removeAll := c.Bool("all")
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- args := c.Args()
- if len(args) == 0 && !removeAll {
- return errors.Errorf("image name or ID must be specified")
- }
- if len(args) > 0 && removeAll {
- return errors.Errorf("when using the --all switch, you may not pass any images names or IDs")
- }
- imagesToDelete := args[:]
- if removeAll {
- localImages, err := runtime.GetImages(&libpod.ImageFilterParams{})
- if err != nil {
- return errors.Wrapf(err, "unable to query local images")
- }
- for _, image := range localImages {
- imagesToDelete = append(imagesToDelete, image.ID)
- }
- }
-
- for _, arg := range imagesToDelete {
- image, err := runtime.GetImage(arg)
- if err != nil {
- return errors.Wrapf(err, "could not get image %q", arg)
- }
- id, err := runtime.RemoveImage(image, c.Bool("force"))
- if err != nil {
- return errors.Wrapf(err, "error removing image %q", id)
- }
- fmt.Printf("%s\n", id)
- }
- return nil
-}
diff --git a/cmd/kpod/run.go b/cmd/kpod/run.go
deleted file mode 100644
index 6142983ad..000000000
--- a/cmd/kpod/run.go
+++ /dev/null
@@ -1,146 +0,0 @@
-package main
-
-import (
- "fmt"
- "sync"
-
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/sirupsen/logrus"
- "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...]]",
- SkipArgReorder: true,
- UseShortOptionHandling: true,
-}
-
-func runCmd(c *cli.Context) error {
- var imageName string
- if err := validateFlags(c, createFlags); err != nil {
- return err
- }
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "error creating libpod runtime")
- }
- defer runtime.Shutdown(false)
-
- createConfig, err := parseCreateOpts(c, runtime)
- if err != nil {
- return err
- }
-
- createImage := runtime.NewImage(createConfig.Image)
- createImage.LocalName, _ = createImage.GetLocalImageName()
- if createImage.LocalName == "" {
- // The image wasnt found by the user input'd name or its fqname
- // Pull the image
- fmt.Printf("Trying to pull %s...", createImage.PullName)
- createImage.Pull()
- }
-
- runtimeSpec, err := createConfigToOCISpec(createConfig)
- if err != nil {
- return err
- }
- logrus.Debug("spec is ", runtimeSpec)
-
- if createImage.LocalName != "" {
- nameIsID, err := runtime.IsImageID(createImage.LocalName)
- if err != nil {
- return err
- }
- if nameIsID {
- // If the input from the user is an ID, then we need to get the image
- // name for cstorage
- createImage.LocalName, err = createImage.GetNameByID()
- if err != nil {
- return err
- }
- }
- imageName = createImage.LocalName
- } else {
- imageName, err = createImage.GetFQName()
- }
- if err != nil {
- return err
- }
- logrus.Debug("imageName is ", imageName)
-
- imageID, err := createImage.GetImageID()
- if err != nil {
- return err
- }
- logrus.Debug("imageID is ", imageID)
-
- options, err := createConfig.GetContainerCreateOptions()
- if err != nil {
- return errors.Wrapf(err, "unable to parse new container options")
- }
-
- // Gather up the options for NewContainer which consist of With... funcs
- options = append(options, libpod.WithRootFSFromImage(imageID, imageName, false))
- options = append(options, libpod.WithSELinuxLabels(createConfig.ProcessLabel, createConfig.MountLabel))
- options = append(options, libpod.WithShmDir(createConfig.ShmDir))
- ctr, err := runtime.NewContainer(runtimeSpec, options...)
- if err != nil {
- return err
- }
-
- logrus.Debug("new container created ", ctr.ID())
- if err := ctr.Init(); err != nil {
- return err
- }
- logrus.Debugf("container storage created for %q", ctr.ID())
-
- if c.String("cidfile") != "" {
- libpod.WriteFile(ctr.ID(), c.String("cidfile"))
- return nil
- }
-
- // Create a bool channel to track that the console socket attach
- // is successful.
- attached := make(chan bool)
- // Create a waitgroup so we can sync and wait for all goroutines
- // to finish before exiting main
- var wg sync.WaitGroup
-
- if !createConfig.Detach {
- // We increment the wg counter because we need to do the attach
- wg.Add(1)
- // Attach to the running container
- go func() {
- logrus.Debugf("trying to attach to the container %s", ctr.ID())
- defer wg.Done()
- if err := ctr.Attach(false, c.String("detach-keys"), attached); err != nil {
- logrus.Errorf("unable to attach to container %s: %q", ctr.ID(), err)
- }
- }()
- if !<-attached {
- return errors.Errorf("unable to attach to container %s", ctr.ID())
- }
- }
- // Start the container
- if err := ctr.Start(); err != nil {
- return errors.Wrapf(err, "unable to start container %q", ctr.ID())
- }
- if createConfig.Detach {
- fmt.Printf("%s\n", ctr.ID())
- return nil
- }
- wg.Wait()
-
- if createConfig.Rm {
- return runtime.RemoveContainer(ctr, true)
- }
- return ctr.CleanupStorage()
-}
diff --git a/cmd/kpod/save.go b/cmd/kpod/save.go
deleted file mode 100644
index 85a8c7930..000000000
--- a/cmd/kpod/save.go
+++ /dev/null
@@ -1,129 +0,0 @@
-package main
-
-import (
- "io"
- "os"
- "strings"
-
- "github.com/containers/image/manifest"
- imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/sirupsen/logrus"
- "github.com/urfave/cli"
-)
-
-const (
- ociManifestDir = "oci-dir"
- v2s2ManifestDir = "docker-dir"
-)
-
-var (
- saveFlags = []cli.Flag{
- cli.BoolFlag{
- Name: "compress",
- Usage: "compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)",
- },
- cli.StringFlag{
- Name: "output, o",
- Usage: "Write to a file, default is STDOUT",
- Value: "/dev/stdout",
- },
- cli.BoolFlag{
- Name: "quiet, q",
- Usage: "Suppress the output",
- },
- cli.StringFlag{
- Name: "format",
- Usage: "Save image to oci-archive, oci-dir (directory with oci manifest type), docker-dir (directory with v2s2 manifest type)",
- },
- }
- saveDescription = `
- Save an image to docker-archive or oci-archive on the local machine.
- Default is docker-archive`
-
- saveCommand = cli.Command{
- Name: "save",
- Usage: "Save image to an archive",
- Description: saveDescription,
- Flags: saveFlags,
- Action: saveCmd,
- ArgsUsage: "",
- }
-)
-
-// saveCmd saves the image to either docker-archive or oci
-func saveCmd(c *cli.Context) error {
- args := c.Args()
- if len(args) == 0 {
- return errors.Errorf("need at least 1 argument")
- }
- if err := validateFlags(c, saveFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not create runtime")
- }
- defer runtime.Shutdown(false)
-
- if c.IsSet("compress") && (c.String("format") != ociManifestDir && c.String("format") != v2s2ManifestDir && c.String("format") == "") {
- return errors.Errorf("--compress can only be set when --format is either 'oci-dir' or 'docker-dir'")
- }
-
- var writer io.Writer
- if !c.Bool("quiet") {
- writer = os.Stdout
- }
-
- output := c.String("output")
- if output == "/dev/stdout" {
- fi := os.Stdout
- if logrus.IsTerminal(fi) {
- return errors.Errorf("refusing to save to terminal. Use -o flag or redirect")
- }
- }
-
- var dst, manifestType string
- switch c.String("format") {
- case libpod.OCIArchive:
- dst = libpod.OCIArchive + ":" + output
- case "oci-dir":
- dst = libpod.DirTransport + ":" + output
- manifestType = imgspecv1.MediaTypeImageManifest
- case "docker-dir":
- dst = libpod.DirTransport + ":" + output
- manifestType = manifest.DockerV2Schema2MediaType
- case libpod.DockerArchive:
- fallthrough
- case "":
- dst = libpod.DockerArchive + ":" + output
- default:
- return errors.Errorf("unknown format option %q", c.String("format"))
- }
-
- saveOpts := libpod.CopyOptions{
- SignaturePolicyPath: "",
- Writer: writer,
- ManifestMIMEType: manifestType,
- ForceCompress: c.Bool("compress"),
- }
-
- // only one image is supported for now
- // future pull requests will fix this
- for _, image := range args {
- dest := dst
- // need dest to be in the format transport:path:reference for the following transports
- if strings.Contains(dst, libpod.OCIArchive) || strings.Contains(dst, libpod.DockerArchive) {
- dest = dst + ":" + image
- }
- if err := runtime.PushImage(image, dest, saveOpts); err != nil {
- if err2 := os.Remove(output); err2 != nil {
- logrus.Errorf("error deleting %q: %v", output, err)
- }
- return errors.Wrapf(err, "unable to save %q", image)
- }
- }
- return nil
-}
diff --git a/cmd/kpod/spec.go b/cmd/kpod/spec.go
deleted file mode 100644
index adfdf7347..000000000
--- a/cmd/kpod/spec.go
+++ /dev/null
@@ -1,561 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "fmt"
- "io/ioutil"
- "strings"
-
- "github.com/cri-o/ocicni/pkg/ocicni"
- "github.com/docker/docker/daemon/caps"
- "github.com/docker/docker/pkg/mount"
- "github.com/docker/go-units"
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/opencontainers/runtime-tools/generate"
- "github.com/opencontainers/selinux/go-selinux/label"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- ann "github.com/projectatomic/libpod/pkg/annotations"
- "github.com/sirupsen/logrus"
- "golang.org/x/sys/unix"
-)
-
-func blockAccessToKernelFilesystems(config *createConfig, g *generate.Generator) {
- if !config.Privileged {
- for _, mp := range []string{
- "/proc/kcore",
- "/proc/latency_stats",
- "/proc/timer_list",
- "/proc/timer_stats",
- "/proc/sched_debug",
- "/proc/scsi",
- "/sys/firmware",
- } {
- g.AddLinuxMaskedPaths(mp)
- }
-
- for _, rp := range []string{
- "/proc/asound",
- "/proc/bus",
- "/proc/fs",
- "/proc/irq",
- "/proc/sys",
- "/proc/sysrq-trigger",
- } {
- g.AddLinuxReadonlyPaths(rp)
- }
- }
-}
-
-func addPidNS(config *createConfig, g *generate.Generator) error {
- pidMode := config.PidMode
- if pidMode.IsHost() {
- return g.RemoveLinuxNamespace(libpod.PIDNamespace)
- }
- if pidMode.IsContainer() {
- ctr, err := config.Runtime.LookupContainer(pidMode.Container())
- if err != nil {
- return errors.Wrapf(err, "container %q not found", pidMode.Container())
- }
- pid, err := ctr.PID()
- if err != nil {
- return errors.Wrapf(err, "Failed to get pid of container %q", pidMode.Container())
- }
- pidNsPath := fmt.Sprintf("/proc/%d/ns/pid", pid)
- if err := g.AddOrReplaceLinuxNamespace(libpod.PIDNamespace, pidNsPath); err != nil {
- return err
- }
- }
- return nil
-}
-
-func addNetNS(config *createConfig, g *generate.Generator) error {
- netMode := config.NetMode
- if netMode.IsHost() {
- return g.RemoveLinuxNamespace(libpod.NetNamespace)
- }
- if netMode.IsNone() {
- return libpod.ErrNotImplemented
- }
- if netMode.IsBridge() {
- return libpod.ErrNotImplemented
- }
- if netMode.IsContainer() {
- ctr, err := config.Runtime.LookupContainer(netMode.ConnectedContainer())
- if err != nil {
- return errors.Wrapf(err, "container %q not found", netMode.ConnectedContainer())
- }
- pid, err := ctr.PID()
- if err != nil {
- return errors.Wrapf(err, "Failed to get pid of container %q", netMode.ConnectedContainer())
- }
- nsPath := fmt.Sprintf("/proc/%d/ns/net", pid)
- if err := g.AddOrReplaceLinuxNamespace(libpod.NetNamespace, nsPath); err != nil {
- return err
- }
- }
- return nil
-}
-
-func addUTSNS(config *createConfig, g *generate.Generator) error {
- utsMode := config.UtsMode
- if utsMode.IsHost() {
- return g.RemoveLinuxNamespace(libpod.UTSNamespace)
- }
- return nil
-}
-
-func addIpcNS(config *createConfig, g *generate.Generator) error {
- ipcMode := config.IpcMode
- if ipcMode.IsHost() {
- return g.RemoveLinuxNamespace(libpod.IPCNamespace)
- }
- if ipcMode.IsContainer() {
- ctr, err := config.Runtime.LookupContainer(ipcMode.Container())
- if err != nil {
- return errors.Wrapf(err, "container %q not found", ipcMode.Container())
- }
- pid, err := ctr.PID()
- if err != nil {
- return errors.Wrapf(err, "Failed to get pid of container %q", ipcMode.Container())
- }
- nsPath := fmt.Sprintf("/proc/%d/ns/ipc", pid)
- if err := g.AddOrReplaceLinuxNamespace(libpod.IPCNamespace, nsPath); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func addRlimits(config *createConfig, g *generate.Generator) error {
- var (
- ul *units.Ulimit
- err error
- )
-
- for _, u := range config.Resources.Ulimit {
- if ul, err = units.ParseUlimit(u); err != nil {
- return errors.Wrapf(err, "ulimit option %q requires name=SOFT:HARD, failed to be parsed", u)
- }
-
- g.AddProcessRlimits("RLIMIT_"+strings.ToUpper(ul.Name), uint64(ul.Soft), uint64(ul.Hard))
- }
- return nil
-}
-
-func setupCapabilities(config *createConfig, configSpec *spec.Spec) error {
- var err error
- var caplist []string
- if config.Privileged {
- caplist = caps.GetAllCapabilities()
- } else {
- caplist, err = caps.TweakCapabilities(configSpec.Process.Capabilities.Bounding, config.CapAdd, config.CapDrop)
- if err != nil {
- return err
- }
- }
-
- configSpec.Process.Capabilities.Bounding = caplist
- configSpec.Process.Capabilities.Permitted = caplist
- configSpec.Process.Capabilities.Inheritable = caplist
- configSpec.Process.Capabilities.Effective = caplist
- return nil
-}
-
-// Parses information needed to create a container into an OCI runtime spec
-func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
- g := generate.New()
- g.AddCgroupsMount("ro")
- g.SetProcessCwd(config.WorkDir)
- g.SetProcessArgs(config.Command)
- g.SetProcessTerminal(config.Tty)
- // User and Group must go together
- g.SetProcessUID(config.User)
- g.SetProcessGID(config.Group)
- for _, gid := range config.GroupAdd {
- g.AddProcessAdditionalGid(gid)
- }
- for key, val := range config.GetAnnotations() {
- g.AddAnnotation(key, val)
- }
- g.SetRootReadonly(config.ReadOnlyRootfs)
- g.SetHostname(config.Hostname)
- if config.Hostname != "" {
- g.AddProcessEnv("HOSTNAME", config.Hostname)
- }
-
- for _, sysctl := range config.Sysctl {
- s := strings.SplitN(sysctl, "=", 2)
- g.AddLinuxSysctl(s[0], s[1])
- }
-
- // RESOURCES - MEMORY
- if config.Resources.Memory != 0 {
- g.SetLinuxResourcesMemoryLimit(config.Resources.Memory)
- }
- if config.Resources.MemoryReservation != 0 {
- g.SetLinuxResourcesMemoryReservation(config.Resources.MemoryReservation)
- }
- if config.Resources.MemorySwap != 0 {
- g.SetLinuxResourcesMemorySwap(config.Resources.MemorySwap)
- }
- if config.Resources.KernelMemory != 0 {
- g.SetLinuxResourcesMemoryKernel(config.Resources.KernelMemory)
- }
- if config.Resources.MemorySwappiness != -1 {
- g.SetLinuxResourcesMemorySwappiness(uint64(config.Resources.MemorySwappiness))
- }
- g.SetLinuxResourcesMemoryDisableOOMKiller(config.Resources.DisableOomKiller)
- g.SetProcessOOMScoreAdj(config.Resources.OomScoreAdj)
-
- // RESOURCES - CPU
-
- if config.Resources.CPUShares != 0 {
- g.SetLinuxResourcesCPUShares(config.Resources.CPUShares)
- }
- if config.Resources.CPUQuota != 0 {
- g.SetLinuxResourcesCPUQuota(config.Resources.CPUQuota)
- }
- if config.Resources.CPUPeriod != 0 {
- g.SetLinuxResourcesCPUPeriod(config.Resources.CPUPeriod)
- }
- if config.Resources.CPURtRuntime != 0 {
- g.SetLinuxResourcesCPURealtimeRuntime(config.Resources.CPURtRuntime)
- }
- if config.Resources.CPURtPeriod != 0 {
- g.SetLinuxResourcesCPURealtimePeriod(config.Resources.CPURtPeriod)
- }
- if config.Resources.CPUs != "" {
- g.SetLinuxResourcesCPUCpus(config.Resources.CPUs)
- }
- if config.Resources.CPUsetMems != "" {
- g.SetLinuxResourcesCPUMems(config.Resources.CPUsetMems)
- }
-
- // SECURITY OPTS
- g.SetProcessNoNewPrivileges(config.NoNewPrivileges)
- g.SetProcessApparmorProfile(config.ApparmorProfile)
- g.SetProcessSelinuxLabel(config.ProcessLabel)
- g.SetLinuxMountLabel(config.MountLabel)
- blockAccessToKernelFilesystems(config, &g)
-
- // RESOURCES - PIDS
- if config.Resources.PidsLimit != 0 {
- g.SetLinuxResourcesPidsLimit(config.Resources.PidsLimit)
- }
-
- for _, i := range config.Tmpfs {
- options := []string{"rw", "noexec", "nosuid", "nodev", "size=65536k"}
- spliti := strings.SplitN(i, ":", 2)
- if len(spliti) > 1 {
- if _, _, err := mount.ParseTmpfsOptions(spliti[1]); err != nil {
- return nil, err
- }
- options = strings.Split(spliti[1], ",")
- }
- // Default options if nothing passed
- g.AddTmpfsMount(spliti[0], options)
- }
-
- for name, val := range config.Env {
- g.AddProcessEnv(name, val)
- }
-
- if err := addRlimits(config, &g); err != nil {
- return nil, err
- }
-
- if err := addPidNS(config, &g); err != nil {
- return nil, err
- }
-
- if err := addNetNS(config, &g); err != nil {
- return nil, err
- }
-
- if err := addUTSNS(config, &g); err != nil {
- return nil, err
- }
-
- if err := addIpcNS(config, &g); err != nil {
- return nil, err
- }
- configSpec := g.Spec()
-
- if config.SeccompProfilePath != "" && config.SeccompProfilePath != "unconfined" {
- seccompProfile, err := ioutil.ReadFile(config.SeccompProfilePath)
- if err != nil {
- return nil, errors.Wrapf(err, "opening seccomp profile (%s) failed", config.SeccompProfilePath)
- }
- var seccompConfig spec.LinuxSeccomp
- if err := json.Unmarshal(seccompProfile, &seccompConfig); err != nil {
- return nil, errors.Wrapf(err, "decoding seccomp profile (%s) failed", config.SeccompProfilePath)
- }
- configSpec.Linux.Seccomp = &seccompConfig
- }
-
- // BIND MOUNTS
- mounts, err := config.GetVolumeMounts()
- if err != nil {
- return nil, errors.Wrapf(err, "error getting volume mounts")
- }
- configSpec.Mounts = append(configSpec.Mounts, mounts...)
- for _, mount := range configSpec.Mounts {
- for _, opt := range mount.Options {
- switch opt {
- case "private", "rprivate", "slave", "rslave", "shared", "rshared":
- if err := g.SetLinuxRootPropagation(opt); err != nil {
- return nil, errors.Wrapf(err, "error setting root propagation for %q", mount.Destination)
- }
- }
- }
- }
-
- // HANDLE CAPABILITIES
- if err := setupCapabilities(config, configSpec); err != nil {
- return nil, err
- }
-
- /*
- Hooks: &configSpec.Hooks{},
- //Annotations
- Resources: &configSpec.LinuxResources{
- Devices: config.GetDefaultDevices(),
- BlockIO: &blkio,
- //HugepageLimits:
- Network: &configSpec.LinuxNetwork{
- // ClassID *uint32
- // Priorites []LinuxInterfacePriority
- },
- },
- //CgroupsPath:
- //Namespaces: []LinuxNamespace
- //Devices
- // DefaultAction:
- // Architectures
- // Syscalls:
- },
- // RootfsPropagation
- // MaskedPaths
- // ReadonlyPaths:
- // IntelRdt
- },
- }
- */
- return configSpec, nil
-}
-
-func (c *createConfig) CreateBlockIO() (spec.LinuxBlockIO, error) {
- bio := spec.LinuxBlockIO{}
- bio.Weight = &c.Resources.BlkioWeight
- if len(c.Resources.BlkioWeightDevice) > 0 {
- var lwds []spec.LinuxWeightDevice
- for _, i := range c.Resources.BlkioWeightDevice {
- wd, err := validateweightDevice(i)
- if err != nil {
- return bio, errors.Wrapf(err, "invalid values for blkio-weight-device")
- }
- wdStat := getStatFromPath(wd.path)
- lwd := spec.LinuxWeightDevice{
- Weight: &wd.weight,
- }
- lwd.Major = int64(unix.Major(wdStat.Rdev))
- lwd.Minor = int64(unix.Minor(wdStat.Rdev))
- lwds = append(lwds, lwd)
- }
- }
- if len(c.Resources.DeviceReadBps) > 0 {
- readBps, err := makeThrottleArray(c.Resources.DeviceReadBps)
- if err != nil {
- return bio, err
- }
- bio.ThrottleReadBpsDevice = readBps
- }
- if len(c.Resources.DeviceWriteBps) > 0 {
- writeBpds, err := makeThrottleArray(c.Resources.DeviceWriteBps)
- if err != nil {
- return bio, err
- }
- bio.ThrottleWriteBpsDevice = writeBpds
- }
- if len(c.Resources.DeviceReadIOps) > 0 {
- readIOps, err := makeThrottleArray(c.Resources.DeviceReadIOps)
- if err != nil {
- return bio, err
- }
- bio.ThrottleReadIOPSDevice = readIOps
- }
- if len(c.Resources.DeviceWriteIOps) > 0 {
- writeIOps, err := makeThrottleArray(c.Resources.DeviceWriteIOps)
- if err != nil {
- return bio, err
- }
- bio.ThrottleWriteIOPSDevice = writeIOps
- }
-
- return bio, nil
-}
-
-// GetAnnotations returns the all the annotations for the container
-func (c *createConfig) GetAnnotations() map[string]string {
- a := getDefaultAnnotations()
- // TODO - Which annotations do we want added by default
- // TODO - This should be added to the DB long term
- if c.Tty {
- a["io.kubernetes.cri-o.TTY"] = "true"
- }
- return a
-}
-
-func getDefaultAnnotations() map[string]string {
- var annotations map[string]string
- annotations = make(map[string]string)
- annotations[ann.Annotations] = ""
- annotations[ann.ContainerID] = ""
- annotations[ann.ContainerName] = ""
- annotations[ann.ContainerType] = ""
- annotations[ann.Created] = ""
- annotations[ann.HostName] = ""
- annotations[ann.IP] = ""
- annotations[ann.Image] = ""
- annotations[ann.ImageName] = ""
- annotations[ann.ImageRef] = ""
- annotations[ann.KubeName] = ""
- annotations[ann.Labels] = ""
- annotations[ann.LogPath] = ""
- annotations[ann.Metadata] = ""
- annotations[ann.Name] = ""
- annotations[ann.PrivilegedRuntime] = ""
- annotations[ann.ResolvPath] = ""
- annotations[ann.HostnamePath] = ""
- annotations[ann.SandboxID] = ""
- annotations[ann.SandboxName] = ""
- annotations[ann.ShmPath] = ""
- annotations[ann.MountPoint] = ""
- annotations[ann.TrustedSandbox] = ""
- annotations[ann.TTY] = "false"
- annotations[ann.Stdin] = ""
- annotations[ann.StdinOnce] = ""
- annotations[ann.Volumes] = ""
-
- return annotations
-}
-
-//GetVolumeMounts takes user provided input for bind mounts and creates Mount structs
-func (c *createConfig) GetVolumeMounts() ([]spec.Mount, error) {
- var m []spec.Mount
- var options []string
- for _, i := range c.Volumes {
- // We need to handle SELinux options better here, specifically :Z
- spliti := strings.Split(i, ":")
- if len(spliti) > 2 {
- options = strings.Split(spliti[2], ",")
- }
- options = append(options, "rbind")
- var foundrw, foundro, foundz, foundZ bool
- var rootProp string
- for _, opt := range options {
- switch opt {
- case "rw":
- foundrw = true
- case "ro":
- foundro = true
- case "z":
- foundz = true
- case "Z":
- foundZ = true
- case "private", "rprivate", "slave", "rslave", "shared", "rshared":
- rootProp = opt
- }
- }
- if !foundrw && !foundro {
- options = append(options, "rw")
- }
- if foundz {
- if err := label.Relabel(spliti[0], c.MountLabel, true); err != nil {
- return nil, errors.Wrapf(err, "relabel failed %q", spliti[0])
- }
- }
- if foundZ {
- if err := label.Relabel(spliti[0], c.MountLabel, false); err != nil {
- return nil, errors.Wrapf(err, "relabel failed %q", spliti[0])
- }
- }
- if rootProp == "" {
- options = append(options, "rprivate")
- }
-
- m = append(m, spec.Mount{
- Destination: spliti[1],
- Type: string(TypeBind),
- Source: spliti[0],
- Options: options,
- })
- }
- return m, nil
-}
-
-//GetTmpfsMounts takes user provided input for Tmpfs mounts and creates Mount structs
-func (c *createConfig) GetTmpfsMounts() []spec.Mount {
- var m []spec.Mount
- for _, i := range c.Tmpfs {
- // Default options if nothing passed
- options := []string{"rw", "noexec", "nosuid", "nodev", "size=65536k"}
- spliti := strings.Split(i, ":")
- destPath := spliti[0]
- if len(spliti) > 1 {
- options = strings.Split(spliti[1], ",")
- }
- m = append(m, spec.Mount{
- Destination: destPath,
- Type: string(TypeTmpfs),
- Options: options,
- Source: string(TypeTmpfs),
- })
- }
- return m
-}
-
-func (c *createConfig) GetContainerCreateOptions() ([]libpod.CtrCreateOption, error) {
- var options []libpod.CtrCreateOption
-
- // Uncomment after talking to mheon about unimplemented funcs
- // options = append(options, libpod.WithLabels(c.labels))
-
- if c.Interactive {
- options = append(options, libpod.WithStdin())
- }
- if c.Name != "" {
- logrus.Debugf("appending name %s", c.Name)
- options = append(options, libpod.WithName(c.Name))
- }
- // TODO parse ports into libpod format and include
- // TODO should not happen if --net=host
- options = append(options, libpod.WithNetNS([]ocicni.PortMapping{}))
-
- return options, nil
-}
-
-func getStatFromPath(path string) unix.Stat_t {
- s := unix.Stat_t{}
- _ = unix.Stat(path, &s)
- return s
-}
-
-func makeThrottleArray(throttleInput []string) ([]spec.LinuxThrottleDevice, error) {
- var ltds []spec.LinuxThrottleDevice
- for _, i := range throttleInput {
- t, err := validateBpsDevice(i)
- if err != nil {
- return []spec.LinuxThrottleDevice{}, err
- }
- ltd := spec.LinuxThrottleDevice{}
- ltd.Rate = t.rate
- ltdStat := getStatFromPath(t.path)
- ltd.Major = int64(unix.Major(ltdStat.Rdev))
- ltd.Minor = int64(unix.Major(ltdStat.Rdev))
- ltds = append(ltds, ltd)
- }
- return ltds, nil
-}
diff --git a/cmd/kpod/spec_test.go b/cmd/kpod/spec_test.go
deleted file mode 100644
index 01e1a4ad3..000000000
--- a/cmd/kpod/spec_test.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package main
-
-import (
- "reflect"
- "testing"
-
- spec "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/stretchr/testify/assert"
-)
-
-func TestCreateConfig_GetVolumeMounts(t *testing.T) {
- data := spec.Mount{
- Destination: "/foobar",
- Type: "bind",
- Source: "foobar",
- Options: []string{"ro", "rbind", "rprivate"},
- }
- config := createConfig{
- Volumes: []string{"foobar:/foobar:ro"},
- }
- specMount, err := config.GetVolumeMounts()
- assert.NoError(t, err)
- assert.True(t, reflect.DeepEqual(data, specMount[0]))
-}
-
-func TestCreateConfig_GetTmpfsMounts(t *testing.T) {
- data := spec.Mount{
- Destination: "/homer",
- Type: "tmpfs",
- Source: "tmpfs",
- Options: []string{"rw", "size=787448k", "mode=1777"},
- }
- config := createConfig{
- Tmpfs: []string{"/homer:rw,size=787448k,mode=1777"},
- }
- tmpfsMount := config.GetTmpfsMounts()
- assert.True(t, reflect.DeepEqual(data, tmpfsMount[0]))
-
-}
diff --git a/cmd/kpod/start.go b/cmd/kpod/start.go
deleted file mode 100644
index 88dadb1c8..000000000
--- a/cmd/kpod/start.go
+++ /dev/null
@@ -1,131 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
- "strconv"
- "sync"
-
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/sirupsen/logrus"
- "github.com/urfave/cli"
-)
-
-var (
- startFlags = []cli.Flag{
- cli.BoolFlag{
- Name: "attach, a",
- Usage: "Attach container's STDOUT and STDERR",
- },
- 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.BoolFlag{
- Name: "interactive, i",
- Usage: "Keep STDIN open even if not attached",
- },
- }
- startDescription = `
- kpod start
-
- Starts one or more containers. The container name or ID can be used.
-`
-
- startCommand = cli.Command{
- Name: "start",
- Usage: "Start one or more containers",
- Description: startDescription,
- Flags: startFlags,
- Action: startCmd,
- ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
- UseShortOptionHandling: true,
- }
-)
-
-func startCmd(c *cli.Context) error {
- args := c.Args()
- if len(args) < 1 {
- return errors.Errorf("you must provide at least one container name or id")
- }
-
- attach := c.Bool("attach")
-
- if len(args) > 1 && attach {
- return errors.Errorf("you cannot start and attach multiple containers at once")
- }
-
- if err := validateFlags(c, startFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "error creating libpod runtime")
- }
- defer runtime.Shutdown(false)
-
- var lastError error
- for _, container := range args {
- // Create a bool channel to track that the console socket attach
- // is successful.
- attached := make(chan bool)
- // Create a waitgroup so we can sync and wait for all goroutines
- // to finish before exiting main
- var wg sync.WaitGroup
-
- ctr, err := runtime.LookupContainer(container)
- if err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "unable to find container %s", container)
- continue
- }
-
- if err := ctr.Init(); err != nil && errors.Cause(err) != libpod.ErrCtrExists {
- return err
- }
-
- // We can only be interactive if both the config and the command-line say so
- if c.Bool("interactive") && !ctr.Config().Stdin {
- return errors.Errorf("the container was not created with the interactive option")
- }
- noStdIn := c.Bool("interactive")
- tty, err := strconv.ParseBool(ctr.Spec().Annotations["io.kubernetes.cri-o.TTY"])
- if err != nil {
- return errors.Wrapf(err, "unable to parse annotations in %s", ctr.ID())
- }
- // We only get a terminal session if both a tty was specified in the spec and
- // -a on the command-line was given.
- if attach && tty {
- // We increment the wg counter because we need to do the attach
- wg.Add(1)
- // Attach to the running container
- go func() {
- logrus.Debugf("trying to attach to the container %s", ctr.ID())
- defer wg.Done()
- if err := ctr.Attach(noStdIn, c.String("detach-keys"), attached); err != nil {
- logrus.Errorf("unable to attach to container %s: %q", ctr.ID(), err)
- }
- }()
- if !<-attached {
- return errors.Errorf("unable to attach to container %s", ctr.ID())
- }
- }
- err = ctr.Start()
- if err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "unable to start %s", container)
- continue
- }
- if !attach {
- fmt.Println(ctr.ID())
- }
- wg.Wait()
- }
- return lastError
-}
diff --git a/cmd/kpod/stats.go b/cmd/kpod/stats.go
deleted file mode 100644
index d98c2ee27..000000000
--- a/cmd/kpod/stats.go
+++ /dev/null
@@ -1,226 +0,0 @@
-package main
-
-import (
- "fmt"
- "reflect"
- "strings"
- "time"
-
- tm "github.com/buger/goterm"
- "github.com/docker/go-units"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/cmd/kpod/formats"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
-)
-
-type statsOutputParams struct {
- Container string `json:"name"`
- ID string `json:"id"`
- CPUPerc string `json:"cpu_percent"`
- MemUsage string `json:"mem_usage"`
- MemPerc string `json:"mem_percent"`
- NetIO string `json:"netio"`
- BlockIO string `json:"blocki"`
- PIDS uint64 `json:"pids"`
-}
-
-var (
- statsFlags = []cli.Flag{
- cli.BoolFlag{
- Name: "all, a",
- Usage: "show all containers. Only running containers are shown by default. The default is false",
- },
- cli.BoolFlag{
- Name: "no-stream",
- Usage: "disable streaming stats and only pull the first result, default setting is false",
- },
- cli.StringFlag{
- Name: "format",
- Usage: "pretty-print container statistics using a Go template",
- },
- cli.BoolFlag{
- Name: "no-reset",
- Usage: "disable resetting the screen between intervals",
- },
- }
-
- statsDescription = "display a live stream of one or more containers' resource usage statistics"
- statsCommand = cli.Command{
- Name: "stats",
- Usage: "Display percentage of CPU, memory, network I/O, block I/O and PIDs for one or more containers",
- Description: statsDescription,
- Flags: statsFlags,
- Action: statsCmd,
- ArgsUsage: "",
- }
-)
-
-func statsCmd(c *cli.Context) error {
- if err := validateFlags(c, statsFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- times := -1
- if c.Bool("no-stream") {
- times = 1
- }
-
- var format string
- var ctrs []*libpod.Container
- var containerFunc func() ([]*libpod.Container, error)
- all := c.Bool("all")
-
- if c.IsSet("format") {
- format = c.String("format")
- } else {
- format = genStatsFormat()
- }
-
- if len(c.Args()) > 0 {
- containerFunc = func() ([]*libpod.Container, error) { return runtime.GetContainersByList(c.Args()) }
- } else if all {
- containerFunc = runtime.GetAllContainers
- } else {
- containerFunc = runtime.GetRunningContainers
- }
-
- ctrs, err = containerFunc()
- if err != nil {
- return errors.Wrapf(err, "unable to get list of containers")
- }
-
- containerStats := map[string]*libpod.ContainerStats{}
- for _, ctr := range ctrs {
- initialStats, err := ctr.GetContainerStats(&libpod.ContainerStats{})
- if err != nil {
- return err
- }
- containerStats[ctr.ID()] = initialStats
- }
- step := 1
- if times == -1 {
- times = 1
- step = 0
- }
- for i := 0; i < times; i += step {
- reportStats := []*libpod.ContainerStats{}
- for _, ctr := range ctrs {
- id := ctr.ID()
- if _, ok := containerStats[ctr.ID()]; !ok {
- initialStats, err := ctr.GetContainerStats(&libpod.ContainerStats{})
- if err != nil {
- return err
- }
- containerStats[id] = initialStats
- }
- stats, err := ctr.GetContainerStats(containerStats[id])
- if err != nil {
- return err
- }
- // replace the previous measurement with the current one
- containerStats[id] = stats
- reportStats = append(reportStats, stats)
- }
- ctrs, err = containerFunc()
- if err != nil {
- return err
- }
- if strings.ToLower(format) != formats.JSONString && !c.Bool("no-reset") {
- tm.Clear()
- tm.MoveCursor(1, 1)
- tm.Flush()
- }
- outputStats(reportStats, format)
- time.Sleep(time.Second)
- }
- return nil
-}
-
-func outputStats(stats []*libpod.ContainerStats, format string) error {
- var out formats.Writer
- var outputStats []statsOutputParams
- for _, s := range stats {
- outputStats = append(outputStats, getStatsOutputParams(s))
- }
- if len(outputStats) == 0 {
- return nil
- }
- if strings.ToLower(format) == formats.JSONString {
- out = formats.JSONStructArray{Output: statsToGeneric(outputStats, []statsOutputParams{})}
- } else {
- out = formats.StdoutTemplateArray{Output: statsToGeneric(outputStats, []statsOutputParams{}), Template: format, Fields: outputStats[0].headerMap()}
- }
- return formats.Writer(out).Out()
-}
-
-func genStatsFormat() (format string) {
- return "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDS}}"
-}
-
-// imagesToGeneric creates an empty array of interfaces for output
-func statsToGeneric(templParams []statsOutputParams, JSONParams []statsOutputParams) (genericParams []interface{}) {
- if len(templParams) > 0 {
- for _, v := range templParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
- }
- for _, v := range JSONParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
-}
-
-// generate the header based on the template provided
-func (i *statsOutputParams) headerMap() map[string]string {
- v := reflect.Indirect(reflect.ValueOf(i))
- values := make(map[string]string)
-
- for i := 0; i < v.NumField(); i++ {
- key := v.Type().Field(i).Name
- value := key
- switch value {
- case "CPUPerc":
- value = "CPU%"
- case "MemUsage":
- value = "MemUsage/Limit"
- case "MemPerc":
- value = "Mem%"
- }
- values[key] = strings.ToUpper(splitCamelCase(value))
- }
- return values
-}
-
-func combineHumanValues(a, b uint64) string {
- return fmt.Sprintf("%s / %s", units.HumanSize(float64(a)), units.HumanSize(float64(b)))
-}
-
-func floatToPercentString(f float64) string {
- strippedFloat, err := libpod.RemoveScientificNotationFromFloat(f)
- if err != nil {
- // If things go bazinga, return a safe value
- return "0.00 %"
- }
- return fmt.Sprintf("%.2f", strippedFloat) + "%"
-}
-
-func getStatsOutputParams(stats *libpod.ContainerStats) statsOutputParams {
- return statsOutputParams{
- Container: stats.ContainerID[:12],
- ID: stats.ContainerID,
- CPUPerc: floatToPercentString(stats.CPU),
- MemUsage: combineHumanValues(stats.MemUsage, stats.MemLimit),
- MemPerc: floatToPercentString(stats.MemPerc),
- NetIO: combineHumanValues(stats.NetInput, stats.NetOutput),
- BlockIO: combineHumanValues(stats.BlockInput, stats.BlockOutput),
- PIDS: stats.PIDs,
- }
-}
diff --git a/cmd/kpod/stop.go b/cmd/kpod/stop.go
deleted file mode 100644
index f18fbc232..000000000
--- a/cmd/kpod/stop.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
-
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/sirupsen/logrus"
- "github.com/urfave/cli"
-)
-
-var (
- defaultTimeout int64 = 10
- stopFlags = []cli.Flag{
- cli.Int64Flag{
- Name: "timeout, t",
- Usage: "Seconds to wait for stop before killing the container",
- Value: defaultTimeout,
- },
- cli.BoolFlag{
- Name: "all, a",
- Usage: "stop all running containers",
- },
- }
- stopDescription = `
- kpod stop
-
- Stops one or more running containers. The container name or ID can be used.
- A timeout to forcibly stop the container can also be set but defaults to 10
- seconds otherwise.
-`
-
- stopCommand = cli.Command{
- Name: "stop",
- Usage: "Stop one or more containers",
- Description: stopDescription,
- Flags: stopFlags,
- Action: stopCmd,
- ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
- }
-)
-
-func stopCmd(c *cli.Context) error {
- args := c.Args()
- stopTimeout := c.Int64("timeout")
- if c.Bool("all") && len(args) > 0 {
- return errors.Errorf("no arguments are needed with -a")
- }
- if len(args) < 1 && !c.Bool("all") {
- return errors.Errorf("you must provide at least one container name or id")
- }
- if err := validateFlags(c, stopFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- logrus.Debugf("Stopping containers with timeout %d", stopTimeout)
-
- var filterFuncs []libpod.ContainerFilter
- var containers []*libpod.Container
- var lastError error
-
- if c.Bool("all") {
- // only get running containers
- filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
- state, _ := c.State()
- return state == libpod.ContainerStateRunning
- })
- containers, err = runtime.GetContainers(filterFuncs...)
- if err != nil {
- return errors.Wrapf(err, "unable to get running containers")
- }
- } else {
- for _, i := range args {
- container, err := runtime.LookupContainer(i)
- if err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "unable to find container %s", i)
- continue
- }
- containers = append(containers, container)
- }
- }
-
- for _, ctr := range containers {
- if err := ctr.Stop(stopTimeout); err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "failed to stop container %v", ctr.ID())
- } else {
- fmt.Println(ctr.ID())
- }
- }
- return lastError
-}
diff --git a/cmd/kpod/tag.go b/cmd/kpod/tag.go
deleted file mode 100644
index f29c8c182..000000000
--- a/cmd/kpod/tag.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package main
-
-import (
- "github.com/containers/image/docker/reference"
- "github.com/containers/storage"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
-)
-
-var (
- tagDescription = "Adds one or more additional names to locally-stored image"
- tagCommand = cli.Command{
- Name: "tag",
- Usage: "Add an additional name to a local image",
- Description: tagDescription,
- Action: tagCmd,
- ArgsUsage: "IMAGE-NAME [IMAGE-NAME ...]",
- }
-)
-
-func tagCmd(c *cli.Context) error {
- args := c.Args()
- if len(args) < 2 {
- return errors.Errorf("image name and at least one new name must be specified")
- }
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not create runtime")
- }
- defer runtime.Shutdown(false)
-
- img, err := runtime.GetImage(args[0])
- if err != nil {
- return err
- }
- if img == nil {
- return errors.New("null image")
- }
- err = addImageNames(runtime, img, args[1:])
- if err != nil {
- return errors.Wrapf(err, "error adding names %v to image %q", args[1:], args[0])
- }
- return nil
-}
-
-func addImageNames(runtime *libpod.Runtime, image *storage.Image, addNames []string) error {
- // Add tags to the names if applicable
- names, err := expandedTags(addNames)
- if err != nil {
- return err
- }
- for _, name := range names {
- if err := runtime.TagImage(image, name); err != nil {
- return errors.Wrapf(err, "error adding name (%v) to image %q", name, image.ID)
- }
- }
- return nil
-}
-
-func expandedTags(tags []string) ([]string, error) {
- expandedNames := []string{}
- for _, tag := range tags {
- var labelName string
- name, err := reference.Parse(tag)
- if err != nil {
- return nil, errors.Wrapf(err, "error parsing tag %q", name)
- }
- if _, ok := name.(reference.NamedTagged); ok {
- labelName = name.String()
- } else {
- labelName = name.String() + ":latest"
- }
- expandedNames = append(expandedNames, labelName)
- }
- return expandedNames, nil
-}
diff --git a/cmd/kpod/top.go b/cmd/kpod/top.go
deleted file mode 100644
index 0c1eabbdb..000000000
--- a/cmd/kpod/top.go
+++ /dev/null
@@ -1,258 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "fmt"
- "strings"
-
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/cmd/kpod/formats"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
-)
-
-var (
- topFlags = []cli.Flag{
- cli.StringFlag{
- Name: "format",
- Usage: "Change the output to JSON",
- },
- }
- topDescription = `
- kpod top
-
- Display the running processes of the container.
-`
-
- topCommand = cli.Command{
- Name: "top",
- Usage: "Display the running processes of a container",
- Description: topDescription,
- Flags: topFlags,
- Action: topCmd,
- ArgsUsage: "CONTAINER-NAME",
- SkipArgReorder: true,
- }
-)
-
-func topCmd(c *cli.Context) error {
- doJSON := false
- if c.IsSet("format") {
- if strings.ToUpper(c.String("format")) == "JSON" {
- doJSON = true
- } else {
- return errors.Errorf("only 'json' is supported for a format option")
- }
- }
- args := c.Args()
- var psArgs []string
- psOpts := []string{"-o", "uid,pid,ppid,c,stime,tname,time,cmd"}
- if len(args) < 1 {
- return errors.Errorf("you must provide the name or id of a running container")
- }
- if err := validateFlags(c, topFlags); err != nil {
- return err
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "error creating libpod runtime")
- }
- defer runtime.Shutdown(false)
- if len(args) > 1 {
- psOpts = args[1:]
- }
-
- container, err := runtime.LookupContainer(args[0])
- if err != nil {
- return errors.Wrapf(err, "unable to lookup %s", args[0])
- }
- conStat, err := container.State()
- if err != nil {
- return errors.Wrapf(err, "unable to look up state for %s", args[0])
- }
- if conStat != libpod.ContainerStateRunning {
- return errors.Errorf("top can only be used on running containers")
- }
-
- psArgs = append(psArgs, psOpts...)
-
- results, err := container.GetContainerPidInformation(psArgs)
- if err != nil {
- return err
- }
- headers := getHeaders(results[0])
- format := genTopFormat(headers)
- var out formats.Writer
- psParams, err := psDataToPSParams(results[1:], headers)
- if err != nil {
- return errors.Wrap(err, "unable to convert ps data to proper structure")
- }
- if doJSON {
- out = formats.JSONStructArray{Output: topToGeneric(psParams)}
- } else {
- out = formats.StdoutTemplateArray{Output: topToGeneric(psParams), Template: format, Fields: createTopHeaderMap(headers)}
- }
- formats.Writer(out).Out()
- return nil
-}
-
-func getHeaders(s string) []string {
- var headers []string
- tmpHeaders := strings.Fields(s)
- for _, header := range tmpHeaders {
- headers = append(headers, strings.Replace(header, "%", "", -1))
- }
- return headers
-}
-
-func genTopFormat(headers []string) string {
- format := "table "
- for _, header := range headers {
- format = fmt.Sprintf("%s{{.%s}}\t", format, header)
- }
- return format
-}
-
-// imagesToGeneric creates an empty array of interfaces for output
-func topToGeneric(templParams []PSParams) (genericParams []interface{}) {
- for _, v := range templParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
-}
-
-// generate the header based on the template provided
-func createTopHeaderMap(v []string) map[string]string {
- values := make(map[string]string)
- for _, key := range v {
- value := key
- if value == "CPU" {
- value = "%CPU"
- } else if value == "MEM" {
- value = "%MEM"
- }
- values[key] = strings.ToUpper(splitCamelCase(value))
- }
- return values
-}
-
-// PSDataToParams converts a string array of data and its headers to an
-// arra if PSParams
-func psDataToPSParams(data []string, headers []string) ([]PSParams, error) {
- var params []PSParams
- for _, line := range data {
- tmpMap := make(map[string]string)
- tmpArray := strings.Fields(line)
- if len(tmpArray) == 0 {
- continue
- }
- for index, v := range tmpArray {
- header := headers[index]
- tmpMap[header] = v
- }
- jsonData, _ := json.Marshal(tmpMap)
- var r PSParams
- err := json.Unmarshal(jsonData, &r)
- if err != nil {
- return []PSParams{}, err
- }
- params = append(params, r)
- }
- return params, nil
-}
-
-//PSParams is a list of options that the command line ps recognizes
-type PSParams struct {
- CPU string
- MEM string
- COMMAND string
- BLOCKED string
- START string
- TIME string
- C string
- CAUGHT string
- CGROUP string
- CLSCLS string
- CLS string
- CMD string
- CP string
- DRS string
- EGID string
- EGROUP string
- EIP string
- ESP string
- ELAPSED string
- EUIDE string
- USER string
- F string
- FGID string
- FGROUP string
- FUID string
- FUSER string
- GID string
- GROUP string
- IGNORED string
- IPCNS string
- LABEL string
- STARTED string
- SESSION string
- LWP string
- MACHINE string
- MAJFLT string
- MINFLT string
- MNTNS string
- NETNS string
- NI string
- NLWP string
- OWNER string
- PENDING string
- PGID string
- PGRP string
- PID string
- PIDNS string
- POL string
- PPID string
- PRI string
- PSR string
- RGID string
- RGROUP string
- RSS string
- RSZ string
- RTPRIO string
- RUID string
- RUSER string
- S string
- SCH string
- SEAT string
- SESS string
- P string
- SGID string
- SGROUP string
- SID string
- SIZE string
- SLICE string
- SPID string
- STACKP string
- STIME string
- SUID string
- SUPGID string
- SUPGRP string
- SUSER string
- SVGID string
- SZ string
- TGID string
- THCNT string
- TID string
- TTY string
- TPGID string
- TRS string
- TT string
- UID string
- UNIT string
- USERNS string
- UTSNS string
- UUNIT string
- VSZ string
- WCHAN string
-}
diff --git a/cmd/kpod/umount.go b/cmd/kpod/umount.go
deleted file mode 100644
index 4b6aba99e..000000000
--- a/cmd/kpod/umount.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package main
-
-import (
- "github.com/pkg/errors"
- "github.com/urfave/cli"
-)
-
-var (
- umountCommand = cli.Command{
- Name: "umount",
- Aliases: []string{"unmount"},
- Usage: "Unmount a working container's root filesystem",
- Description: "Unmounts a working container's root filesystem",
- Action: umountCmd,
- ArgsUsage: "CONTAINER-NAME-OR-ID",
- }
-)
-
-func umountCmd(c *cli.Context) error {
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- args := c.Args()
- if len(args) == 0 {
- return errors.Errorf("container ID must be specified")
- }
- if len(args) > 1 {
- return errors.Errorf("too many arguments specified")
- }
-
- ctr, err := runtime.LookupContainer(args[0])
- if err != nil {
- return errors.Wrapf(err, "error looking up container %q", args[0])
- }
-
- return ctr.Unmount()
-}
diff --git a/cmd/kpod/unpause.go b/cmd/kpod/unpause.go
deleted file mode 100644
index 6deed7e77..000000000
--- a/cmd/kpod/unpause.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
-
- "github.com/pkg/errors"
- "github.com/urfave/cli"
-)
-
-var (
- unpauseDescription = `
- kpod unpause
-
- Unpauses one or more running containers. The container name or ID can be used.
-`
- unpauseCommand = cli.Command{
- Name: "unpause",
- Usage: "Unpause the processes in one or more containers",
- Description: unpauseDescription,
- Action: unpauseCmd,
- ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
- }
-)
-
-func unpauseCmd(c *cli.Context) error {
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.Shutdown(false)
-
- args := c.Args()
- if len(args) < 1 {
- return errors.Errorf("you must provide at least one container name or id")
- }
-
- var lastError error
- for _, arg := range args {
- ctr, err := runtime.LookupContainer(arg)
- if err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "error looking up container %q", arg)
- continue
- }
- if err = ctr.Unpause(); err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "failed to unpause container %v", ctr.ID())
- } else {
- fmt.Println(ctr.ID())
- }
- }
- return lastError
-}
diff --git a/cmd/kpod/user.go b/cmd/kpod/user.go
deleted file mode 100644
index 3e2e308c5..000000000
--- a/cmd/kpod/user.go
+++ /dev/null
@@ -1,121 +0,0 @@
-package main
-
-// #include <sys/types.h>
-// #include <grp.h>
-// #include <pwd.h>
-// #include <stdlib.h>
-// #include <stdio.h>
-// #include <string.h>
-// typedef FILE * pFILE;
-import "C"
-
-import (
- "fmt"
- "os/user"
- "path/filepath"
- "sync"
- "syscall"
- "unsafe"
-
- "github.com/pkg/errors"
-)
-
-func fopenContainerFile(rootdir, filename string) (C.pFILE, error) {
- var st, lst syscall.Stat_t
-
- ctrfile := filepath.Join(rootdir, filename)
- cctrfile := C.CString(ctrfile)
- defer C.free(unsafe.Pointer(cctrfile))
- mode := C.CString("r")
- defer C.free(unsafe.Pointer(mode))
- f, err := C.fopen(cctrfile, mode)
- if f == nil || err != nil {
- return nil, errors.Wrapf(err, "error opening %q", ctrfile)
- }
- if err = syscall.Fstat(int(C.fileno(f)), &st); err != nil {
- return nil, errors.Wrapf(err, "fstat(%q)", ctrfile)
- }
- if err = syscall.Lstat(ctrfile, &lst); err != nil {
- return nil, errors.Wrapf(err, "lstat(%q)", ctrfile)
- }
- if st.Dev != lst.Dev || st.Ino != lst.Ino {
- return nil, errors.Errorf("%q is not a regular file", ctrfile)
- }
- return f, nil
-}
-
-var (
- lookupUser, lookupGroup sync.Mutex
-)
-
-func lookupUserInContainer(rootdir, username string) (uint64, uint64, error) {
- name := C.CString(username)
- defer C.free(unsafe.Pointer(name))
-
- f, err := fopenContainerFile(rootdir, "/etc/passwd")
- if err != nil {
- return 0, 0, err
- }
- defer C.fclose(f)
-
- lookupUser.Lock()
- defer lookupUser.Unlock()
-
- pwd := C.fgetpwent(f)
- for pwd != nil {
- if C.strcmp(pwd.pw_name, name) != 0 {
- pwd = C.fgetpwent(f)
- continue
- }
- return uint64(pwd.pw_uid), uint64(pwd.pw_gid), nil
- }
-
- return 0, 0, user.UnknownUserError(fmt.Sprintf("error looking up user %q", username))
-}
-
-func lookupGroupForUIDInContainer(rootdir string, userid uint64) (string, uint64, error) {
- f, err := fopenContainerFile(rootdir, "/etc/passwd")
- if err != nil {
- return "", 0, err
- }
- defer C.fclose(f)
-
- lookupUser.Lock()
- defer lookupUser.Unlock()
-
- pwd := C.fgetpwent(f)
- for pwd != nil {
- if uint64(pwd.pw_uid) != userid {
- pwd = C.fgetpwent(f)
- continue
- }
- return C.GoString(pwd.pw_name), uint64(pwd.pw_gid), nil
- }
-
- return "", 0, user.UnknownUserError(fmt.Sprintf("error looking up user with UID %d", userid))
-}
-
-func lookupGroupInContainer(rootdir, groupname string) (uint64, error) {
- name := C.CString(groupname)
- defer C.free(unsafe.Pointer(name))
-
- f, err := fopenContainerFile(rootdir, "/etc/group")
- if err != nil {
- return 0, err
- }
- defer C.fclose(f)
-
- lookupGroup.Lock()
- defer lookupGroup.Unlock()
-
- grp := C.fgetgrent(f)
- for grp != nil {
- if C.strcmp(grp.gr_name, name) != 0 {
- grp = C.fgetgrent(f)
- continue
- }
- return uint64(grp.gr_gid), nil
- }
-
- return 0, user.UnknownGroupError(fmt.Sprintf("error looking up group %q", groupname))
-}
diff --git a/cmd/kpod/version.go b/cmd/kpod/version.go
deleted file mode 100644
index 586c41da6..000000000
--- a/cmd/kpod/version.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package main
-
-import (
- "fmt"
- "runtime"
- "strconv"
- "time"
-
- "github.com/urfave/cli"
-)
-
-// Overwritten at build time
-var (
- // gitCommit is the commit that the binary is being built from.
- // It will be populated by the Makefile.
- gitCommit string
- // buildInfo is the time at which the binary was built
- // It will be populated by the Makefile.
- buildInfo string
-)
-
-// versionCmd gets and prints version info for version command
-func versionCmd(c *cli.Context) error {
- fmt.Println("Version: ", c.App.Version)
- fmt.Println("Go Version: ", runtime.Version())
- if gitCommit != "" {
- fmt.Println("Git Commit: ", gitCommit)
- }
- if buildInfo != "" {
- // Converts unix time from string to int64
- buildTime, err := strconv.ParseInt(buildInfo, 10, 64)
- if err != nil {
- return err
- }
- // Prints out the build time in readable format
- fmt.Println("Built: ", time.Unix(buildTime, 0).Format(time.ANSIC))
- }
- fmt.Println("OS/Arch: ", runtime.GOOS+"/"+runtime.GOARCH)
-
- return nil
-}
-
-// Cli command to print out the full version of kpod
-var versionCommand = cli.Command{
- Name: "version",
- Usage: "Display the KPOD Version Information",
- Action: versionCmd,
-}
diff --git a/cmd/kpod/wait.go b/cmd/kpod/wait.go
deleted file mode 100644
index 6e22f54e5..000000000
--- a/cmd/kpod/wait.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
-
- "github.com/pkg/errors"
- "github.com/urfave/cli"
-)
-
-var (
- waitDescription = `
- kpod wait
-
- Block until one or more containers stop and then print their exit codes
-`
-
- waitCommand = cli.Command{
- Name: "wait",
- Usage: "Block on one or more containers",
- Description: waitDescription,
- Action: waitCmd,
- ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
- }
-)
-
-func waitCmd(c *cli.Context) error {
- args := c.Args()
- if len(args) < 1 {
- return errors.Errorf("you must provide at least one container name or id")
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "error creating libpod runtime")
- }
- defer runtime.Shutdown(false)
-
- if err != nil {
- return errors.Wrapf(err, "could not get config")
- }
-
- var lastError error
- for _, container := range c.Args() {
- ctr, err := runtime.LookupContainer(container)
- if err != nil {
- return errors.Wrapf(err, "unable to find container %s", container)
- }
- returnCode, err := ctr.Wait()
- if err != nil {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "failed to wait for the container %v", container)
- } else {
- fmt.Println(returnCode)
- }
- }
-
- return lastError
-}