summaryrefslogtreecommitdiff
path: root/cmd/podman/shared
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman/shared')
-rw-r--r--cmd/podman/shared/create.go63
-rw-r--r--cmd/podman/shared/create_cli.go184
-rw-r--r--cmd/podman/shared/parse/parse.go353
-rw-r--r--cmd/podman/shared/parse/parse_test.go99
-rw-r--r--cmd/podman/shared/workers.go5
5 files changed, 123 insertions, 581 deletions
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go
index 48476e177..81566326b 100644
--- a/cmd/podman/shared/create.go
+++ b/cmd/podman/shared/create.go
@@ -25,7 +25,6 @@ import (
"github.com/docker/go-connections/nat"
"github.com/docker/go-units"
"github.com/google/shlex"
- spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
@@ -114,6 +113,7 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
}
}
}
+
createConfig, err := ParseCreateOpts(ctx, c, runtime, imageName, data)
if err != nil {
return nil, nil, err
@@ -123,7 +123,16 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
// at this point. The rest is done by WithOptions.
createConfig.HealthCheck = healthCheck
- ctr, err := CreateContainerFromCreateConfig(runtime, createConfig, ctx, nil)
+ // TODO: Should be able to return this from ParseCreateOpts
+ var pod *libpod.Pod
+ if createConfig.Pod != "" {
+ pod, err = runtime.LookupPod(createConfig.Pod)
+ if err != nil {
+ return nil, nil, errors.Wrapf(err, "error looking up pod to join")
+ }
+ }
+
+ ctr, err := CreateContainerFromCreateConfig(runtime, createConfig, ctx, pod)
if err != nil {
return nil, nil, err
}
@@ -139,7 +148,7 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.
return ctr, createConfig, nil
}
-func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error {
+func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string, runtime *libpod.Runtime) error {
var (
labelOpts []string
)
@@ -147,7 +156,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error {
if config.PidMode.IsHost() {
labelOpts = append(labelOpts, label.DisableSecOpt()...)
} else if config.PidMode.IsContainer() {
- ctr, err := config.Runtime.LookupContainer(config.PidMode.Container())
+ ctr, err := runtime.LookupContainer(config.PidMode.Container())
if err != nil {
return errors.Wrapf(err, "container %q not found", config.PidMode.Container())
}
@@ -161,7 +170,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string) error {
if config.IpcMode.IsHost() {
labelOpts = append(labelOpts, label.DisableSecOpt()...)
} else if config.IpcMode.IsContainer() {
- ctr, err := config.Runtime.LookupContainer(config.IpcMode.Container())
+ ctr, err := runtime.LookupContainer(config.IpcMode.Container())
if err != nil {
return errors.Wrapf(err, "container %q not found", config.IpcMode.Container())
}
@@ -331,18 +340,6 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
}
blkioWeight = uint16(u)
}
- var mountList []spec.Mount
- if mountList, err = parseMounts(c.StringArray("mount")); err != nil {
- return nil, err
- }
-
- if err = parseVolumes(c.StringArray("volume")); err != nil {
- return nil, err
- }
-
- if err = parseVolumesFrom(c.StringSlice("volumes-from")); err != nil {
- return nil, err
- }
tty := c.Bool("tty")
@@ -604,7 +601,6 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
memorySwappiness := c.Int64("memory-swappiness")
config := &cc.CreateConfig{
- Runtime: runtime,
Annotations: annotations,
BuiltinImgVolumes: ImageVolumes,
ConmonPidFile: c.String("conmon-pidfile"),
@@ -627,6 +623,8 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
HTTPProxy: c.Bool("http-proxy"),
NoHosts: c.Bool("no-hosts"),
IDMappings: idmappings,
+ Init: c.Bool("init"),
+ InitPath: c.String("init-path"),
Image: imageName,
ImageID: imageID,
Interactive: c.Bool("interactive"),
@@ -687,31 +685,18 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
Tty: tty,
User: user,
UsernsMode: usernsMode,
- Mounts: mountList,
+ MountsFlag: c.StringArray("mount"),
Volumes: c.StringArray("volume"),
WorkDir: workDir,
Rootfs: rootfs,
VolumesFrom: c.StringSlice("volumes-from"),
Syslog: c.Bool("syslog"),
}
- if c.Bool("init") {
- initPath := c.String("init-path")
- if initPath == "" {
- rtc, err := runtime.GetConfig()
- if err != nil {
- return nil, err
- }
- initPath = rtc.InitPath
- }
- if err := config.AddContainerInitBinary(initPath); err != nil {
- return nil, err
- }
- }
if config.Privileged {
config.LabelOpts = label.DisableSecOpt()
} else {
- if err := parseSecurityOpt(config, c.StringArray("security-opt")); err != nil {
+ if err := parseSecurityOpt(config, c.StringArray("security-opt"), runtime); err != nil {
return nil, err
}
}
@@ -726,18 +711,8 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
return config, nil
}
-type namespace interface {
- IsContainer() bool
- Container() string
-}
-
func CreateContainerFromCreateConfig(r *libpod.Runtime, createConfig *cc.CreateConfig, ctx context.Context, pod *libpod.Pod) (*libpod.Container, error) {
- runtimeSpec, err := cc.CreateConfigToOCISpec(createConfig)
- if err != nil {
- return nil, err
- }
-
- options, err := createConfig.GetContainerCreateOptions(r, pod)
+ runtimeSpec, options, err := createConfig.MakeContainerConfig(r, pod)
if err != nil {
return nil, err
}
diff --git a/cmd/podman/shared/create_cli.go b/cmd/podman/shared/create_cli.go
index 4f9cb1699..f731e8db5 100644
--- a/cmd/podman/shared/create_cli.go
+++ b/cmd/podman/shared/create_cli.go
@@ -2,15 +2,11 @@ package shared
import (
"fmt"
- "os"
- "path/filepath"
"strings"
"github.com/containers/libpod/cmd/podman/shared/parse"
cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/libpod/pkg/sysinfo"
- "github.com/docker/go-units"
- spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -78,186 +74,6 @@ func addWarning(warnings []string, msg string) []string {
return append(warnings, msg)
}
-// Format supported.
-// podman run --mount type=bind,src=/etc/resolv.conf,target=/etc/resolv.conf ...
-// podman run --mount type=tmpfs,target=/dev/shm ..
-func parseMounts(mounts []string) ([]spec.Mount, error) {
- // TODO(vrothberg): the manual parsing can be replaced with a regular expression
- // to allow a more robust parsing of the mount format and to give
- // precise errors regarding supported format versus suppored options.
- var mountList []spec.Mount
- errInvalidSyntax := errors.Errorf("incorrect mount format: should be --mount type=<bind|tmpfs>,[src=<host-dir>,]target=<ctr-dir>[,options]")
- for _, mount := range mounts {
- var tokenCount int
- var mountInfo spec.Mount
-
- arr := strings.SplitN(mount, ",", 2)
- if len(arr) < 2 {
- return nil, errors.Wrapf(errInvalidSyntax, "%q", mount)
- }
- kv := strings.Split(arr[0], "=")
- if kv[0] != "type" {
- return nil, errors.Wrapf(errInvalidSyntax, "%q", mount)
- }
- switch kv[1] {
- case "bind":
- mountInfo.Type = string(cc.TypeBind)
- case "tmpfs":
- mountInfo.Type = string(cc.TypeTmpfs)
- mountInfo.Source = string(cc.TypeTmpfs)
- mountInfo.Options = append(mountInfo.Options, []string{"rprivate", "noexec", "nosuid", "nodev", "size=65536k"}...)
-
- default:
- return nil, errors.Errorf("invalid filesystem type %q", kv[1])
- }
-
- tokens := strings.Split(arr[1], ",")
- for i, val := range tokens {
- if i == (tokenCount - 1) {
- //Parse tokens before options.
- break
- }
- kv := strings.Split(val, "=")
- switch kv[0] {
- case "ro", "nosuid", "nodev", "noexec":
- mountInfo.Options = append(mountInfo.Options, kv[0])
- case "shared", "rshared", "private", "rprivate", "slave", "rslave", "Z", "z":
- if mountInfo.Type != "bind" {
- return nil, errors.Errorf("%s can only be used with bind mounts", kv[0])
- }
- mountInfo.Options = append(mountInfo.Options, kv[0])
- case "tmpfs-mode":
- if mountInfo.Type != "tmpfs" {
- return nil, errors.Errorf("%s can only be used with tmpfs mounts", kv[0])
- }
- mountInfo.Options = append(mountInfo.Options, fmt.Sprintf("mode=%s", kv[1]))
- case "tmpfs-size":
- if mountInfo.Type != "tmpfs" {
- return nil, errors.Errorf("%s can only be used with tmpfs mounts", kv[0])
- }
- shmSize, err := units.FromHumanSize(kv[1])
- if err != nil {
- return nil, errors.Wrapf(err, "unable to translate tmpfs-size")
- }
-
- mountInfo.Options = append(mountInfo.Options, fmt.Sprintf("size=%d", shmSize))
-
- case "bind-propagation":
- if mountInfo.Type != "bind" {
- return nil, errors.Errorf("%s can only be used with bind mounts", kv[0])
- }
- mountInfo.Options = append(mountInfo.Options, kv[1])
- case "src", "source":
- if mountInfo.Type == "tmpfs" {
- return nil, errors.Errorf("cannot use src= on a tmpfs file system")
- }
- if err := ValidateVolumeHostDir(kv[1]); err != nil {
- return nil, err
- }
- mountInfo.Source = kv[1]
- case "target", "dst", "destination":
- if err := ValidateVolumeCtrDir(kv[1]); err != nil {
- return nil, err
- }
- mountInfo.Destination = kv[1]
- default:
- return nil, errors.Errorf("incorrect mount option : %s", kv[0])
- }
- }
- mountList = append(mountList, mountInfo)
- }
- return mountList, nil
-}
-
-func parseVolumes(volumes []string) error {
- 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 parseVolumesFrom(volumesFrom []string) error {
- for _, vol := range volumesFrom {
- arr := strings.SplitN(vol, ":", 2)
- if len(arr) == 2 {
- if strings.Contains(arr[1], "Z") || strings.Contains(arr[1], "private") || strings.Contains(arr[1], "slave") || strings.Contains(arr[1], "shared") {
- return errors.Errorf("invalid options %q, can only specify 'ro', 'rw', and 'z", arr[1])
- }
- if err := validateVolumeOpts(arr[1]); err != nil {
- return err
- }
- }
- }
- return nil
-}
-
-// ValidateVolumeHostDir ...
-func ValidateVolumeHostDir(hostDir string) error {
- if len(hostDir) == 0 {
- return errors.Errorf("host directory cannot be empty")
- }
- if filepath.IsAbs(hostDir) {
- if _, err := os.Stat(hostDir); err != nil {
- return errors.Wrapf(err, "error checking path %q", hostDir)
- }
- }
- // If hostDir is not an absolute path, that means the user wants to create a
- // named volume. This will be done later on in the code.
- return nil
-}
-
-// ValidateVolumeCtrDir ...
-func ValidateVolumeCtrDir(ctrDir string) error {
- if len(ctrDir) == 0 {
- return errors.Errorf("container directory cannot be empty")
- }
- if !filepath.IsAbs(ctrDir) {
- return errors.Errorf("invalid container path, must be an absolute 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":
- foundRWRO++
- if foundRWRO > 1 {
- return errors.Errorf("invalid options %q, can only specify 1 'rw' or 'ro' option", option)
- }
- case "z", "Z":
- foundLabelChange++
- if foundLabelChange > 1 {
- return errors.Errorf("invalid options %q, can only specify 1 'z' or 'Z' option", option)
- }
- case "private", "rprivate", "shared", "rshared", "slave", "rslave":
- foundRootPropagation++
- if foundRootPropagation > 1 {
- return errors.Errorf("invalid options %q, can only specify 1 '[r]shared', '[r]private' or '[r]slave' option", option)
- }
- default:
- return errors.Errorf("invalid option type %q", option)
- }
- }
- return nil
-}
-
func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, error) {
warnings := []string{}
sysInfo := sysinfo.New(true)
diff --git a/cmd/podman/shared/parse/parse.go b/cmd/podman/shared/parse/parse.go
index a3751835b..7bc2652cb 100644
--- a/cmd/podman/shared/parse/parse.go
+++ b/cmd/podman/shared/parse/parse.go
@@ -5,15 +5,10 @@ package parse
import (
"bufio"
- "bytes"
- "encoding/json"
"fmt"
- "io/ioutil"
"net"
"os"
- "path"
"regexp"
- "strconv"
"strings"
"github.com/pkg/errors"
@@ -72,77 +67,6 @@ func validateIPAddress(val string) (string, error) {
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)
-}
-
-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
-}
-
-// 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)
@@ -154,30 +78,6 @@ func ValidateDomain(val string) (string, error) {
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
@@ -241,259 +141,6 @@ func parseEnvFile(env map[string]string, filename string) error {
return scanner.Err()
}
-// 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
-}
-
-// 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) ([]*PortMapping, error) { //nolint
- var portMappings []*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) ([]*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 := Protocol_TCP
- if strings.ToLower(proto) == "udp" {
- protocol = Protocol_UDP
- }
-
- var ports []*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 := &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
-}
-
-// 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
-}
-
-// 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
-}
-
// ValidateFileName returns an error if filename contains ":"
// as it is currently not supported
func ValidateFileName(filename string) error {
diff --git a/cmd/podman/shared/parse/parse_test.go b/cmd/podman/shared/parse/parse_test.go
new file mode 100644
index 000000000..0a221c244
--- /dev/null
+++ b/cmd/podman/shared/parse/parse_test.go
@@ -0,0 +1,99 @@
+//nolint
+// most of these validate and parse functions have been taken from projectatomic/docker
+// and modified for cri-o
+package parse
+
+import (
+ "testing"
+)
+
+func TestValidateExtraHost(t *testing.T) {
+ type args struct {
+ val string
+ }
+ tests := []struct {
+ name string
+ args args
+ want string
+ wantErr bool
+ }{
+ //2001:0db8:85a3:0000:0000:8a2e:0370:7334
+ {name: "good-ipv4", args: args{val: "foobar:192.168.1.1"}, want: "foobar:192.168.1.1", wantErr: false},
+ {name: "bad-ipv4", args: args{val: "foobar:999.999.999.99"}, want: "", wantErr: true},
+ {name: "bad-ipv4", args: args{val: "foobar:999.999.999"}, want: "", wantErr: true},
+ {name: "noname-ipv4", args: args{val: "192.168.1.1"}, want: "", wantErr: true},
+ {name: "noname-ipv4", args: args{val: ":192.168.1.1"}, want: "", wantErr: true},
+ {name: "noip", args: args{val: "foobar:"}, want: "", wantErr: true},
+ {name: "noip", args: args{val: "foobar"}, want: "", wantErr: true},
+ {name: "good-ipv6", args: args{val: "foobar:2001:0db8:85a3:0000:0000:8a2e:0370:7334"}, want: "foobar:2001:0db8:85a3:0000:0000:8a2e:0370:7334", wantErr: false},
+ {name: "bad-ipv6", args: args{val: "foobar:0db8:85a3:0000:0000:8a2e:0370:7334"}, want: "", wantErr: true},
+ {name: "bad-ipv6", args: args{val: "foobar:0db8:85a3:0000:0000:8a2e:0370:7334.0000.0000.000"}, want: "", wantErr: true},
+ {name: "noname-ipv6", args: args{val: "2001:0db8:85a3:0000:0000:8a2e:0370:7334"}, want: "", wantErr: true},
+ {name: "noname-ipv6", args: args{val: ":2001:0db8:85a3:0000:0000:8a2e:0370:7334"}, want: "", wantErr: true},
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := ValidateExtraHost(tt.args.val)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("ValidateExtraHost() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if got != tt.want {
+ t.Errorf("ValidateExtraHost() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func Test_validateIPAddress(t *testing.T) {
+ type args struct {
+ val string
+ }
+ tests := []struct {
+ name string
+ args args
+ want string
+ wantErr bool
+ }{
+ {name: "ipv4-good", args: args{val: "192.168.1.1"}, want: "192.168.1.1", wantErr: false},
+ {name: "ipv4-bad", args: args{val: "192.168.1.1.1"}, want: "", wantErr: true},
+ {name: "ipv4-bad", args: args{val: "192."}, want: "", wantErr: true},
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := validateIPAddress(tt.args.val)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("validateIPAddress() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if got != tt.want {
+ t.Errorf("validateIPAddress() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func TestValidateFileName(t *testing.T) {
+ type args struct {
+ filename string
+ }
+ tests := []struct {
+ name string
+ args args
+ wantErr bool
+ }{
+ {name: "good", args: args{filename: "/som/rand/path"}, wantErr: false},
+ {name: "good", args: args{filename: "som/rand/path"}, wantErr: false},
+ {name: "good", args: args{filename: "/"}, wantErr: false},
+ {name: "bad", args: args{filename: "/:"}, wantErr: true},
+ {name: "bad", args: args{filename: ":/"}, wantErr: true},
+ {name: "bad", args: args{filename: "/some/rand:/path"}, wantErr: true},
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if err := ValidateFileName(tt.args.filename); (err != nil) != tt.wantErr {
+ t.Errorf("ValidateFileName() error = %v, wantErr %v", err, tt.wantErr)
+ }
+ })
+ }
+}
diff --git a/cmd/podman/shared/workers.go b/cmd/podman/shared/workers.go
index 112af89cc..b6e3f10e7 100644
--- a/cmd/podman/shared/workers.go
+++ b/cmd/podman/shared/workers.go
@@ -110,9 +110,14 @@ func (p *Pool) newWorker(slot int) {
func DefaultPoolSize(name string) int {
numCpus := runtime.NumCPU()
switch name {
+ case "init":
+ fallthrough
case "kill":
+ fallthrough
case "pause":
+ fallthrough
case "rm":
+ fallthrough
case "unpause":
if numCpus <= 3 {
return numCpus * 3