summaryrefslogtreecommitdiff
path: root/cmd/podman/create.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman/create.go')
-rw-r--r--cmd/podman/create.go131
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}
+}