diff options
Diffstat (limited to 'cmd/podman/create.go')
-rw-r--r-- | cmd/podman/create.go | 131 |
1 files changed, 110 insertions, 21 deletions
diff --git a/cmd/podman/create.go b/cmd/podman/create.go index ead2f6735..80cb7f432 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io" + "net" "os" "strconv" "strings" @@ -47,7 +48,7 @@ type createResourceConfig struct { CPURtPeriod uint64 // cpu-rt-period CPURtRuntime int64 // cpu-rt-runtime CPUShares uint64 // cpu-shares - CPUs string // cpus + CPUs float64 // cpus CPUsetCPUs string CPUsetMems string // cpuset-mems DeviceReadBps []string // device-read-bps @@ -83,6 +84,7 @@ type createConfig struct { Env map[string]string //env ExposedPorts map[nat.Port]struct{} GroupAdd []uint32 // group-add + HostAdd []string //add-host Hostname string //hostname Image string ImageID string @@ -114,7 +116,6 @@ type createConfig struct { SigProxy bool //sig-proxy StopSignal syscall.Signal // stop-signal StopTimeout uint // stop-timeout - StorageOpts []string //storage-opt Sysctl map[string]string //sysctl Tmpfs []string // tmpfs Tty bool //tty @@ -171,6 +172,9 @@ func createCmd(c *cli.Context) error { defer runtime.Shutdown(false) imageName, _, data, err := imageData(c, runtime, c.Args()[0]) + if err != nil { + return err + } createConfig, err := parseCreateOpts(c, runtime, imageName, data) if err != nil { return err @@ -216,8 +220,6 @@ func createCmd(c *cli.Context) error { return nil } -const seccompDefaultPath = "/etc/crio/seccomp.json" - func parseSecurityOpt(config *createConfig, securityOpts []string) error { var ( labelOpts []string @@ -267,28 +269,56 @@ func parseSecurityOpt(config *createConfig, securityOpts []string) error { } if config.SeccompProfilePath == "" { - if _, err := os.Stat(seccompDefaultPath); err != nil { + if _, err := os.Stat(libpod.SeccompOverridePath); err == nil { + config.SeccompProfilePath = libpod.SeccompOverridePath + } else { if !os.IsNotExist(err) { - return errors.Wrapf(err, "can't check if %q exists", seccompDefaultPath) + return errors.Wrapf(err, "can't check if %q exists", libpod.SeccompOverridePath) + } + if _, err := os.Stat(libpod.SeccompDefaultPath); err != nil { + if !os.IsNotExist(err) { + return errors.Wrapf(err, "can't check if %q exists", libpod.SeccompDefaultPath) + } + } else { + config.SeccompProfilePath = libpod.SeccompDefaultPath } - } else { - config.SeccompProfilePath = seccompDefaultPath } } config.ProcessLabel, config.MountLabel, err = label.InitLabels(labelOpts) return err } -func exposedPorts(c *cli.Context, imageExposedPorts map[string]struct{}) (map[nat.Port]struct{}, map[nat.Port][]nat.PortBinding, error) { - // TODO Handle exposed ports from image - // Currently ignoring imageExposedPorts +// isPortInPortBindings determines if an exposed host port is in user +// provided ports +func isPortInPortBindings(pb map[nat.Port][]nat.PortBinding, port nat.Port) bool { + var hostPorts []string + for _, i := range pb { + hostPorts = append(hostPorts, i[0].HostPort) + } + return libpod.StringInSlice(port.Port(), hostPorts) +} - ports, portBindings, err := nat.ParsePortSpecs(c.StringSlice("publish")) +func exposedPorts(c *cli.Context, imageExposedPorts map[string]struct{}) (map[nat.Port]struct{}, map[nat.Port][]nat.PortBinding, error) { + var exposedPorts []string + var ports map[nat.Port]struct{} + ports = make(map[nat.Port]struct{}) + _, portBindings, err := nat.ParsePortSpecs(c.StringSlice("publish")) if err != nil { return nil, nil, err } - for _, e := range c.StringSlice("expose") { + // Parse the ports from the image itself + for i := range imageExposedPorts { + fields := strings.Split(i, "/") + if len(fields) > 2 { + return nil, nil, errors.Errorf("invalid exposed port format in image") + } + exposedPorts = append(exposedPorts, fields[0]) + } + + // Add the ports from the image to the ports from the user + exposedPorts = append(exposedPorts, c.StringSlice("expose")...) + for _, e := range exposedPorts { // Merge in exposed ports to the map of published ports if strings.Contains(e, ":") { return nil, nil, fmt.Errorf("invalid port format for --expose: %s", e) @@ -306,6 +336,28 @@ func exposedPorts(c *cli.Context, imageExposedPorts map[string]struct{}) (map[na if err != nil { return nil, nil, err } + // check if the port in question is already being used + if isPortInPortBindings(portBindings, p) { + return nil, nil, errors.Errorf("host port %s already used in --publish option", p.Port()) + } + + if c.Bool("publish-all") { + l, err := net.Listen("tcp", ":0") + if err != nil { + return nil, nil, errors.Wrapf(err, "unable to get free port") + } + _, randomPort, err := net.SplitHostPort(l.Addr().String()) + if err != nil { + return nil, nil, errors.Wrapf(err, "unable to determine free port") + } + rp, err := strconv.Atoi(randomPort) + if err != nil { + return nil, nil, errors.Wrapf(err, "unable to convert random port to int") + } + logrus.Debug(fmt.Sprintf("Using random host port %s with container port %d", randomPort, p.Int())) + portBindings[p] = CreatePortBinding(rp, "") + continue + } if _, exists := ports[p]; !exists { ports[p] = struct{}{} } @@ -371,7 +423,6 @@ func imageData(c *cli.Context, runtime *libpod.Runtime, image string) (string, s // 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, imageName string, data *libpod.ImageData) (*createConfig, error) { - //imageName, imageID, data, err := imageData(c, runtime, image) var command []string var memoryLimit, memoryReservation, memorySwap, memoryKernel int64 var blkioWeight uint16 @@ -382,9 +433,9 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, command = c.Args()[1:] } - sysctl, err := convertStringSliceToMap(c.StringSlice("sysctl"), "=") + sysctl, err := validateSysctl(c.StringSlice("sysctl")) if err != nil { - return nil, errors.Wrapf(err, "sysctl values must be in the form of KEY=VALUE") + return nil, errors.Wrapf(err, "invalid value for sysctl") } groupAdd, err := stringSlicetoUint32Slice(c.StringSlice("group-add")) @@ -444,6 +495,12 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, if c.Bool("detach") && c.Bool("rm") { return nil, errors.Errorf("--rm and --detach can not be specified together") } + if c.Int64("cpu-period") != 0 && c.Float64("cpus") > 0 { + return nil, errors.Errorf("--cpu-period and --cpus cannot be set together") + } + if c.Int64("cpu-quota") != 0 && c.Float64("cpus") > 0 { + return nil, errors.Errorf("--cpu-quota and --cpus cannot be set together") + } utsMode := container.UTSMode(c.String("uts")) if !utsMode.Valid() { @@ -536,6 +593,29 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, if err != nil { return nil, errors.Wrapf(err, "unable to translate --shm-size") } + // Network + // Both --network and --net have default values of 'bridge' + // --net only overrides --network when --network is not explicitly + // set and --net is. + if c.IsSet("network") && c.IsSet("net") { + return nil, errors.Errorf("cannot use --network and --net together. use only --network instead") + } + networkMode := c.String("network") + if !c.IsSet("network") && c.IsSet("net") { + networkMode = c.String("net") + } + + // Verify the additional hosts are in correct format + for _, host := range c.StringSlice("add-host") { + if _, err := validateExtraHost(host); err != nil { + return nil, err + } + } + + // Check for . and dns-search domains + if libpod.StringInSlice(".", c.StringSlice("dns-search")) && len(c.StringSlice("dns-search")) > 1 { + return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'") + } config := &createConfig{ Runtime: runtime, @@ -553,6 +633,7 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, ExposedPorts: ports, GroupAdd: groupAdd, Hostname: c.String("hostname"), + HostAdd: c.StringSlice("add-host"), Image: imageName, ImageID: imageID, Interactive: c.Bool("interactive"), @@ -564,10 +645,10 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, LogDriverOpt: c.StringSlice("log-opt"), MacAddress: c.String("mac-address"), Name: c.String("name"), - Network: c.String("network"), + Network: networkMode, NetworkAlias: c.StringSlice("network-alias"), IpcMode: ipcMode, - NetMode: container.NetworkMode(c.String("network")), + NetMode: container.NetworkMode(networkMode), UtsMode: utsMode, PidMode: pidMode, Pod: c.String("pod"), @@ -582,12 +663,12 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, BlkioWeightDevice: c.StringSlice("blkio-weight-device"), CPUShares: c.Uint64("cpu-shares"), CPUPeriod: c.Uint64("cpu-period"), - CPUsetCPUs: c.String("cpu-period"), + CPUsetCPUs: c.String("cpuset-cpus"), 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"), + CPUs: c.Float64("cpus"), DeviceReadBps: c.StringSlice("device-read-bps"), DeviceReadIOps: c.StringSlice("device-read-iops"), DeviceWriteBps: c.StringSlice("device-write-bps"), @@ -609,7 +690,6 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, SigProxy: c.Bool("sig-proxy"), StopSignal: stopSignal, StopTimeout: c.Uint("stop-timeout"), - StorageOpts: c.StringSlice("storage-opt"), Sysctl: sysctl, Tmpfs: c.StringSlice("tmpfs"), Tty: tty, @@ -633,3 +713,12 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, } return config, nil } + +//CreatePortBinding takes port (int) and IP (string) and creates an array of portbinding structs +func CreatePortBinding(hostPort int, hostIP string) []nat.PortBinding { + pb := nat.PortBinding{ + HostPort: strconv.Itoa(hostPort), + } + pb.HostIP = hostIP + return []nat.PortBinding{pb} +} |