diff options
author | Sascha Grunert <sgrunert@redhat.com> | 2022-07-06 09:48:36 +0200 |
---|---|---|
committer | Sascha Grunert <sgrunert@redhat.com> | 2022-07-08 08:54:47 +0200 |
commit | a46f798831df06c472b288db7b34de8536a7ea5a (patch) | |
tree | c370fb0fc23b461691906e308b179a50e583228b /pkg/specgenutil | |
parent | 862cc42ddc11ff56b41be128182b748b0843dff3 (diff) | |
download | podman-a46f798831df06c472b288db7b34de8536a7ea5a.tar.gz podman-a46f798831df06c472b288db7b34de8536a7ea5a.tar.bz2 podman-a46f798831df06c472b288db7b34de8536a7ea5a.zip |
pkg: switch to golang native error wrapping
We now use the golang error wrapping format specifier `%w` instead of
the deprecated github.com/pkg/errors package.
[NO NEW TESTS NEEDED]
Signed-off-by: Sascha Grunert <sgrunert@redhat.com>
Diffstat (limited to 'pkg/specgenutil')
-rw-r--r-- | pkg/specgenutil/createparse.go | 5 | ||||
-rw-r--r-- | pkg/specgenutil/ports.go | 5 | ||||
-rw-r--r-- | pkg/specgenutil/specgen.go | 66 | ||||
-rw-r--r-- | pkg/specgenutil/util.go | 47 | ||||
-rw-r--r-- | pkg/specgenutil/volumes.go | 130 |
5 files changed, 128 insertions, 125 deletions
diff --git a/pkg/specgenutil/createparse.go b/pkg/specgenutil/createparse.go index 132f93771..373fb6faa 100644 --- a/pkg/specgenutil/createparse.go +++ b/pkg/specgenutil/createparse.go @@ -1,9 +1,10 @@ package specgenutil import ( + "errors" + "github.com/containers/common/pkg/config" "github.com/containers/podman/v4/pkg/domain/entities" - "github.com/pkg/errors" ) // validate determines if the flags and values given by the user are valid. things checked @@ -11,7 +12,7 @@ import ( func validate(c *entities.ContainerCreateOptions) error { var () if c.Rm && (c.Restart != "" && c.Restart != "no" && c.Restart != "on-failure") { - return errors.Errorf(`the --rm option conflicts with --restart, when the restartPolicy is not "" and "no"`) + return errors.New(`the --rm option conflicts with --restart, when the restartPolicy is not "" and "no"`) } if _, err := config.ParsePullPolicy(c.Pull); err != nil { diff --git a/pkg/specgenutil/ports.go b/pkg/specgenutil/ports.go index 6cc4de1ed..23ee9b4d3 100644 --- a/pkg/specgenutil/ports.go +++ b/pkg/specgenutil/ports.go @@ -1,8 +1,9 @@ package specgenutil import ( + "fmt" + "github.com/docker/go-connections/nat" - "github.com/pkg/errors" ) func verifyExpose(expose []string) error { @@ -15,7 +16,7 @@ func verifyExpose(expose []string) error { // if expose a port, the start and end port are the same _, _, err := nat.ParsePortRange(port) if err != nil { - return errors.Wrapf(err, "invalid range format for --expose: %s", expose) + return fmt.Errorf("invalid range format for --expose: %s: %w", expose, err) } } return nil diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index 34350579d..9a7d50947 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -2,6 +2,7 @@ package specgenutil import ( "encoding/json" + "errors" "fmt" "os" "strconv" @@ -22,7 +23,6 @@ import ( "github.com/docker/docker/opts" "github.com/docker/go-units" "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" ) func getCPULimits(c *entities.ContainerCreateOptions) *specs.LinuxCPU { @@ -78,7 +78,7 @@ func getIOLimits(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions) ( if b := c.BlkIOWeight; len(b) > 0 { u, err := strconv.ParseUint(b, 10, 16) if err != nil { - return nil, errors.Wrapf(err, "invalid value for blkio-weight") + return nil, fmt.Errorf("invalid value for blkio-weight: %w", err) } nu := uint16(u) io.Weight = &nu @@ -143,7 +143,7 @@ func getMemoryLimits(c *entities.ContainerCreateOptions) (*specs.LinuxMemory, er if m := c.Memory; len(m) > 0 { ml, err := units.RAMInBytes(m) if err != nil { - return nil, errors.Wrapf(err, "invalid value for memory") + return nil, fmt.Errorf("invalid value for memory: %w", err) } LimitToSwap(memory, c.MemorySwap, ml) hasLimits = true @@ -151,7 +151,7 @@ func getMemoryLimits(c *entities.ContainerCreateOptions) (*specs.LinuxMemory, er if m := c.MemoryReservation; len(m) > 0 { mr, err := units.RAMInBytes(m) if err != nil { - return nil, errors.Wrapf(err, "invalid value for memory") + return nil, fmt.Errorf("invalid value for memory: %w", err) } memory.Reservation = &mr hasLimits = true @@ -164,7 +164,7 @@ func getMemoryLimits(c *entities.ContainerCreateOptions) (*specs.LinuxMemory, er ms, err = units.RAMInBytes(m) memory.Swap = &ms if err != nil { - return nil, errors.Wrapf(err, "invalid value for memory") + return nil, fmt.Errorf("invalid value for memory: %w", err) } hasLimits = true } @@ -248,7 +248,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions if len(c.HealthCmd) > 0 { if c.NoHealthCheck { - return errors.New("Cannot specify both --no-healthcheck and --health-cmd") + return errors.New("cannot specify both --no-healthcheck and --health-cmd") } s.HealthConfig, err = makeHealthCheckFromCli(c.HealthCmd, c.HealthInterval, c.HealthRetries, c.HealthTimeout, c.HealthStartPeriod) if err != nil { @@ -318,7 +318,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions if len(c.PodIDFile) > 0 { if len(s.Pod) > 0 { - return errors.New("Cannot specify both --pod and --pod-id-file") + return errors.New("cannot specify both --pod and --pod-id-file") } podID, err := ReadPodIDFile(c.PodIDFile) if err != nil { @@ -357,7 +357,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions // any case. osEnv, err := envLib.ParseSlice(os.Environ()) if err != nil { - return errors.Wrap(err, "error parsing host environment variables") + return fmt.Errorf("error parsing host environment variables: %w", err) } if !s.EnvHost { @@ -390,7 +390,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions // LABEL VARIABLES labels, err := parse.GetAllLabels(c.LabelFile, c.Label) if err != nil { - return errors.Wrapf(err, "unable to process labels") + return fmt.Errorf("unable to process labels: %w", err) } if systemdUnit, exists := osEnv[systemdDefine.EnvVariable]; exists { @@ -414,7 +414,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions for _, annotation := range c.Annotation { splitAnnotation := strings.SplitN(annotation, "=", 2) if len(splitAnnotation) < 2 { - return errors.Errorf("Annotations must be formatted KEY=VALUE") + return errors.New("annotations must be formatted KEY=VALUE") } annotations[splitAnnotation[0]] = splitAnnotation[1] } @@ -427,7 +427,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions for _, opt := range c.StorageOpts { split := strings.SplitN(opt, "=", 2) if len(split) != 2 { - return errors.Errorf("storage-opt must be formatted KEY=VALUE") + return errors.New("storage-opt must be formatted KEY=VALUE") } opts[split[0]] = split[1] } @@ -459,7 +459,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions if c.ShmSize != "" { var m opts.MemBytes if err := m.Set(c.ShmSize); err != nil { - return errors.Wrapf(err, "unable to translate --shm-size") + return fmt.Errorf("unable to translate --shm-size: %w", err) } val := m.Value() s.ShmSize = &val @@ -531,7 +531,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions for _, unified := range c.CgroupConf { splitUnified := strings.SplitN(unified, "=", 2) if len(splitUnified) < 2 { - return errors.Errorf("--cgroup-conf must be formatted KEY=VALUE") + return errors.New("--cgroup-conf must be formatted KEY=VALUE") } unifieds[splitUnified[0]] = splitUnified[1] } @@ -608,7 +608,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions for _, ctl := range c.Sysctl { splitCtl := strings.SplitN(ctl, "=", 2) if len(splitCtl) < 2 { - return errors.Errorf("invalid sysctl value %q", ctl) + return fmt.Errorf("invalid sysctl value %q", ctl) } sysmap[splitCtl[0]] = splitCtl[1] } @@ -731,7 +731,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions } ul, err := units.ParseUlimit(u) if err != nil { - return errors.Wrapf(err, "ulimit option %q requires name=SOFT:HARD, failed to be parsed", u) + return fmt.Errorf("ulimit option %q requires name=SOFT:HARD, failed to be parsed: %w", u, err) } rl := specs.POSIXRlimit{ Type: ul.Name, @@ -745,7 +745,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions for _, o := range c.LogOptions { split := strings.SplitN(o, "=", 2) if len(split) < 2 { - return errors.Errorf("invalid log option %q", o) + return fmt.Errorf("invalid log option %q", o) } switch strings.ToLower(split[0]) { case "driver": @@ -782,19 +782,19 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions // No retries specified case 2: if strings.ToLower(splitRestart[0]) != "on-failure" { - return errors.Errorf("restart policy retries can only be specified with on-failure restart policy") + return errors.New("restart policy retries can only be specified with on-failure restart policy") } retries, err := strconv.Atoi(splitRestart[1]) if err != nil { - return errors.Wrapf(err, "error parsing restart policy retry count") + return fmt.Errorf("error parsing restart policy retry count: %w", err) } if retries < 0 { - return errors.Errorf("must specify restart policy retry count as a number greater than 0") + return errors.New("must specify restart policy retry count as a number greater than 0") } var retriesUint = uint(retries) s.RestartRetries = &retriesUint default: - return errors.Errorf("invalid restart policy: may specify retries at most once") + return errors.New("invalid restart policy: may specify retries at most once") } s.RestartPolicy = splitRestart[0] } @@ -869,7 +869,7 @@ func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, start } // Every healthcheck requires a command if len(cmdArr) == 0 { - return nil, errors.New("Must define a healthcheck command for all healthchecks") + return nil, errors.New("must define a healthcheck command for all healthchecks") } var concat string @@ -902,7 +902,7 @@ func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, start } intervalDuration, err := time.ParseDuration(interval) if err != nil { - return nil, errors.Wrapf(err, "invalid healthcheck-interval") + return nil, fmt.Errorf("invalid healthcheck-interval: %w", err) } hc.Interval = intervalDuration @@ -913,7 +913,7 @@ func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, start hc.Retries = int(retries) timeoutDuration, err := time.ParseDuration(timeout) if err != nil { - return nil, errors.Wrapf(err, "invalid healthcheck-timeout") + return nil, fmt.Errorf("invalid healthcheck-timeout: %w", err) } if timeoutDuration < time.Duration(1) { return nil, errors.New("healthcheck-timeout must be at least 1 second") @@ -922,7 +922,7 @@ func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, start startPeriodDuration, err := time.ParseDuration(startPeriod) if err != nil { - return nil, errors.Wrapf(err, "invalid healthcheck-start-period") + return nil, fmt.Errorf("invalid healthcheck-start-period: %w", err) } if startPeriodDuration < time.Duration(0) { return nil, errors.New("healthcheck-start-period must be 0 seconds or greater") @@ -1035,17 +1035,17 @@ func parseSecrets(secrets []string) ([]specgen.Secret, map[string]string, error) for _, val := range split { kv := strings.SplitN(val, "=", 2) if len(kv) < 2 { - return nil, nil, errors.Wrapf(secretParseError, "option %s must be in form option=value", val) + return nil, nil, fmt.Errorf("option %s must be in form option=value: %w", val, secretParseError) } switch kv[0] { case "source": source = kv[1] case "type": if secretType != "" { - return nil, nil, errors.Wrap(secretParseError, "cannot set more than one secret type") + return nil, nil, fmt.Errorf("cannot set more than one secret type: %w", secretParseError) } if kv[1] != "mount" && kv[1] != "env" { - return nil, nil, errors.Wrapf(secretParseError, "type %s is invalid", kv[1]) + return nil, nil, fmt.Errorf("type %s is invalid: %w", kv[1], secretParseError) } secretType = kv[1] case "target": @@ -1054,26 +1054,26 @@ func parseSecrets(secrets []string) ([]specgen.Secret, map[string]string, error) mountOnly = true mode64, err := strconv.ParseUint(kv[1], 8, 32) if err != nil { - return nil, nil, errors.Wrapf(secretParseError, "mode %s invalid", kv[1]) + return nil, nil, fmt.Errorf("mode %s invalid: %w", kv[1], secretParseError) } mode = uint32(mode64) case "uid", "UID": mountOnly = true uid64, err := strconv.ParseUint(kv[1], 10, 32) if err != nil { - return nil, nil, errors.Wrapf(secretParseError, "UID %s invalid", kv[1]) + return nil, nil, fmt.Errorf("UID %s invalid: %w", kv[1], secretParseError) } uid = uint32(uid64) case "gid", "GID": mountOnly = true gid64, err := strconv.ParseUint(kv[1], 10, 32) if err != nil { - return nil, nil, errors.Wrapf(secretParseError, "GID %s invalid", kv[1]) + return nil, nil, fmt.Errorf("GID %s invalid: %w", kv[1], secretParseError) } gid = uint32(gid64) default: - return nil, nil, errors.Wrapf(secretParseError, "option %s invalid", val) + return nil, nil, fmt.Errorf("option %s invalid: %w", val, secretParseError) } } @@ -1081,7 +1081,7 @@ func parseSecrets(secrets []string) ([]specgen.Secret, map[string]string, error) secretType = "mount" } if source == "" { - return nil, nil, errors.Wrapf(secretParseError, "no source found %s", val) + return nil, nil, fmt.Errorf("no source found %s: %w", val, secretParseError) } if secretType == "mount" { mountSecret := specgen.Secret{ @@ -1095,7 +1095,7 @@ func parseSecrets(secrets []string) ([]specgen.Secret, map[string]string, error) } if secretType == "env" { if mountOnly { - return nil, nil, errors.Wrap(secretParseError, "UID, GID, Mode options cannot be set with secret type env") + return nil, nil, fmt.Errorf("UID, GID, Mode options cannot be set with secret type env: %w", secretParseError) } if target == "" { target = source diff --git a/pkg/specgenutil/util.go b/pkg/specgenutil/util.go index fa2e90457..66d148672 100644 --- a/pkg/specgenutil/util.go +++ b/pkg/specgenutil/util.go @@ -1,6 +1,8 @@ package specgenutil import ( + "errors" + "fmt" "io/ioutil" "net" "os" @@ -10,7 +12,6 @@ import ( "github.com/containers/common/libnetwork/types" "github.com/containers/common/pkg/config" storageTypes "github.com/containers/storage/types" - "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -19,7 +20,7 @@ import ( func ReadPodIDFile(path string) (string, error) { content, err := ioutil.ReadFile(path) if err != nil { - return "", errors.Wrap(err, "error reading pod ID file") + return "", fmt.Errorf("error reading pod ID file: %w", err) } return strings.Split(string(content), "\n")[0], nil } @@ -50,7 +51,7 @@ func CreateExpose(expose []string) (map[uint16]string, error) { proto := "tcp" splitProto := strings.Split(e, "/") if len(splitProto) > 2 { - return nil, errors.Errorf("invalid expose format - protocol can only be specified once") + return nil, errors.New("invalid expose format - protocol can only be specified once") } else if len(splitProto) == 2 { proto = splitProto[1] } @@ -96,7 +97,7 @@ func CreatePortBindings(ports []string) ([]types.PortMapping, error) { case 2: proto = &(splitProto[1]) default: - return nil, errors.Errorf("invalid port format - protocol can only be specified once") + return nil, errors.New("invalid port format - protocol can only be specified once") } remainder := splitProto[0] @@ -111,23 +112,23 @@ func CreatePortBindings(ports []string) ([]types.PortMapping, error) { // We potentially have an IPv6 address haveV6 = true if !strings.HasPrefix(splitV6[0], "[") { - return nil, errors.Errorf("invalid port format - IPv6 addresses must be enclosed by []") + return nil, errors.New("invalid port format - IPv6 addresses must be enclosed by []") } if !strings.HasPrefix(splitV6[1], ":") { - return nil, errors.Errorf("invalid port format - IPv6 address must be followed by a colon (':')") + return nil, errors.New("invalid port format - IPv6 address must be followed by a colon (':')") } ipNoPrefix := strings.TrimPrefix(splitV6[0], "[") hostIP = &ipNoPrefix remainder = strings.TrimPrefix(splitV6[1], ":") default: - return nil, errors.Errorf("invalid port format - at most one IPv6 address can be specified in a --publish") + return nil, errors.New("invalid port format - at most one IPv6 address can be specified in a --publish") } splitPort := strings.Split(remainder, ":") switch len(splitPort) { case 1: if haveV6 { - return nil, errors.Errorf("invalid port format - must provide host and destination port if specifying an IP") + return nil, errors.New("invalid port format - must provide host and destination port if specifying an IP") } ctrPort = splitPort[0] case 2: @@ -135,13 +136,13 @@ func CreatePortBindings(ports []string) ([]types.PortMapping, error) { ctrPort = splitPort[1] case 3: if haveV6 { - return nil, errors.Errorf("invalid port format - when v6 address specified, must be [ipv6]:hostPort:ctrPort") + return nil, errors.New("invalid port format - when v6 address specified, must be [ipv6]:hostPort:ctrPort") } hostIP = &(splitPort[0]) hostPort = &(splitPort[1]) ctrPort = splitPort[2] default: - return nil, errors.Errorf("invalid port format - format is [[hostIP:]hostPort:]containerPort") + return nil, errors.New("invalid port format - format is [[hostIP:]hostPort:]containerPort") } newPort, err := parseSplitPort(hostIP, hostPort, ctrPort, proto) @@ -160,30 +161,30 @@ func CreatePortBindings(ports []string) ([]types.PortMapping, error) { func parseSplitPort(hostIP, hostPort *string, ctrPort string, protocol *string) (types.PortMapping, error) { newPort := types.PortMapping{} if ctrPort == "" { - return newPort, errors.Errorf("must provide a non-empty container port to publish") + return newPort, errors.New("must provide a non-empty container port to publish") } ctrStart, ctrLen, err := parseAndValidateRange(ctrPort) if err != nil { - return newPort, errors.Wrapf(err, "error parsing container port") + return newPort, fmt.Errorf("error parsing container port: %w", err) } newPort.ContainerPort = ctrStart newPort.Range = ctrLen if protocol != nil { if *protocol == "" { - return newPort, errors.Errorf("must provide a non-empty protocol to publish") + return newPort, errors.New("must provide a non-empty protocol to publish") } newPort.Protocol = *protocol } if hostIP != nil { if *hostIP == "" { - return newPort, errors.Errorf("must provide a non-empty container host IP to publish") + return newPort, errors.New("must provide a non-empty container host IP to publish") } else if *hostIP != "0.0.0.0" { // If hostIP is 0.0.0.0, leave it unset - CNI treats // 0.0.0.0 and empty differently, Docker does not. testIP := net.ParseIP(*hostIP) if testIP == nil { - return newPort, errors.Errorf("cannot parse %q as an IP address", *hostIP) + return newPort, fmt.Errorf("cannot parse %q as an IP address", *hostIP) } newPort.HostIP = testIP.String() } @@ -196,10 +197,10 @@ func parseSplitPort(hostIP, hostPort *string, ctrPort string, protocol *string) } else { hostStart, hostLen, err := parseAndValidateRange(*hostPort) if err != nil { - return newPort, errors.Wrapf(err, "error parsing host port") + return newPort, fmt.Errorf("error parsing host port: %w", err) } if hostLen != ctrLen { - return newPort, errors.Errorf("host and container port ranges have different lengths: %d vs %d", hostLen, ctrLen) + return newPort, fmt.Errorf("host and container port ranges have different lengths: %d vs %d", hostLen, ctrLen) } newPort.HostPort = hostStart } @@ -216,11 +217,11 @@ func parseSplitPort(hostIP, hostPort *string, ctrPort string, protocol *string) func parseAndValidateRange(portRange string) (uint16, uint16, error) { splitRange := strings.Split(portRange, "-") if len(splitRange) > 2 { - return 0, 0, errors.Errorf("invalid port format - port ranges are formatted as startPort-stopPort") + return 0, 0, errors.New("invalid port format - port ranges are formatted as startPort-stopPort") } if splitRange[0] == "" { - return 0, 0, errors.Errorf("port numbers cannot be negative") + return 0, 0, errors.New("port numbers cannot be negative") } startPort, err := parseAndValidatePort(splitRange[0]) @@ -231,14 +232,14 @@ func parseAndValidateRange(portRange string) (uint16, uint16, error) { var rangeLen uint16 = 1 if len(splitRange) == 2 { if splitRange[1] == "" { - return 0, 0, errors.Errorf("must provide ending number for port range") + return 0, 0, errors.New("must provide ending number for port range") } endPort, err := parseAndValidatePort(splitRange[1]) if err != nil { return 0, 0, err } if endPort <= startPort { - return 0, 0, errors.Errorf("the end port of a range must be higher than the start port - %d is not higher than %d", endPort, startPort) + return 0, 0, fmt.Errorf("the end port of a range must be higher than the start port - %d is not higher than %d", endPort, startPort) } // Our range is the total number of ports // involved, so we need to add 1 (8080:8081 is @@ -253,10 +254,10 @@ func parseAndValidateRange(portRange string) (uint16, uint16, error) { func parseAndValidatePort(port string) (uint16, error) { num, err := strconv.Atoi(port) if err != nil { - return 0, errors.Wrapf(err, "invalid port number") + return 0, fmt.Errorf("invalid port number: %w", err) } if num < 1 || num > 65535 { - return 0, errors.Errorf("port numbers must be between 1 and 65535 (inclusive), got %d", num) + return 0, fmt.Errorf("port numbers must be between 1 and 65535 (inclusive), got %d", num) } return uint16(num), nil } diff --git a/pkg/specgenutil/volumes.go b/pkg/specgenutil/volumes.go index 016166a20..e9fffdca9 100644 --- a/pkg/specgenutil/volumes.go +++ b/pkg/specgenutil/volumes.go @@ -2,6 +2,7 @@ package specgenutil import ( "encoding/csv" + "errors" "fmt" "path" "strings" @@ -11,14 +12,13 @@ import ( "github.com/containers/podman/v4/pkg/specgen" "github.com/containers/podman/v4/pkg/util" spec "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" ) var ( - errDuplicateDest = errors.Errorf("duplicate mount destination") - optionArgError = errors.Errorf("must provide an argument for option") - noDestError = errors.Errorf("must set volume destination") - errInvalidSyntax = errors.Errorf("incorrect mount format: should be --mount type=<bind|tmpfs|volume>,[src=<host-dir|volume-name>,]target=<ctr-dir>[,options]") + errDuplicateDest = errors.New("duplicate mount destination") + errOptionArg = errors.New("must provide an argument for option") + errNoDest = errors.New("must set volume destination") + errInvalidSyntax = errors.New("incorrect mount format: should be --mount type=<bind|tmpfs|volume>,[src=<host-dir|volume-name>,]target=<ctr-dir>[,options]") ) // Parse all volume-related options in the create config into a set of mounts @@ -50,20 +50,20 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo // Start with --volume. for dest, mount := range volumeMounts { if _, ok := unifiedMounts[dest]; ok { - return nil, nil, nil, nil, errors.Wrapf(errDuplicateDest, dest) + return nil, nil, nil, nil, fmt.Errorf("%v: %w", dest, errDuplicateDest) } unifiedMounts[dest] = mount } for dest, volume := range volumeVolumes { if _, ok := unifiedVolumes[dest]; ok { - return nil, nil, nil, nil, errors.Wrapf(errDuplicateDest, dest) + return nil, nil, nil, nil, fmt.Errorf("%v: %w", dest, errDuplicateDest) } unifiedVolumes[dest] = volume } // Now --tmpfs for dest, tmpfs := range tmpfsMounts { if _, ok := unifiedMounts[dest]; ok { - return nil, nil, nil, nil, errors.Wrapf(errDuplicateDest, dest) + return nil, nil, nil, nil, fmt.Errorf("%v: %w", dest, errDuplicateDest) } unifiedMounts[dest] = tmpfs } @@ -93,7 +93,7 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo allMounts := make(map[string]bool) testAndSet := func(dest string) error { if _, ok := allMounts[dest]; ok { - return errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest) + return fmt.Errorf("conflict at mount destination %v: %w", dest, errDuplicateDest) } allMounts[dest] = true return nil @@ -125,7 +125,7 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo if mount.Type == define.TypeBind { absSrc, err := specgen.ConvertWinMountPath(mount.Source) if err != nil { - return nil, nil, nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source) + return nil, nil, nil, nil, fmt.Errorf("error getting absolute path of %s: %w", mount.Source, err) } mount.Source = absSrc } @@ -199,7 +199,7 @@ func Mounts(mountFlag []string) (map[string]spec.Mount, map[string]*specgen.Name return nil, nil, nil, err } if _, ok := finalMounts[mount.Destination]; ok { - return nil, nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination) + return nil, nil, nil, fmt.Errorf("%v: %w", mount.Destination, errDuplicateDest) } finalMounts[mount.Destination] = mount case define.TypeTmpfs: @@ -208,7 +208,7 @@ func Mounts(mountFlag []string) (map[string]spec.Mount, map[string]*specgen.Name return nil, nil, nil, err } if _, ok := finalMounts[mount.Destination]; ok { - return nil, nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination) + return nil, nil, nil, fmt.Errorf("%v: %w", mount.Destination, errDuplicateDest) } finalMounts[mount.Destination] = mount case define.TypeDevpts: @@ -217,7 +217,7 @@ func Mounts(mountFlag []string) (map[string]spec.Mount, map[string]*specgen.Name return nil, nil, nil, err } if _, ok := finalMounts[mount.Destination]; ok { - return nil, nil, nil, errors.Wrapf(errDuplicateDest, mount.Destination) + return nil, nil, nil, fmt.Errorf("%v: %w", mount.Destination, errDuplicateDest) } finalMounts[mount.Destination] = mount case "image": @@ -226,7 +226,7 @@ func Mounts(mountFlag []string) (map[string]spec.Mount, map[string]*specgen.Name return nil, nil, nil, err } if _, ok := finalImageVolumes[volume.Destination]; ok { - return nil, nil, nil, errors.Wrapf(errDuplicateDest, volume.Destination) + return nil, nil, nil, fmt.Errorf("%v: %w", volume.Destination, errDuplicateDest) } finalImageVolumes[volume.Destination] = volume case "volume": @@ -235,11 +235,11 @@ func Mounts(mountFlag []string) (map[string]spec.Mount, map[string]*specgen.Name return nil, nil, nil, err } if _, ok := finalNamedVolumes[volume.Dest]; ok { - return nil, nil, nil, errors.Wrapf(errDuplicateDest, volume.Dest) + return nil, nil, nil, fmt.Errorf("%v: %w", volume.Dest, errDuplicateDest) } finalNamedVolumes[volume.Dest] = volume default: - return nil, nil, nil, errors.Errorf("invalid filesystem type %q", mountType) + return nil, nil, nil, fmt.Errorf("invalid filesystem type %q", mountType) } } @@ -261,7 +261,7 @@ func getBindMount(args []string) (spec.Mount, error) { newMount.Options = append(newMount.Options, "bind") case "readonly", "ro", "rw": if setRORW { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'readonly', 'ro', or 'rw' options more than once") + return newMount, fmt.Errorf("cannot pass 'readonly', 'ro', or 'rw' options more than once: %w", errOptionArg) } setRORW = true // Can be formatted as one of: @@ -288,26 +288,26 @@ func getBindMount(args []string) (spec.Mount, error) { newMount.Options = append(newMount.Options, "ro") } default: - return newMount, errors.Wrapf(optionArgError, "'readonly', 'ro', or 'rw' must be set to true or false, instead received %q", kv[1]) + return newMount, fmt.Errorf("'readonly', 'ro', or 'rw' must be set to true or false, instead received %q: %w", kv[1], errOptionArg) } default: - return newMount, errors.Wrapf(optionArgError, "badly formatted option %q", val) + return newMount, fmt.Errorf("badly formatted option %q: %w", val, errOptionArg) } case "nosuid", "suid": if setSuid { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once") + return newMount, fmt.Errorf("cannot pass 'nosuid' and 'suid' options more than once: %w", errOptionArg) } setSuid = true newMount.Options = append(newMount.Options, kv[0]) case "nodev", "dev": if setDev { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'nodev' and 'dev' options more than once") + return newMount, fmt.Errorf("cannot pass 'nodev' and 'dev' options more than once: %w", errOptionArg) } setDev = true newMount.Options = append(newMount.Options, kv[0]) case "noexec", "exec": if setExec { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'noexec' and 'exec' options more than once") + return newMount, fmt.Errorf("cannot pass 'noexec' and 'exec' options more than once: %w", errOptionArg) } setExec = true newMount.Options = append(newMount.Options, kv[0]) @@ -315,21 +315,21 @@ func getBindMount(args []string) (spec.Mount, error) { newMount.Options = append(newMount.Options, kv[0]) case "bind-propagation": if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) + return newMount, fmt.Errorf("%v: %w", kv[0], errOptionArg) } newMount.Options = append(newMount.Options, kv[1]) case "src", "source": if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) + return newMount, fmt.Errorf("%v: %w", kv[0], errOptionArg) } if len(kv[1]) == 0 { - return newMount, errors.Wrapf(optionArgError, "host directory cannot be empty") + return newMount, fmt.Errorf("host directory cannot be empty: %w", errOptionArg) } newMount.Source = kv[1] setSource = true case "target", "dst", "destination": if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) + return newMount, fmt.Errorf("%v: %w", kv[0], errOptionArg) } if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil { return newMount, err @@ -338,11 +338,11 @@ func getBindMount(args []string) (spec.Mount, error) { setDest = true case "relabel": if setRelabel { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'relabel' option more than once") + return newMount, fmt.Errorf("cannot pass 'relabel' option more than once: %w", errOptionArg) } setRelabel = true if len(kv) != 2 { - return newMount, errors.Wrapf(util.ErrBadMntOption, "%s mount option must be 'private' or 'shared'", kv[0]) + return newMount, fmt.Errorf("%s mount option must be 'private' or 'shared': %w", kv[0], util.ErrBadMntOption) } switch kv[1] { case "private": @@ -350,11 +350,11 @@ func getBindMount(args []string) (spec.Mount, error) { case "shared": newMount.Options = append(newMount.Options, "z") default: - return newMount, errors.Wrapf(util.ErrBadMntOption, "%s mount option must be 'private' or 'shared'", kv[0]) + return newMount, fmt.Errorf("%s mount option must be 'private' or 'shared': %w", kv[0], util.ErrBadMntOption) } case "U", "chown": if setOwnership { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'U' or 'chown' option more than once") + return newMount, fmt.Errorf("cannot pass 'U' or 'chown' option more than once: %w", errOptionArg) } ok, err := validChownFlag(val) if err != nil { @@ -375,12 +375,12 @@ func getBindMount(args []string) (spec.Mount, error) { // Since Docker ignores this option so shall we. continue default: - return newMount, errors.Wrapf(util.ErrBadMntOption, "%s", kv[0]) + return newMount, fmt.Errorf("%s: %w", kv[0], util.ErrBadMntOption) } } if !setDest { - return newMount, noDestError + return newMount, errNoDest } if !setSource { @@ -409,49 +409,49 @@ func getTmpfsMount(args []string) (spec.Mount, error) { switch kv[0] { case "tmpcopyup", "notmpcopyup": if setTmpcopyup { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'tmpcopyup' and 'notmpcopyup' options more than once") + return newMount, fmt.Errorf("cannot pass 'tmpcopyup' and 'notmpcopyup' options more than once: %w", errOptionArg) } setTmpcopyup = true newMount.Options = append(newMount.Options, kv[0]) case "ro", "rw": if setRORW { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'ro' and 'rw' options more than once") + return newMount, fmt.Errorf("cannot pass 'ro' and 'rw' options more than once: %w", errOptionArg) } setRORW = true newMount.Options = append(newMount.Options, kv[0]) case "nosuid", "suid": if setSuid { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once") + return newMount, fmt.Errorf("cannot pass 'nosuid' and 'suid' options more than once: %w", errOptionArg) } setSuid = true newMount.Options = append(newMount.Options, kv[0]) case "nodev", "dev": if setDev { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'nodev' and 'dev' options more than once") + return newMount, fmt.Errorf("cannot pass 'nodev' and 'dev' options more than once: %w", errOptionArg) } setDev = true newMount.Options = append(newMount.Options, kv[0]) case "noexec", "exec": if setExec { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'noexec' and 'exec' options more than once") + return newMount, fmt.Errorf("cannot pass 'noexec' and 'exec' options more than once: %w", errOptionArg) } setExec = true newMount.Options = append(newMount.Options, kv[0]) case "tmpfs-mode": if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) + return newMount, fmt.Errorf("%v: %w", kv[0], errOptionArg) } newMount.Options = append(newMount.Options, fmt.Sprintf("mode=%s", kv[1])) case "tmpfs-size": if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) + return newMount, fmt.Errorf("%v: %w", kv[0], errOptionArg) } newMount.Options = append(newMount.Options, fmt.Sprintf("size=%s", kv[1])) case "src", "source": - return newMount, errors.Errorf("source is not supported with tmpfs mounts") + return newMount, fmt.Errorf("source is not supported with tmpfs mounts") case "target", "dst", "destination": if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) + return newMount, fmt.Errorf("%v: %w", kv[0], errOptionArg) } if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil { return newMount, err @@ -460,7 +460,7 @@ func getTmpfsMount(args []string) (spec.Mount, error) { setDest = true case "U", "chown": if setOwnership { - return newMount, errors.Wrapf(optionArgError, "cannot pass 'U' or 'chown' option more than once") + return newMount, fmt.Errorf("cannot pass 'U' or 'chown' option more than once: %w", errOptionArg) } ok, err := validChownFlag(val) if err != nil { @@ -475,12 +475,12 @@ func getTmpfsMount(args []string) (spec.Mount, error) { // Since Docker ignores this option so shall we. continue default: - return newMount, errors.Wrapf(util.ErrBadMntOption, "%s", kv[0]) + return newMount, fmt.Errorf("%s: %w", kv[0], util.ErrBadMntOption) } } if !setDest { - return newMount, noDestError + return newMount, errNoDest } return newMount, nil @@ -502,7 +502,7 @@ func getDevptsMount(args []string) (spec.Mount, error) { newMount.Options = append(newMount.Options, val) case "target", "dst", "destination": if len(kv) == 1 { - return newMount, errors.Wrapf(optionArgError, kv[0]) + return newMount, fmt.Errorf("%v: %w", kv[0], errOptionArg) } if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil { return newMount, err @@ -510,12 +510,12 @@ func getDevptsMount(args []string) (spec.Mount, error) { newMount.Destination = unixPathClean(kv[1]) setDest = true default: - return newMount, errors.Wrapf(util.ErrBadMntOption, "%s", kv[0]) + return newMount, fmt.Errorf("%s: %w", kv[0], util.ErrBadMntOption) } } if !setDest { - return newMount, noDestError + return newMount, errNoDest } return newMount, nil @@ -536,38 +536,38 @@ func getNamedVolume(args []string) (*specgen.NamedVolume, error) { newVolume.Options = append(newVolume.Options, val) case "ro", "rw": if setRORW { - return nil, errors.Wrapf(optionArgError, "cannot pass 'ro' and 'rw' options more than once") + return nil, fmt.Errorf("cannot pass 'ro' and 'rw' options more than once: %w", errOptionArg) } setRORW = true newVolume.Options = append(newVolume.Options, kv[0]) case "nosuid", "suid": if setSuid { - return nil, errors.Wrapf(optionArgError, "cannot pass 'nosuid' and 'suid' options more than once") + return nil, fmt.Errorf("cannot pass 'nosuid' and 'suid' options more than once: %w", errOptionArg) } setSuid = true newVolume.Options = append(newVolume.Options, kv[0]) case "nodev", "dev": if setDev { - return nil, errors.Wrapf(optionArgError, "cannot pass 'nodev' and 'dev' options more than once") + return nil, fmt.Errorf("cannot pass 'nodev' and 'dev' options more than once: %w", errOptionArg) } setDev = true newVolume.Options = append(newVolume.Options, kv[0]) case "noexec", "exec": if setExec { - return nil, errors.Wrapf(optionArgError, "cannot pass 'noexec' and 'exec' options more than once") + return nil, fmt.Errorf("cannot pass 'noexec' and 'exec' options more than once: %w", errOptionArg) } setExec = true newVolume.Options = append(newVolume.Options, kv[0]) case "volume-label": - return nil, errors.Errorf("the --volume-label option is not presently implemented") + return nil, fmt.Errorf("the --volume-label option is not presently implemented") case "src", "source": if len(kv) == 1 { - return nil, errors.Wrapf(optionArgError, kv[0]) + return nil, fmt.Errorf("%v: %w", kv[0], errOptionArg) } newVolume.Name = kv[1] case "target", "dst", "destination": if len(kv) == 1 { - return nil, errors.Wrapf(optionArgError, kv[0]) + return nil, fmt.Errorf("%v: %w", kv[0], errOptionArg) } if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil { return nil, err @@ -576,7 +576,7 @@ func getNamedVolume(args []string) (*specgen.NamedVolume, error) { setDest = true case "U", "chown": if setOwnership { - return newVolume, errors.Wrapf(optionArgError, "cannot pass 'U' or 'chown' option more than once") + return newVolume, fmt.Errorf("cannot pass 'U' or 'chown' option more than once: %w", errOptionArg) } ok, err := validChownFlag(val) if err != nil { @@ -591,12 +591,12 @@ func getNamedVolume(args []string) (*specgen.NamedVolume, error) { // Since Docker ignores this option so shall we. continue default: - return nil, errors.Wrapf(util.ErrBadMntOption, "%s", kv[0]) + return nil, fmt.Errorf("%s: %w", kv[0], util.ErrBadMntOption) } } if !setDest { - return nil, noDestError + return nil, errNoDest } return newVolume, nil @@ -614,12 +614,12 @@ func getImageVolume(args []string) (*specgen.ImageVolume, error) { switch kv[0] { case "src", "source": if len(kv) == 1 { - return nil, errors.Wrapf(optionArgError, kv[0]) + return nil, fmt.Errorf("%v: %w", kv[0], errOptionArg) } newVolume.Source = kv[1] case "target", "dst", "destination": if len(kv) == 1 { - return nil, errors.Wrapf(optionArgError, kv[0]) + return nil, fmt.Errorf("%v: %w", kv[0], errOptionArg) } if err := parse.ValidateVolumeCtrDir(kv[1]); err != nil { return nil, err @@ -632,19 +632,19 @@ func getImageVolume(args []string) (*specgen.ImageVolume, error) { case "false": // Nothing to do. RO is default. default: - return nil, errors.Wrapf(util.ErrBadMntOption, "invalid rw value %q", kv[1]) + return nil, fmt.Errorf("invalid rw value %q: %w", kv[1], util.ErrBadMntOption) } case "consistency": // Often used on MACs and mistakenly on Linux platforms. // Since Docker ignores this option so shall we. continue default: - return nil, errors.Wrapf(util.ErrBadMntOption, "%s", kv[0]) + return nil, fmt.Errorf("%s: %w", kv[0], util.ErrBadMntOption) } } if len(newVolume.Source)*len(newVolume.Destination) == 0 { - return nil, errors.Errorf("must set source and destination for image volume") + return nil, errors.New("must set source and destination for image volume") } return newVolume, nil @@ -666,7 +666,7 @@ func getTmpfsMounts(tmpfsFlag []string) (map[string]spec.Mount, error) { } if _, ok := m[destPath]; ok { - return nil, errors.Wrapf(errDuplicateDest, destPath) + return nil, fmt.Errorf("%v: %w", destPath, errDuplicateDest) } mount := spec.Mount{ @@ -692,10 +692,10 @@ func validChownFlag(flag string) (bool, error) { case "false": return false, nil default: - return false, errors.Wrapf(optionArgError, "'U' or 'chown' must be set to true or false, instead received %q", kv[1]) + return false, fmt.Errorf("'U' or 'chown' must be set to true or false, instead received %q: %w", kv[1], errOptionArg) } default: - return false, errors.Wrapf(optionArgError, "badly formatted option %q", flag) + return false, fmt.Errorf("badly formatted option %q: %w", flag, errOptionArg) } return true, nil |