summaryrefslogtreecommitdiff
path: root/cmd/kpod/create.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/kpod/create.go')
-rw-r--r--cmd/kpod/create.go343
1 files changed, 343 insertions, 0 deletions
diff --git a/cmd/kpod/create.go b/cmd/kpod/create.go
new file mode 100644
index 000000000..2e79c883e
--- /dev/null
+++ b/cmd/kpod/create.go
@@ -0,0 +1,343 @@
+package main
+
+import (
+ "fmt"
+ "strconv"
+
+ "github.com/docker/go-units"
+ "github.com/projectatomic/libpod/libpod"
+ "github.com/pkg/errors"
+ "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 = []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM=xterm"}
+)
+
+type createResourceConfig struct {
+ blkioDevice []string // blkio-weight-device
+ blkioWeight uint16 // blkio-weight
+ 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
+ memorySwapiness uint64 // memory-swappiness
+ oomScoreAdj int //oom-score-adj
+ pidsLimit int64 // pids-limit
+ shmSize string
+ ulimit []string //ulimit
+}
+
+type createConfig struct {
+ 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 []string //env
+ expose []string //expose
+ groupAdd []uint32 // group-add
+ hostname string //hostname
+ image string
+ interactive bool //interactive
+ 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
+ network string //network
+ networkAlias []string //network-alias
+ nsIPC string // ipc
+ nsNet string //net
+ nsPID string //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
+ securityOpts []string //security-opt
+ 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
+ volumes []string //volume
+ volumesFrom []string //volumes-from
+ workDir string //workdir
+}
+
+var createDescription = "Creates a new container from the given image or" +
+ " storage and prepares it for running the specified command. The" +
+ " container ID is then printed to stdout. You can then start it at" +
+ " any time with the kpod start <container_id> command. The container" +
+ " will be created with the initial state 'created'."
+
+var createCommand = cli.Command{
+ Name: "create",
+ Usage: "create but do not start a container",
+ Description: createDescription,
+ Flags: createFlags,
+ Action: createCmd,
+ ArgsUsage: "IMAGE [COMMAND [ARG...]]",
+}
+
+func createCmd(c *cli.Context) error {
+ // TODO should allow user to create based off a directory on the host not just image
+ // Need CLI support for this
+ if err := validateFlags(c, createFlags); err != nil {
+ return err
+ }
+
+ runtime, err := getRuntime(c)
+ if err != nil {
+ return errors.Wrapf(err, "error creating libpod runtime")
+ }
+
+ createConfig, err := parseCreateOpts(c, runtime)
+ if err != nil {
+ return err
+ }
+
+ // Deal with the image after all the args have been checked
+ createImage := runtime.NewImage(createConfig.image)
+ if !createImage.HasImageLocal() {
+ // 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
+ }
+ defer runtime.Shutdown(false)
+ imageName, err := createImage.GetFQName()
+ if err != nil {
+ return err
+ }
+ imageID, err := createImage.GetImageID()
+ if err != nil {
+ return err
+ }
+ options, err := createConfig.GetContainerCreateOptions(c)
+ 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))
+ ctr, err := runtime.NewContainer(runtimeSpec, options...)
+ if err != nil {
+ return err
+ }
+
+ if c.String("cidfile") != "" {
+ libpod.WriteFile(ctr.ID(), c.String("cidfile"))
+ } else {
+ fmt.Printf("%s\n", ctr.ID())
+ }
+
+ return nil
+}
+
+// Parses CLI options related to container creation into a config which can be
+// parsed into an OCI runtime spec
+func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, error) {
+ var command []string
+ var memoryLimit, memoryReservation, memorySwap, memoryKernel int64
+ var blkioWeight uint16
+ var uid, gid uint32
+
+ image := c.Args()[0]
+
+ if len(c.Args()) < 1 {
+ return nil, errors.Errorf("image name or ID is required")
+ }
+ if len(c.Args()) > 1 {
+ command = c.Args()[1:]
+ }
+
+ // LABEL VARIABLES
+ labels, err := getAllLabels(c)
+ if err != nil {
+ return &createConfig{}, errors.Wrapf(err, "unable to process labels")
+ }
+ // ENVIRONMENT VARIABLES
+ // TODO where should env variables be verified to be x=y format
+ env, err := getAllEnvironmentVariables(c)
+ if 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)
+ }
+
+ config := &createConfig{
+ 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("env"),
+ 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"),
+ nsIPC: c.String("ipc"),
+ nsNet: c.String("net"),
+ nsPID: c.String("pid"),
+ 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,
+ blkioDevice: 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,
+ memorySwapiness: c.Uint64("memory-swapiness"),
+ kernelMemory: memoryKernel,
+ oomScoreAdj: c.Int("oom-score-adj"),
+
+ pidsLimit: c.Int64("pids-limit"),
+ ulimit: c.StringSlice("ulimit"),
+ },
+ rm: c.Bool("rm"),
+ securityOpts: c.StringSlice("security-opt"),
+ 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: c.Bool("tty"),
+ user: uid,
+ group: gid,
+ volumes: c.StringSlice("volume"),
+ volumesFrom: c.StringSlice("volumes-from"),
+ workDir: c.String("workdir"),
+ }
+
+ return config, nil
+}