diff options
Diffstat (limited to 'cmd/kpod/create.go')
-rw-r--r-- | cmd/kpod/create.go | 343 |
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 +} |