Merge pull request #44381 from thaJeztah/strings_cut
Replace uses of `strings.Split(N)` with `strings.Cut()`
This commit is contained in:
commit
3a5598affa
49 changed files with 323 additions and 405 deletions
|
@ -166,13 +166,13 @@ func (args Args) MatchKVList(key string, sources map[string]string) bool {
|
|||
}
|
||||
|
||||
for value := range fieldValues {
|
||||
testKV := strings.SplitN(value, "=", 2)
|
||||
testK, testV, hasValue := strings.Cut(value, "=")
|
||||
|
||||
v, ok := sources[testKV[0]]
|
||||
v, ok := sources[testK]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if len(testKV) == 2 && testKV[1] != v {
|
||||
if hasValue && testV != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,27 +105,27 @@ func GetTimestamp(value string, reference time.Time) (string, error) {
|
|||
// since := time.Unix(seconds, nanoseconds)
|
||||
//
|
||||
// returns seconds as defaultSeconds if value == ""
|
||||
func ParseTimestamps(value string, defaultSeconds int64) (int64, int64, error) {
|
||||
func ParseTimestamps(value string, defaultSeconds int64) (seconds int64, nanoseconds int64, err error) {
|
||||
if value == "" {
|
||||
return defaultSeconds, 0, nil
|
||||
}
|
||||
return parseTimestamp(value)
|
||||
}
|
||||
|
||||
func parseTimestamp(value string) (int64, int64, error) {
|
||||
sa := strings.SplitN(value, ".", 2)
|
||||
s, err := strconv.ParseInt(sa[0], 10, 64)
|
||||
func parseTimestamp(value string) (sec int64, nsec int64, err error) {
|
||||
s, n, ok := strings.Cut(value, ".")
|
||||
sec, err = strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return s, 0, err
|
||||
return sec, 0, err
|
||||
}
|
||||
if len(sa) != 2 {
|
||||
return s, 0, nil
|
||||
if !ok {
|
||||
return sec, 0, nil
|
||||
}
|
||||
n, err := strconv.ParseInt(sa[1], 10, 64)
|
||||
nsec, err = strconv.ParseInt(n, 10, 64)
|
||||
if err != nil {
|
||||
return s, n, err
|
||||
return sec, nsec, err
|
||||
}
|
||||
// should already be in nanoseconds but just in case convert n to nanoseconds
|
||||
n = int64(float64(n) * math.Pow(float64(10), float64(9-len(sa[1]))))
|
||||
return s, n, nil
|
||||
nsec = int64(float64(nsec) * math.Pow(float64(10), float64(9-len(n))))
|
||||
return sec, nsec, nil
|
||||
}
|
||||
|
|
|
@ -348,20 +348,19 @@ func DecodeSecurityOptions(opts []string) ([]SecurityOpt, error) {
|
|||
continue
|
||||
}
|
||||
secopt := SecurityOpt{}
|
||||
split := strings.Split(opt, ",")
|
||||
for _, s := range split {
|
||||
kv := strings.SplitN(s, "=", 2)
|
||||
if len(kv) != 2 {
|
||||
for _, s := range strings.Split(opt, ",") {
|
||||
k, v, ok := strings.Cut(s, "=")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid security option %q", s)
|
||||
}
|
||||
if kv[0] == "" || kv[1] == "" {
|
||||
if k == "" || v == "" {
|
||||
return nil, errors.New("invalid empty security option")
|
||||
}
|
||||
if kv[0] == "name" {
|
||||
secopt.Name = kv[1]
|
||||
if k == "name" {
|
||||
secopt.Name = v
|
||||
continue
|
||||
}
|
||||
secopt.Options = append(secopt.Options, KeyValue{Key: kv[0], Value: kv[1]})
|
||||
secopt.Options = append(secopt.Options, KeyValue{Key: k, Value: v})
|
||||
}
|
||||
so = append(so, secopt)
|
||||
}
|
||||
|
|
|
@ -46,8 +46,7 @@ func dispatchEnv(ctx context.Context, d dispatchRequest, c *instructions.EnvComm
|
|||
commitMessage.WriteString(" " + newVar)
|
||||
gotOne := false
|
||||
for i, envVar := range runConfig.Env {
|
||||
envParts := strings.SplitN(envVar, "=", 2)
|
||||
compareFrom := envParts[0]
|
||||
compareFrom, _, _ := strings.Cut(envVar, "=")
|
||||
if shell.EqualEnvKeys(compareFrom, name) {
|
||||
runConfig.Env[i] = newVar
|
||||
gotOne = true
|
||||
|
@ -408,9 +407,9 @@ func dispatchRun(ctx context.Context, d dispatchRequest, c *instructions.RunComm
|
|||
// These args are transparent so resulting image should be the same regardless
|
||||
// of the value.
|
||||
func prependEnvOnCmd(buildArgs *BuildArgs, buildArgVars []string, cmd strslice.StrSlice) strslice.StrSlice {
|
||||
var tmpBuildEnv []string
|
||||
tmpBuildEnv := make([]string, 0, len(buildArgVars))
|
||||
for _, env := range buildArgVars {
|
||||
key := strings.SplitN(env, "=", 2)[0]
|
||||
key, _, _ := strings.Cut(env, "=")
|
||||
if buildArgs.IsReferencedOrNotBuiltin(key) {
|
||||
tmpBuildEnv = append(tmpBuildEnv, env)
|
||||
}
|
||||
|
@ -418,7 +417,7 @@ func prependEnvOnCmd(buildArgs *BuildArgs, buildArgVars []string, cmd strslice.S
|
|||
|
||||
sort.Strings(tmpBuildEnv)
|
||||
tmpEnv := append([]string{fmt.Sprintf("|%d", len(tmpBuildEnv))}, tmpBuildEnv...)
|
||||
return strslice.StrSlice(append(tmpEnv, cmd...))
|
||||
return append(tmpEnv, cmd...)
|
||||
}
|
||||
|
||||
// CMD foo
|
||||
|
|
|
@ -97,15 +97,10 @@ func parseRemoteURL(remoteURL string) (gitRepo, error) {
|
|||
remoteURL = "https://" + remoteURL
|
||||
}
|
||||
|
||||
var fragment string
|
||||
if strings.HasPrefix(remoteURL, "git@") {
|
||||
// git@.. is not an URL, so cannot be parsed as URL
|
||||
parts := strings.SplitN(remoteURL, "#", 2)
|
||||
|
||||
repo.remote = parts[0]
|
||||
if len(parts) == 2 {
|
||||
fragment = parts[1]
|
||||
}
|
||||
var fragment string
|
||||
repo.remote, fragment, _ = strings.Cut(remoteURL, "#")
|
||||
repo.ref, repo.subdir = getRefAndSubdir(fragment)
|
||||
} else {
|
||||
u, err := url.Parse(remoteURL)
|
||||
|
@ -126,15 +121,11 @@ func parseRemoteURL(remoteURL string) (gitRepo, error) {
|
|||
}
|
||||
|
||||
func getRefAndSubdir(fragment string) (ref string, subdir string) {
|
||||
refAndDir := strings.SplitN(fragment, ":", 2)
|
||||
ref = "master"
|
||||
if len(refAndDir[0]) != 0 {
|
||||
ref = refAndDir[0]
|
||||
ref, subdir, _ = strings.Cut(fragment, ":")
|
||||
if ref == "" {
|
||||
ref = "master"
|
||||
}
|
||||
if len(refAndDir) > 1 && len(refAndDir[1]) != 0 {
|
||||
subdir = refAndDir[1]
|
||||
}
|
||||
return
|
||||
return ref, subdir
|
||||
}
|
||||
|
||||
func fetchArgs(remoteURL string, ref string) []string {
|
||||
|
|
|
@ -282,13 +282,12 @@ func (cli *Client) HTTPClient() *http.Client {
|
|||
// ParseHostURL parses a url string, validates the string is a host url, and
|
||||
// returns the parsed URL
|
||||
func ParseHostURL(host string) (*url.URL, error) {
|
||||
protoAddrParts := strings.SplitN(host, "://", 2)
|
||||
if len(protoAddrParts) == 1 {
|
||||
proto, addr, ok := strings.Cut(host, "://")
|
||||
if !ok || addr == "" {
|
||||
return nil, errors.Errorf("unable to parse docker host `%s`", host)
|
||||
}
|
||||
|
||||
var basePath string
|
||||
proto, addr := protoAddrParts[0], protoAddrParts[1]
|
||||
if proto == "tcp" {
|
||||
parsed, err := url.Parse("tcp://" + addr)
|
||||
if err != nil {
|
||||
|
|
|
@ -64,10 +64,10 @@ func parsePingResponse(cli *Client, resp serverResponse) (types.Ping, error) {
|
|||
ping.BuilderVersion = types.BuilderVersion(bv)
|
||||
}
|
||||
if si := resp.header.Get("Swarm"); si != "" {
|
||||
parts := strings.SplitN(si, "/", 2)
|
||||
state, role, _ := strings.Cut(si, "/")
|
||||
ping.SwarmStatus = &swarm.Status{
|
||||
NodeState: swarm.LocalNodeState(parts[0]),
|
||||
ControlAvailable: len(parts) == 2 && parts[1] == "manager",
|
||||
NodeState: swarm.LocalNodeState(state),
|
||||
ControlAvailable: role == "manager",
|
||||
}
|
||||
}
|
||||
err := cli.checkResponseErr(resp)
|
||||
|
|
|
@ -662,13 +662,11 @@ func loadListeners(cli *DaemonCli, serverConfig *apiserver.Config) ([]string, er
|
|||
|
||||
for i := 0; i < len(serverConfig.Hosts); i++ {
|
||||
protoAddr := serverConfig.Hosts[i]
|
||||
protoAddrParts := strings.SplitN(serverConfig.Hosts[i], "://", 2)
|
||||
if len(protoAddrParts) != 2 {
|
||||
proto, addr, ok := strings.Cut(protoAddr, "://")
|
||||
if !ok || addr == "" {
|
||||
return nil, fmt.Errorf("bad format %s, expected PROTO://ADDR", protoAddr)
|
||||
}
|
||||
|
||||
proto, addr := protoAddrParts[0], protoAddrParts[1]
|
||||
|
||||
// It's a bad idea to bind to TCP without tlsverify.
|
||||
authEnabled := serverConfig.TLSConfig != nil && serverConfig.TLSConfig.ClientAuth == tls.RequireAndVerifyClientCert
|
||||
if proto == "tcp" && !authEnabled {
|
||||
|
@ -719,7 +717,7 @@ func loadListeners(cli *DaemonCli, serverConfig *apiserver.Config) ([]string, er
|
|||
return nil, err
|
||||
}
|
||||
logrus.Debugf("Listener created for HTTP on %s (%s)", proto, addr)
|
||||
hosts = append(hosts, protoAddrParts[1])
|
||||
hosts = append(hosts, addr)
|
||||
cli.api.Accept(addr, ls...)
|
||||
}
|
||||
|
||||
|
|
|
@ -637,18 +637,18 @@ func parsePortMap(portMap nat.PortMap) ([]*api.PortConfig, error) {
|
|||
exposedPorts := make([]*api.PortConfig, 0, len(portMap))
|
||||
|
||||
for portProtocol, mapping := range portMap {
|
||||
parts := strings.SplitN(string(portProtocol), "/", 2)
|
||||
if len(parts) != 2 {
|
||||
p, proto, ok := strings.Cut(string(portProtocol), "/")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid port mapping: %s", portProtocol)
|
||||
}
|
||||
|
||||
port, err := strconv.ParseUint(parts[0], 10, 16)
|
||||
port, err := strconv.ParseUint(p, 10, 16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var protocol api.PortConfig_Protocol
|
||||
switch strings.ToLower(parts[1]) {
|
||||
switch strings.ToLower(proto) {
|
||||
case "tcp":
|
||||
protocol = api.ProtocolTCP
|
||||
case "udp":
|
||||
|
@ -656,7 +656,7 @@ func parsePortMap(portMap nat.PortMap) ([]*api.PortConfig, error) {
|
|||
case "sctp":
|
||||
protocol = api.ProtocolSCTP
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid protocol: %s", parts[1])
|
||||
return nil, fmt.Errorf("invalid protocol: %s", proto)
|
||||
}
|
||||
|
||||
for _, binding := range mapping {
|
||||
|
|
|
@ -114,11 +114,11 @@ func (e *executor) Describe(ctx context.Context) (*api.NodeDescription, error) {
|
|||
// parse []string labels into a map[string]string
|
||||
labels := map[string]string{}
|
||||
for _, l := range info.Labels {
|
||||
stringSlice := strings.SplitN(l, "=", 2)
|
||||
k, v, ok := strings.Cut(l, "=")
|
||||
// this will take the last value in the list for a given key
|
||||
// ideally, one shouldn't assign multiple values to the same key
|
||||
if len(stringSlice) > 1 {
|
||||
labels[stringSlice[0]] = stringSlice[1]
|
||||
if ok {
|
||||
labels[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,16 +38,16 @@ func merge(userConf, imageConf *containertypes.Config) error {
|
|||
} else {
|
||||
for _, imageEnv := range imageConf.Env {
|
||||
found := false
|
||||
imageEnvKey := strings.Split(imageEnv, "=")[0]
|
||||
imageEnvKey, _, _ := strings.Cut(imageEnv, "=")
|
||||
for _, userEnv := range userConf.Env {
|
||||
userEnvKey := strings.Split(userEnv, "=")[0]
|
||||
userEnvKey, _, _ := strings.Cut(userEnv, "=")
|
||||
if isWindows {
|
||||
// Case insensitive environment variables on Windows
|
||||
imageEnvKey = strings.ToUpper(imageEnvKey)
|
||||
userEnvKey = strings.ToUpper(userEnvKey)
|
||||
found = strings.EqualFold(imageEnvKey, userEnvKey)
|
||||
} else {
|
||||
found = imageEnvKey == userEnvKey
|
||||
}
|
||||
if imageEnvKey == userEnvKey {
|
||||
found = true
|
||||
if found {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,18 +107,18 @@ func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]lib
|
|||
if _, err := opts.ValidateExtraHost(extraHost); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parts := strings.SplitN(extraHost, ":", 2)
|
||||
host, ip, _ := strings.Cut(extraHost, ":")
|
||||
// If the IP Address is a string called "host-gateway", replace this
|
||||
// value with the IP address stored in the daemon level HostGatewayIP
|
||||
// config variable
|
||||
if parts[1] == opts.HostGatewayName {
|
||||
if ip == opts.HostGatewayName {
|
||||
gateway := daemon.configStore.HostGatewayIP.String()
|
||||
if gateway == "" {
|
||||
return nil, fmt.Errorf("unable to derive the IP value for host-gateway")
|
||||
}
|
||||
parts[1] = gateway
|
||||
ip = gateway
|
||||
}
|
||||
sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1]))
|
||||
sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(host, ip))
|
||||
}
|
||||
|
||||
if container.HostConfig.PortBindings != nil {
|
||||
|
|
|
@ -215,26 +215,27 @@ func parseSecurityOpt(container *container.Container, config *containertypes.Hos
|
|||
continue
|
||||
}
|
||||
|
||||
var con []string
|
||||
var k, v string
|
||||
var ok bool
|
||||
if strings.Contains(opt, "=") {
|
||||
con = strings.SplitN(opt, "=", 2)
|
||||
k, v, ok = strings.Cut(opt, "=")
|
||||
} else if strings.Contains(opt, ":") {
|
||||
con = strings.SplitN(opt, ":", 2)
|
||||
k, v, ok = strings.Cut(opt, ":")
|
||||
logrus.Warn("Security options with `:` as a separator are deprecated and will be completely unsupported in 17.04, use `=` instead.")
|
||||
}
|
||||
if len(con) != 2 {
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid --security-opt 1: %q", opt)
|
||||
}
|
||||
|
||||
switch con[0] {
|
||||
switch k {
|
||||
case "label":
|
||||
labelOpts = append(labelOpts, con[1])
|
||||
labelOpts = append(labelOpts, v)
|
||||
case "apparmor":
|
||||
container.AppArmorProfile = con[1]
|
||||
container.AppArmorProfile = v
|
||||
case "seccomp":
|
||||
container.SeccompProfile = con[1]
|
||||
container.SeccompProfile = v
|
||||
case "no-new-privileges":
|
||||
noNewPrivileges, err := strconv.ParseBool(con[1])
|
||||
noNewPrivileges, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid --security-opt 2: %q", opt)
|
||||
}
|
||||
|
@ -1360,8 +1361,8 @@ func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *
|
|||
return errors.Wrapf(err, "could not get container for %s", name)
|
||||
}
|
||||
for child.HostConfig.NetworkMode.IsContainer() {
|
||||
parts := strings.SplitN(string(child.HostConfig.NetworkMode), ":", 2)
|
||||
child, err = daemon.GetContainer(parts[1])
|
||||
cid := child.HostConfig.NetworkMode.ConnectedContainer()
|
||||
child, err = daemon.GetContainer(cid)
|
||||
if err != nil {
|
||||
if errdefs.IsNotFound(err) {
|
||||
// Trying to link to a non-existing container is not valid, and
|
||||
|
@ -1370,7 +1371,7 @@ func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *
|
|||
// image could not be found (see moby/moby#39823)
|
||||
err = errdefs.InvalidParameter(err)
|
||||
}
|
||||
return errors.Wrapf(err, "Could not get container for %s", parts[1])
|
||||
return errors.Wrapf(err, "could not get container for %s", cid)
|
||||
}
|
||||
}
|
||||
if child.HostConfig.NetworkMode.IsHost() {
|
||||
|
|
|
@ -57,9 +57,9 @@ func Scan(text string) (*events.Message, error) {
|
|||
}
|
||||
|
||||
attrs := make(map[string]string)
|
||||
for _, a := range strings.SplitN(md["attributes"], ", ", -1) {
|
||||
kv := strings.SplitN(a, "=", 2)
|
||||
attrs[kv[0]] = kv[1]
|
||||
for _, a := range strings.Split(md["attributes"], ", ") {
|
||||
k, v, _ := strings.Cut(a, "=")
|
||||
attrs[k] = v
|
||||
}
|
||||
|
||||
return &events.Message{
|
||||
|
|
|
@ -110,15 +110,16 @@ func InitFilter(home string, options []string, _ idtools.IdentityMapping) (graph
|
|||
return nil, fmt.Errorf("windowsfilter failed to create '%s': %v", home, err)
|
||||
}
|
||||
|
||||
storageOpt := make(map[string]string)
|
||||
storageOpt["size"] = defaultSandboxSize
|
||||
|
||||
for _, v := range options {
|
||||
opt := strings.SplitN(v, "=", 2)
|
||||
storageOpt[strings.ToLower(opt[0])] = opt[1]
|
||||
storageOpt := map[string]string{
|
||||
"size": defaultSandboxSize,
|
||||
}
|
||||
|
||||
storageOptions, err := parseStorageOpt(storageOpt)
|
||||
for _, o := range options {
|
||||
k, v, _ := strings.Cut(o, "=")
|
||||
storageOpt[strings.ToLower(k)] = v
|
||||
}
|
||||
|
||||
opts, err := parseStorageOpt(storageOpt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("windowsfilter failed to parse default storage options - %s", err)
|
||||
}
|
||||
|
@ -130,7 +131,7 @@ func InitFilter(home string, options []string, _ idtools.IdentityMapping) (graph
|
|||
},
|
||||
cache: make(map[string]string),
|
||||
ctr: graphdriver.NewRefCounter(&checker{}),
|
||||
defaultStorageOpts: storageOptions,
|
||||
defaultStorageOpts: opts,
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package zfs // import "github.com/docker/docker/daemon/graphdriver/zfs"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
|
@ -12,7 +11,7 @@ import (
|
|||
func checkRootdirFs(rootdir string) error {
|
||||
var buf unix.Statfs_t
|
||||
if err := unix.Statfs(rootdir, &buf); err != nil {
|
||||
return fmt.Errorf("Failed to access '%s': %s", rootdir, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// on FreeBSD buf.Fstypename contains ['z', 'f', 's', 0 ... ]
|
||||
|
@ -24,15 +23,14 @@ func checkRootdirFs(rootdir string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
const maxlen = 12
|
||||
|
||||
func getMountpoint(id string) string {
|
||||
maxlen := 12
|
||||
|
||||
// we need to preserve filesystem suffix
|
||||
suffix := strings.SplitN(id, "-", 2)
|
||||
|
||||
if len(suffix) > 1 {
|
||||
return id[:maxlen] + "-" + suffix[1]
|
||||
id, suffix, _ := strings.Cut(id, "-")
|
||||
id = id[:maxlen]
|
||||
if suffix != "" {
|
||||
// preserve filesystem suffix.
|
||||
id += "-" + suffix
|
||||
}
|
||||
|
||||
return id[:maxlen]
|
||||
return id
|
||||
}
|
||||
|
|
|
@ -206,9 +206,7 @@ func (daemon *Daemon) fillAPIInfo(v *types.Info) {
|
|||
cfg := daemon.configStore
|
||||
for _, host := range cfg.Hosts {
|
||||
// cnf.Hosts is normalized during startup, so should always have a scheme/proto
|
||||
h := strings.SplitN(host, "://", 2)
|
||||
proto := h[0]
|
||||
addr := h[1]
|
||||
proto, addr, _ := strings.Cut(host, "://")
|
||||
if proto != "tcp" {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -94,15 +94,15 @@ func (l *Link) ToEnv() []string {
|
|||
|
||||
if l.ChildEnvironment != nil {
|
||||
for _, v := range l.ChildEnvironment {
|
||||
parts := strings.SplitN(v, "=", 2)
|
||||
if len(parts) < 2 {
|
||||
name, val, ok := strings.Cut(v, "=")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// Ignore a few variables that are added during docker build (and not really relevant to linked containers)
|
||||
if parts[0] == "HOME" || parts[0] == "PATH" {
|
||||
if name == "HOME" || name == "PATH" {
|
||||
continue
|
||||
}
|
||||
env = append(env, fmt.Sprintf("%s_ENV_%s=%s", alias, parts[0], parts[1]))
|
||||
env = append(env, fmt.Sprintf("%s_ENV_%s=%s", alias, name, val))
|
||||
}
|
||||
}
|
||||
return env
|
||||
|
|
|
@ -234,8 +234,8 @@ func (j *Journal) Data() (map[string]string, error) {
|
|||
return m, fmt.Errorf("journald: error enumerating entry data: %w", syscall.Errno(-rc))
|
||||
}
|
||||
|
||||
kv := strings.SplitN(C.GoStringN((*C.char)(data), C.int(len)), "=", 2)
|
||||
m[kv[0]] = kv[1]
|
||||
k, v, _ := strings.Cut(C.GoStringN((*C.char)(data), C.int(len)), "=")
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,8 +59,8 @@ func (info *Info) ExtraAttributes(keyMod func(string) string) (map[string]string
|
|||
|
||||
envMapping := make(map[string]string)
|
||||
for _, e := range info.ContainerEnv {
|
||||
if kv := strings.SplitN(e, "=", 2); len(kv) == 2 {
|
||||
envMapping[kv[0]] = kv[1]
|
||||
if k, v, ok := strings.Cut(e, "="); ok {
|
||||
envMapping[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -241,8 +241,7 @@ func WithNamespaces(daemon *Daemon, c *container.Container) coci.SpecOpts {
|
|||
// network
|
||||
if !c.Config.NetworkDisabled {
|
||||
ns := specs.LinuxNamespace{Type: "network"}
|
||||
parts := strings.SplitN(string(c.HostConfig.NetworkMode), ":", 2)
|
||||
if parts[0] == "container" {
|
||||
if c.HostConfig.NetworkMode.IsContainer() {
|
||||
nc, err := daemon.getNetworkedContainer(c.ID, c.HostConfig.NetworkMode.ConnectedContainer())
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -279,29 +279,31 @@ func (daemon *Daemon) setWindowsCredentialSpec(c *container.Container, s *specs.
|
|||
// this doesn't seem like a great idea?
|
||||
credentialSpec := ""
|
||||
|
||||
// TODO(thaJeztah): extract validating and parsing SecurityOpt to a reusable function.
|
||||
for _, secOpt := range c.HostConfig.SecurityOpt {
|
||||
optSplits := strings.SplitN(secOpt, "=", 2)
|
||||
if len(optSplits) != 2 {
|
||||
k, v, ok := strings.Cut(secOpt, "=")
|
||||
if !ok {
|
||||
return errdefs.InvalidParameter(fmt.Errorf("invalid security option: no equals sign in supplied value %s", secOpt))
|
||||
}
|
||||
if !strings.EqualFold(optSplits[0], "credentialspec") {
|
||||
return errdefs.InvalidParameter(fmt.Errorf("security option not supported: %s", optSplits[0]))
|
||||
// FIXME(thaJeztah): options should not be case-insensitive
|
||||
if !strings.EqualFold(k, "credentialspec") {
|
||||
return errdefs.InvalidParameter(fmt.Errorf("security option not supported: %s", k))
|
||||
}
|
||||
|
||||
credSpecSplits := strings.SplitN(optSplits[1], "://", 2)
|
||||
if len(credSpecSplits) != 2 || credSpecSplits[1] == "" {
|
||||
scheme, value, ok := strings.Cut(v, "://")
|
||||
if !ok || value == "" {
|
||||
return errInvalidCredentialSpecSecOpt
|
||||
}
|
||||
value := credSpecSplits[1]
|
||||
|
||||
var err error
|
||||
switch strings.ToLower(credSpecSplits[0]) {
|
||||
switch strings.ToLower(scheme) {
|
||||
case "file":
|
||||
if credentialSpec, err = readCredentialSpecFile(c.ID, daemon.root, filepath.Clean(value)); err != nil {
|
||||
credentialSpec, err = readCredentialSpecFile(c.ID, daemon.root, filepath.Clean(value))
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
case "registry":
|
||||
if credentialSpec, err = readCredentialSpecRegistry(c.ID, value); err != nil {
|
||||
credentialSpec, err = readCredentialSpecRegistry(c.ID, value)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(err)
|
||||
}
|
||||
case "config":
|
||||
|
@ -439,44 +441,41 @@ func readCredentialSpecRegistry(id, name string) (string, error) {
|
|||
// This allows for staging on machines which do not have the necessary components.
|
||||
func readCredentialSpecFile(id, root, location string) (string, error) {
|
||||
if filepath.IsAbs(location) {
|
||||
return "", fmt.Errorf("invalid credential spec - file:// path cannot be absolute")
|
||||
return "", fmt.Errorf("invalid credential spec: file:// path cannot be absolute")
|
||||
}
|
||||
base := filepath.Join(root, credentialSpecFileLocation)
|
||||
full := filepath.Join(base, location)
|
||||
if !strings.HasPrefix(full, base) {
|
||||
return "", fmt.Errorf("invalid credential spec - file:// path must be under %s", base)
|
||||
return "", fmt.Errorf("invalid credential spec: file:// path must be under %s", base)
|
||||
}
|
||||
bcontents, err := os.ReadFile(full)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "credential spec for container %s could not be read from file %q", id, full)
|
||||
return "", errors.Wrapf(err, "failed to load credential spec for container %s", id)
|
||||
}
|
||||
return string(bcontents[:]), nil
|
||||
}
|
||||
|
||||
func setupWindowsDevices(devices []containertypes.DeviceMapping) (specDevices []specs.WindowsDevice, err error) {
|
||||
if len(devices) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, deviceMapping := range devices {
|
||||
devicePath := deviceMapping.PathOnHost
|
||||
if strings.HasPrefix(devicePath, "class/") {
|
||||
devicePath = strings.Replace(devicePath, "class/", "class://", 1)
|
||||
if strings.HasPrefix(deviceMapping.PathOnHost, "class/") {
|
||||
specDevices = append(specDevices, specs.WindowsDevice{
|
||||
ID: strings.TrimPrefix(deviceMapping.PathOnHost, "class/"),
|
||||
IDType: "class",
|
||||
})
|
||||
} else {
|
||||
idType, id, ok := strings.Cut(deviceMapping.PathOnHost, "://")
|
||||
if !ok {
|
||||
return nil, errors.Errorf("invalid device assignment path: '%s', must be 'class/ID' or 'IDType://ID'", deviceMapping.PathOnHost)
|
||||
}
|
||||
if idType == "" {
|
||||
return nil, errors.Errorf("invalid device assignment path: '%s', IDType cannot be empty", deviceMapping.PathOnHost)
|
||||
}
|
||||
specDevices = append(specDevices, specs.WindowsDevice{
|
||||
ID: id,
|
||||
IDType: idType,
|
||||
})
|
||||
}
|
||||
|
||||
srcParts := strings.SplitN(devicePath, "://", 2)
|
||||
if len(srcParts) != 2 {
|
||||
return nil, errors.Errorf("invalid device assignment path: '%s', must be 'class/ID' or 'IDType://ID'", deviceMapping.PathOnHost)
|
||||
}
|
||||
if srcParts[0] == "" {
|
||||
return nil, errors.Errorf("invalid device assignment path: '%s', IDType cannot be empty", deviceMapping.PathOnHost)
|
||||
}
|
||||
wd := specs.WindowsDevice{
|
||||
ID: srcParts[1],
|
||||
IDType: srcParts[0],
|
||||
}
|
||||
specDevices = append(specDevices, wd)
|
||||
}
|
||||
|
||||
return
|
||||
return specDevices, nil
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/fs"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
|
@ -87,7 +88,7 @@ func TestSetWindowsCredentialSpecInSpec(t *testing.T) {
|
|||
spec := &specs.Spec{}
|
||||
|
||||
err := daemon.setWindowsCredentialSpec(containerFactory(`file://C:\path\to\my\credspec.json`), spec)
|
||||
assert.ErrorContains(t, err, "invalid credential spec - file:// path cannot be absolute")
|
||||
assert.ErrorContains(t, err, "invalid credential spec: file:// path cannot be absolute")
|
||||
|
||||
assert.Check(t, spec.Windows == nil)
|
||||
})
|
||||
|
@ -96,7 +97,7 @@ func TestSetWindowsCredentialSpecInSpec(t *testing.T) {
|
|||
spec := &specs.Spec{}
|
||||
|
||||
err := daemon.setWindowsCredentialSpec(containerFactory(`file://..\credspec.json`), spec)
|
||||
assert.ErrorContains(t, err, fmt.Sprintf("invalid credential spec - file:// path must be under %s", credSpecsDir))
|
||||
assert.ErrorContains(t, err, fmt.Sprintf("invalid credential spec: file:// path must be under %s", credSpecsDir))
|
||||
|
||||
assert.Check(t, spec.Windows == nil)
|
||||
})
|
||||
|
@ -105,9 +106,8 @@ func TestSetWindowsCredentialSpecInSpec(t *testing.T) {
|
|||
spec := &specs.Spec{}
|
||||
|
||||
err := daemon.setWindowsCredentialSpec(containerFactory("file://i-dont-exist.json"), spec)
|
||||
assert.ErrorContains(t, err, fmt.Sprintf("credential spec for container %s could not be read from file", dummyContainerID))
|
||||
assert.ErrorContains(t, err, "The system cannot find")
|
||||
|
||||
assert.Check(t, is.ErrorContains(err, fmt.Sprintf("failed to load credential spec for container %s", dummyContainerID)))
|
||||
assert.Check(t, is.ErrorIs(err, os.ErrNotExist))
|
||||
assert.Check(t, spec.Windows == nil)
|
||||
})
|
||||
|
||||
|
|
|
@ -211,21 +211,21 @@ func (s *DockerCLIBuildSuite) TestBuildEnvironmentReplacementEnv(c *testing.T) {
|
|||
envCount := 0
|
||||
|
||||
for _, env := range envResult {
|
||||
parts := strings.SplitN(env, "=", 2)
|
||||
if parts[0] == "bar" {
|
||||
k, v, _ := strings.Cut(env, "=")
|
||||
if k == "bar" {
|
||||
found = true
|
||||
if parts[1] != "zzz" {
|
||||
c.Fatalf("Could not find replaced var for env `bar`: got %q instead of `zzz`", parts[1])
|
||||
if v != "zzz" {
|
||||
c.Fatalf("Could not find replaced var for env `bar`: got %q instead of `zzz`", v)
|
||||
}
|
||||
} else if strings.HasPrefix(parts[0], "env") {
|
||||
} else if strings.HasPrefix(k, "env") {
|
||||
envCount++
|
||||
if parts[1] != "zzz" {
|
||||
c.Fatalf("%s should be 'zzz' but instead its %q", parts[0], parts[1])
|
||||
if v != "zzz" {
|
||||
c.Fatalf("%s should be 'zzz' but instead its %q", k, v)
|
||||
}
|
||||
} else if strings.HasPrefix(parts[0], "env") {
|
||||
} else if strings.HasPrefix(k, "env") {
|
||||
envCount++
|
||||
if parts[1] != "foo" {
|
||||
c.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
|
||||
if v != "foo" {
|
||||
c.Fatalf("%s should be 'foo' but instead its %q", k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
"github.com/docker/docker/runconfig"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/assert/cmp"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
type DockerCLILinksSuite struct {
|
||||
|
@ -39,11 +39,8 @@ func (s *DockerCLILinksSuite) TestLinksInvalidContainerTarget(c *testing.T) {
|
|||
out, _, err := dockerCmdWithError("run", "--link", "bogus:alias", "busybox", "true")
|
||||
|
||||
// an invalid container target should produce an error
|
||||
assert.Assert(c, err != nil, "out: %s", out)
|
||||
// an invalid container target should produce an error
|
||||
// note: convert the output to lowercase first as the error string
|
||||
// capitalization was changed after API version 1.32
|
||||
assert.Assert(c, strings.Contains(strings.ToLower(out), "could not get container"))
|
||||
assert.Check(c, is.ErrorContains(err, "could not get container for bogus"))
|
||||
assert.Check(c, is.Contains(out, "could not get container"))
|
||||
}
|
||||
|
||||
func (s *DockerCLILinksSuite) TestLinksPingLinkedContainers(c *testing.T) {
|
||||
|
@ -163,7 +160,7 @@ func (s *DockerCLILinksSuite) TestLinksHostsFilesInject(c *testing.T) {
|
|||
readContainerFileWithExec(c, idOne, "/etc/hosts")
|
||||
contentTwo := readContainerFileWithExec(c, idTwo, "/etc/hosts")
|
||||
// Host is not present in updated hosts file
|
||||
assert.Assert(c, strings.Contains(string(contentTwo), "onetwo"))
|
||||
assert.Assert(c, is.Contains(string(contentTwo), "onetwo"))
|
||||
}
|
||||
|
||||
func (s *DockerCLILinksSuite) TestLinksUpdateOnRestart(c *testing.T) {
|
||||
|
@ -183,29 +180,29 @@ func (s *DockerCLILinksSuite) TestLinksUpdateOnRestart(c *testing.T) {
|
|||
return string(matches[1])
|
||||
}
|
||||
ip := getIP(content, "one")
|
||||
assert.Equal(c, ip, realIP)
|
||||
assert.Check(c, is.Equal(ip, realIP))
|
||||
|
||||
ip = getIP(content, "onetwo")
|
||||
assert.Equal(c, ip, realIP)
|
||||
assert.Check(c, is.Equal(ip, realIP))
|
||||
|
||||
dockerCmd(c, "restart", "one")
|
||||
realIP = inspectField(c, "one", "NetworkSettings.Networks.bridge.IPAddress")
|
||||
|
||||
content = readContainerFileWithExec(c, id, "/etc/hosts")
|
||||
ip = getIP(content, "one")
|
||||
assert.Equal(c, ip, realIP)
|
||||
assert.Check(c, is.Equal(ip, realIP))
|
||||
|
||||
ip = getIP(content, "onetwo")
|
||||
assert.Equal(c, ip, realIP)
|
||||
assert.Check(c, is.Equal(ip, realIP))
|
||||
}
|
||||
|
||||
func (s *DockerCLILinksSuite) TestLinksEnvs(c *testing.T) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
dockerCmd(c, "run", "-d", "-e", "e1=", "-e", "e2=v2", "-e", "e3=v3=v3", "--name=first", "busybox", "top")
|
||||
out, _ := dockerCmd(c, "run", "--name=second", "--link=first:first", "busybox", "env")
|
||||
assert.Assert(c, strings.Contains(out, "FIRST_ENV_e1=\n"))
|
||||
assert.Assert(c, strings.Contains(out, "FIRST_ENV_e2=v2"))
|
||||
assert.Assert(c, strings.Contains(out, "FIRST_ENV_e3=v3=v3"))
|
||||
assert.Assert(c, is.Contains(out, "FIRST_ENV_e1=\n"))
|
||||
assert.Assert(c, is.Contains(out, "FIRST_ENV_e2=v2"))
|
||||
assert.Assert(c, is.Contains(out, "FIRST_ENV_e3=v3=v3"))
|
||||
}
|
||||
|
||||
func (s *DockerCLILinksSuite) TestLinkShortDefinition(c *testing.T) {
|
||||
|
@ -230,16 +227,16 @@ func (s *DockerCLILinksSuite) TestLinksNetworkHostContainer(c *testing.T) {
|
|||
out, _, err := dockerCmdWithError("run", "--name", "should_fail", "--link", "host_container:tester", "busybox", "true")
|
||||
|
||||
// Running container linking to a container with --net host should have failed
|
||||
assert.Assert(c, err != nil, "out: %s", out)
|
||||
assert.Check(c, err != nil, "out: %s", out)
|
||||
// Running container linking to a container with --net host should have failed
|
||||
assert.Assert(c, strings.Contains(out, runconfig.ErrConflictHostNetworkAndLinks.Error()))
|
||||
assert.Check(c, is.Contains(out, runconfig.ErrConflictHostNetworkAndLinks.Error()))
|
||||
}
|
||||
|
||||
func (s *DockerCLILinksSuite) TestLinksEtcHostsRegularFile(c *testing.T) {
|
||||
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
||||
out, _ := dockerCmd(c, "run", "--net=host", "busybox", "ls", "-la", "/etc/hosts")
|
||||
// /etc/hosts should be a regular file
|
||||
assert.Assert(c, cmp.Regexp("^-.+\n$", out))
|
||||
assert.Assert(c, is.Regexp("^-.+\n$", out))
|
||||
}
|
||||
|
||||
func (s *DockerCLILinksSuite) TestLinksMultipleWithSameName(c *testing.T) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
|
@ -91,23 +90,20 @@ func WithVolume(target string) func(*TestContainerConfig) {
|
|||
// WithBind sets the bind mount of the container
|
||||
func WithBind(src, target string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
c.HostConfig.Binds = append(c.HostConfig.Binds, fmt.Sprintf("%s:%s", src, target))
|
||||
c.HostConfig.Binds = append(c.HostConfig.Binds, src+":"+target)
|
||||
}
|
||||
}
|
||||
|
||||
// WithTmpfs sets a target path in the container to a tmpfs
|
||||
func WithTmpfs(target string) func(config *TestContainerConfig) {
|
||||
// WithTmpfs sets a target path in the container to a tmpfs, with optional options
|
||||
// (separated with a colon).
|
||||
func WithTmpfs(targetAndOpts string) func(config *TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
if c.HostConfig.Tmpfs == nil {
|
||||
c.HostConfig.Tmpfs = make(map[string]string)
|
||||
}
|
||||
|
||||
spec := strings.SplitN(target, ":", 2)
|
||||
var opts string
|
||||
if len(spec) > 1 {
|
||||
opts = spec[1]
|
||||
}
|
||||
c.HostConfig.Tmpfs[spec[0]] = opts
|
||||
target, opts, _ := strings.Cut(targetAndOpts, ":")
|
||||
c.HostConfig.Tmpfs[target] = opts
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,8 @@ import "strings"
|
|||
func setupEnvironmentVariables(a []string) map[string]string {
|
||||
r := make(map[string]string)
|
||||
for _, s := range a {
|
||||
arr := strings.SplitN(s, "=", 2)
|
||||
if len(arr) == 2 {
|
||||
r[arr[0]] = arr[1]
|
||||
if k, v, ok := strings.Cut(s, "="); ok {
|
||||
r[k] = v
|
||||
}
|
||||
}
|
||||
return r
|
||||
|
|
|
@ -222,12 +222,12 @@ func newClient(scope string, kv string, addr string, config *store.Config, cache
|
|||
}
|
||||
}
|
||||
|
||||
store, err := libkv.NewStore(store.Backend(kv), addrs, config)
|
||||
s, err := libkv.NewStore(store.Backend(kv), addrs, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds := &datastore{scope: scope, store: store, active: true, watchCh: make(chan struct{}), sequential: sequential}
|
||||
ds := &datastore{scope: scope, store: s, active: true, watchCh: make(chan struct{}), sequential: sequential}
|
||||
if cached {
|
||||
ds.cache = newCache(ds)
|
||||
}
|
||||
|
|
|
@ -75,20 +75,19 @@ func Build(path, IP, hostname, domainname string, extraContent []Record) error {
|
|||
|
||||
content := bytes.NewBuffer(nil)
|
||||
if IP != "" {
|
||||
//set main record
|
||||
// set main record
|
||||
var mainRec Record
|
||||
mainRec.IP = IP
|
||||
// User might have provided a FQDN in hostname or split it across hostname
|
||||
// and domainname. We want the FQDN and the bare hostname.
|
||||
fqdn := hostname
|
||||
if domainname != "" {
|
||||
fqdn = fmt.Sprintf("%s.%s", fqdn, domainname)
|
||||
fqdn += "." + domainname
|
||||
}
|
||||
parts := strings.SplitN(fqdn, ".", 2)
|
||||
if len(parts) == 2 {
|
||||
mainRec.Hosts = fmt.Sprintf("%s %s", fqdn, parts[0])
|
||||
} else {
|
||||
mainRec.Hosts = fqdn
|
||||
mainRec.Hosts = fqdn
|
||||
|
||||
if hostName, _, ok := strings.Cut(fqdn, "."); ok {
|
||||
mainRec.Hosts += " " + hostName
|
||||
}
|
||||
if _, err := mainRec.WriteTo(content); err != nil {
|
||||
return err
|
||||
|
|
|
@ -30,7 +30,7 @@ const (
|
|||
// DNSServers A list of DNS servers associated with the endpoint
|
||||
DNSServers = Prefix + ".endpoint.dnsservers"
|
||||
|
||||
//EnableIPv6 constant represents enabling IPV6 at network level
|
||||
// EnableIPv6 constant represents enabling IPV6 at network level
|
||||
EnableIPv6 = Prefix + ".enable_ipv6"
|
||||
|
||||
// DriverMTU constant represents the MTU size for the network driver
|
||||
|
@ -106,27 +106,18 @@ func MakeKVClient(scope string) string {
|
|||
|
||||
// Key extracts the key portion of the label
|
||||
func Key(label string) (key string) {
|
||||
if kv := strings.SplitN(label, "=", 2); len(kv) > 0 {
|
||||
key = kv[0]
|
||||
}
|
||||
return
|
||||
key, _, _ = strings.Cut(label, "=")
|
||||
return key
|
||||
}
|
||||
|
||||
// Value extracts the value portion of the label
|
||||
func Value(label string) (value string) {
|
||||
if kv := strings.SplitN(label, "=", 2); len(kv) > 1 {
|
||||
value = kv[1]
|
||||
}
|
||||
return
|
||||
_, value, _ = strings.Cut(label, "=")
|
||||
return value
|
||||
}
|
||||
|
||||
// KeyValue decomposes the label in the (key,value) pair
|
||||
func KeyValue(label string) (key string, value string) {
|
||||
if kv := strings.SplitN(label, "=", 2); len(kv) > 0 {
|
||||
key = kv[0]
|
||||
if len(kv) > 1 {
|
||||
value = kv[1]
|
||||
}
|
||||
}
|
||||
return
|
||||
key, value, _ = strings.Cut(label, "=")
|
||||
return key, value
|
||||
}
|
||||
|
|
|
@ -110,19 +110,18 @@ func (sb *sandbox) updateHostsFile(ifaceIPs []string) error {
|
|||
// User might have provided a FQDN in hostname or split it across hostname
|
||||
// and domainname. We want the FQDN and the bare hostname.
|
||||
fqdn := sb.config.hostName
|
||||
mhost := sb.config.hostName
|
||||
if sb.config.domainName != "" {
|
||||
fqdn = fmt.Sprintf("%s.%s", fqdn, sb.config.domainName)
|
||||
fqdn += "." + sb.config.domainName
|
||||
}
|
||||
hosts := fqdn
|
||||
|
||||
parts := strings.SplitN(fqdn, ".", 2)
|
||||
if len(parts) == 2 {
|
||||
mhost = fmt.Sprintf("%s %s", fqdn, parts[0])
|
||||
if hostName, _, ok := strings.Cut(fqdn, "."); ok {
|
||||
hosts += " " + hostName
|
||||
}
|
||||
|
||||
var extraContent []etchosts.Record
|
||||
for _, ip := range ifaceIPs {
|
||||
extraContent = append(extraContent, etchosts.Record{Hosts: mhost, IP: ip})
|
||||
extraContent = append(extraContent, etchosts.Record{Hosts: hosts, IP: ip})
|
||||
}
|
||||
|
||||
sb.addHostsEntries(extraContent)
|
||||
|
|
|
@ -31,19 +31,17 @@ func (p *PoolsOpt) Set(value string) error {
|
|||
poolsDef := types.NetworkToSplit{}
|
||||
|
||||
for _, field := range fields {
|
||||
parts := strings.SplitN(field, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
// TODO(thaJeztah): this should not be case-insensitive.
|
||||
key, val, ok := strings.Cut(strings.ToLower(field), "=")
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid field '%s' must be a key=value pair", field)
|
||||
}
|
||||
|
||||
key := strings.ToLower(parts[0])
|
||||
value := strings.ToLower(parts[1])
|
||||
|
||||
switch key {
|
||||
case "base":
|
||||
poolsDef.Base = value
|
||||
poolsDef.Base = val
|
||||
case "size":
|
||||
size, err := strconv.Atoi(value)
|
||||
size, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid size value: %q (must be integer): %v", value, err)
|
||||
}
|
||||
|
|
10
opts/env.go
10
opts/env.go
|
@ -16,15 +16,15 @@ import (
|
|||
//
|
||||
// The only validation here is to check if name is empty, per #25099
|
||||
func ValidateEnv(val string) (string, error) {
|
||||
arr := strings.SplitN(val, "=", 2)
|
||||
if arr[0] == "" {
|
||||
k, _, ok := strings.Cut(val, "=")
|
||||
if k == "" {
|
||||
return "", errors.New("invalid environment variable: " + val)
|
||||
}
|
||||
if len(arr) > 1 {
|
||||
if ok {
|
||||
return val, nil
|
||||
}
|
||||
if envVal, ok := os.LookupEnv(arr[0]); ok {
|
||||
return arr[0] + "=" + envVal, nil
|
||||
if envVal, ok := os.LookupEnv(k); ok {
|
||||
return k + "=" + envVal, nil
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
|
|
@ -60,8 +60,7 @@ func ParseHost(defaultToTLS, defaultToUnixXDG bool, val string) (string, error)
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
socket := filepath.Join(runtimeDir, "docker.sock")
|
||||
host = "unix://" + socket
|
||||
host = "unix://" + filepath.Join(runtimeDir, "docker.sock")
|
||||
} else {
|
||||
host = DefaultHost
|
||||
}
|
||||
|
@ -77,23 +76,32 @@ func ParseHost(defaultToTLS, defaultToUnixXDG bool, val string) (string, error)
|
|||
|
||||
// parseDaemonHost parses the specified address and returns an address that will be used as the host.
|
||||
// Depending on the address specified, this may return one of the global Default* strings defined in hosts.go.
|
||||
func parseDaemonHost(addr string) (string, error) {
|
||||
addrParts := strings.SplitN(addr, "://", 2)
|
||||
if len(addrParts) == 1 && addrParts[0] != "" {
|
||||
addrParts = []string{"tcp", addrParts[0]}
|
||||
func parseDaemonHost(address string) (string, error) {
|
||||
proto, addr, ok := strings.Cut(address, "://")
|
||||
if !ok && proto != "" {
|
||||
addr = proto
|
||||
proto = "tcp"
|
||||
}
|
||||
|
||||
switch addrParts[0] {
|
||||
switch proto {
|
||||
case "tcp":
|
||||
return ParseTCPAddr(addr, DefaultTCPHost)
|
||||
return ParseTCPAddr(address, DefaultTCPHost)
|
||||
case "unix":
|
||||
return parseSimpleProtoAddr("unix", addrParts[1], DefaultUnixSocket)
|
||||
a, err := parseSimpleProtoAddr(proto, addr, DefaultUnixSocket)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "invalid bind address (%s)", address)
|
||||
}
|
||||
return a, nil
|
||||
case "npipe":
|
||||
return parseSimpleProtoAddr("npipe", addrParts[1], DefaultNamedPipe)
|
||||
a, err := parseSimpleProtoAddr(proto, addr, DefaultNamedPipe)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "invalid bind address (%s)", address)
|
||||
}
|
||||
return a, nil
|
||||
case "fd":
|
||||
return addr, nil
|
||||
return address, nil
|
||||
default:
|
||||
return "", errors.Errorf("invalid bind address (%s): unsupported proto '%s'", addr, addrParts[0])
|
||||
return "", errors.Errorf("invalid bind address (%s): unsupported proto '%s'", address, proto)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,9 +110,8 @@ func parseDaemonHost(addr string) (string, error) {
|
|||
// socket address, either using the address parsed from addr, or the contents of
|
||||
// defaultAddr if addr is a blank string.
|
||||
func parseSimpleProtoAddr(proto, addr, defaultAddr string) (string, error) {
|
||||
addr = strings.TrimPrefix(addr, proto+"://")
|
||||
if strings.Contains(addr, "://") {
|
||||
return "", errors.Errorf("invalid proto, expected %s: %s", proto, addr)
|
||||
return "", errors.Errorf("invalid %s address: %s", proto, addr)
|
||||
}
|
||||
if addr == "" {
|
||||
addr = defaultAddr
|
||||
|
@ -172,14 +179,14 @@ func parseTCPAddr(address string, strict bool) (*url.URL, error) {
|
|||
// ExtraHost is in the form of name:ip where the ip has to be a valid ip (IPv4 or IPv6).
|
||||
func ValidateExtraHost(val string) (string, error) {
|
||||
// allow for IPv6 addresses in extra hosts by only splitting on first ":"
|
||||
arr := strings.SplitN(val, ":", 2)
|
||||
if len(arr) != 2 || len(arr[0]) == 0 {
|
||||
name, ip, ok := strings.Cut(val, ":")
|
||||
if !ok || name == "" {
|
||||
return "", errors.Errorf("bad format for add-host: %q", val)
|
||||
}
|
||||
// Skip IPaddr validation for special "host-gateway" string
|
||||
if arr[1] != HostGatewayName {
|
||||
if _, err := ValidateIPAddress(arr[1]); err != nil {
|
||||
return "", errors.Errorf("invalid IP address in add-host: %q", arr[1])
|
||||
if ip != HostGatewayName {
|
||||
if _, err := ValidateIPAddress(ip); err != nil {
|
||||
return "", errors.Errorf("invalid IP address in add-host: %q", ip)
|
||||
}
|
||||
}
|
||||
return val, nil
|
||||
|
|
|
@ -85,6 +85,8 @@ func TestParseDockerDaemonHost(t *testing.T) {
|
|||
"[0:0:0:0:0:0:0:1]:5555/path": "invalid bind address ([0:0:0:0:0:0:0:1]:5555/path): should not contain a path element",
|
||||
"tcp://:5555/path": "invalid bind address (tcp://:5555/path): should not contain a path element",
|
||||
"localhost:5555/path": "invalid bind address (localhost:5555/path): should not contain a path element",
|
||||
"unix://tcp://127.0.0.1": "invalid bind address (unix://tcp://127.0.0.1): invalid unix address: tcp://127.0.0.1",
|
||||
"unix://unix://tcp://127.0.0.1": "invalid bind address (unix://unix://tcp://127.0.0.1): invalid unix address: unix://tcp://127.0.0.1",
|
||||
}
|
||||
valids := map[string]string{
|
||||
":": DefaultTCPHost,
|
||||
|
@ -130,7 +132,7 @@ func TestParseDockerDaemonHost(t *testing.T) {
|
|||
t.Errorf(`unexpected error: "%v"`, err)
|
||||
}
|
||||
if addr != expectedAddr {
|
||||
t.Errorf(`expected "%s", got "%s""`, expectedAddr, addr)
|
||||
t.Errorf(`expected "%s", got "%s"`, expectedAddr, addr)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -210,18 +212,6 @@ func TestParseTCP(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestParseInvalidUnixAddrInvalid(t *testing.T) {
|
||||
if _, err := parseSimpleProtoAddr("unix", "tcp://127.0.0.1", "unix:///var/run/docker.sock"); err == nil || err.Error() != "invalid proto, expected unix: tcp://127.0.0.1" {
|
||||
t.Fatalf("Expected an error, got %v", err)
|
||||
}
|
||||
if _, err := parseSimpleProtoAddr("unix", "unix://tcp://127.0.0.1", "/var/run/docker.sock"); err == nil || err.Error() != "invalid proto, expected unix: tcp://127.0.0.1" {
|
||||
t.Fatalf("Expected an error, got %v", err)
|
||||
}
|
||||
if v, err := parseSimpleProtoAddr("unix", "", "/var/run/docker.sock"); err != nil || v != "unix:///var/run/docker.sock" {
|
||||
t.Fatalf("Expected an %v, got %v", v, "unix:///var/run/docker.sock")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateExtraHosts(t *testing.T) {
|
||||
valid := []string{
|
||||
`myhost:192.168.0.1`,
|
||||
|
|
|
@ -162,12 +162,8 @@ func (opts *MapOpts) Set(value string) error {
|
|||
}
|
||||
value = v
|
||||
}
|
||||
vals := strings.SplitN(value, "=", 2)
|
||||
if len(vals) == 1 {
|
||||
(opts.values)[vals[0]] = ""
|
||||
} else {
|
||||
(opts.values)[vals[0]] = vals[1]
|
||||
}
|
||||
k, v, _ := strings.Cut(value, "=")
|
||||
(opts.values)[k] = v
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -29,27 +29,29 @@ func (o *RuntimeOpt) Name() string {
|
|||
|
||||
// Set validates and updates the list of Runtimes
|
||||
func (o *RuntimeOpt) Set(val string) error {
|
||||
parts := strings.SplitN(val, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
k, v, ok := strings.Cut(val, "=")
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid runtime argument: %s", val)
|
||||
}
|
||||
|
||||
parts[0] = strings.TrimSpace(parts[0])
|
||||
parts[1] = strings.TrimSpace(parts[1])
|
||||
if parts[0] == "" || parts[1] == "" {
|
||||
// TODO(thaJeztah): this should not accept spaces.
|
||||
k = strings.TrimSpace(k)
|
||||
v = strings.TrimSpace(v)
|
||||
if k == "" || v == "" {
|
||||
return fmt.Errorf("invalid runtime argument: %s", val)
|
||||
}
|
||||
|
||||
parts[0] = strings.ToLower(parts[0])
|
||||
if parts[0] == o.stockRuntimeName {
|
||||
// TODO(thaJeztah): this should not be case-insensitive.
|
||||
k = strings.ToLower(k)
|
||||
if k == o.stockRuntimeName {
|
||||
return fmt.Errorf("runtime name '%s' is reserved", o.stockRuntimeName)
|
||||
}
|
||||
|
||||
if _, ok := (*o.values)[parts[0]]; ok {
|
||||
return fmt.Errorf("runtime '%s' was already defined", parts[0])
|
||||
if _, ok := (*o.values)[k]; ok {
|
||||
return fmt.Errorf("runtime '%s' was already defined", k)
|
||||
}
|
||||
|
||||
(*o.values)[parts[0]] = types.Runtime{Path: parts[1]}
|
||||
(*o.values)[k] = types.Runtime{Path: v}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -26,27 +26,24 @@ func GetKernelVersion() (*VersionInfo, error) {
|
|||
|
||||
// getRelease uses `system_profiler SPSoftwareDataType` to get OSX kernel version
|
||||
func getRelease(osName string) (string, error) {
|
||||
var release string
|
||||
data := strings.Split(osName, "\n")
|
||||
for _, line := range data {
|
||||
for _, line := range strings.Split(osName, "\n") {
|
||||
if !strings.Contains(line, "Kernel Version") {
|
||||
continue
|
||||
}
|
||||
// It has the format like ' Kernel Version: Darwin 14.5.0'
|
||||
content := strings.SplitN(line, ":", 2)
|
||||
if len(content) != 2 {
|
||||
return "", fmt.Errorf("Kernel Version is invalid")
|
||||
_, ver, ok := strings.Cut(line, ":")
|
||||
if !ok {
|
||||
return "", fmt.Errorf("kernel Version is invalid")
|
||||
}
|
||||
|
||||
prettyNames := strings.SplitN(strings.TrimSpace(content[1]), " ", 2)
|
||||
|
||||
if len(prettyNames) != 2 {
|
||||
return "", fmt.Errorf("Kernel Version needs to be 'Darwin x.x.x' ")
|
||||
_, release, ok := strings.Cut(strings.TrimSpace(ver), " ")
|
||||
if !ok {
|
||||
return "", fmt.Errorf("kernel version needs to be 'Darwin x.x.x'")
|
||||
}
|
||||
release = prettyNames[1]
|
||||
return release, nil
|
||||
}
|
||||
|
||||
return release, nil
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func getSPSoftwareDataType() (string, error) {
|
||||
|
|
|
@ -5,7 +5,6 @@ package operatingsystem // import "github.com/docker/docker/pkg/parsers/operatin
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
@ -44,23 +43,22 @@ func getValueFromOsRelease(key string) (string, error) {
|
|||
osReleaseFile, err := os.Open(etcOsRelease)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return "", fmt.Errorf("Error opening %s: %v", etcOsRelease, err)
|
||||
return "", err
|
||||
}
|
||||
osReleaseFile, err = os.Open(altOsRelease)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error opening %s: %v", altOsRelease, err)
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
defer osReleaseFile.Close()
|
||||
|
||||
var value string
|
||||
keyWithTrailingEqual := key + "="
|
||||
scanner := bufio.NewScanner(osReleaseFile)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, keyWithTrailingEqual) {
|
||||
data := strings.SplitN(line, "=", 2)
|
||||
value = strings.Trim(data[1], `"' `) // remove leading/trailing quotes and whitespace
|
||||
if strings.HasPrefix(line, key+"=") {
|
||||
value = strings.TrimPrefix(line, key+"=")
|
||||
value = strings.Trim(value, `"' `) // remove leading/trailing quotes and whitespace
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,13 +9,14 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// ParseKeyValueOpt parses and validates the specified string as a key/value pair (key=value)
|
||||
func ParseKeyValueOpt(opt string) (string, string, error) {
|
||||
parts := strings.SplitN(opt, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return "", "", fmt.Errorf("Unable to parse key/value option: %s", opt)
|
||||
// ParseKeyValueOpt parses and validates the specified string as a key/value
|
||||
// pair (key=value).
|
||||
func ParseKeyValueOpt(opt string) (key string, value string, err error) {
|
||||
k, v, ok := strings.Cut(opt, "=")
|
||||
if !ok {
|
||||
return "", "", fmt.Errorf("unable to parse key/value option: %s", opt)
|
||||
}
|
||||
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
|
||||
return strings.TrimSpace(k), strings.TrimSpace(v), nil
|
||||
}
|
||||
|
||||
// ParseUintListMaximum parses and validates the specified string as the value
|
||||
|
@ -75,12 +76,12 @@ func parseUintList(val string, maximum int) (map[int]bool, error) {
|
|||
}
|
||||
availableInts[v] = true
|
||||
} else {
|
||||
split := strings.SplitN(r, "-", 2)
|
||||
min, err := strconv.Atoi(split[0])
|
||||
minS, maxS, _ := strings.Cut(r, "-")
|
||||
min, err := strconv.Atoi(minS)
|
||||
if err != nil {
|
||||
return nil, errInvalidFormat
|
||||
}
|
||||
max, err := strconv.Atoi(split[1])
|
||||
max, err := strconv.Atoi(maxS)
|
||||
if err != nil {
|
||||
return nil, errInvalidFormat
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
|
||||
func TestParseKeyValueOpt(t *testing.T) {
|
||||
invalids := map[string]string{
|
||||
"": "Unable to parse key/value option: ",
|
||||
"key": "Unable to parse key/value option: key",
|
||||
"": "unable to parse key/value option: ",
|
||||
"key": "unable to parse key/value option: key",
|
||||
}
|
||||
for invalid, expectedError := range invalids {
|
||||
if _, _, err := ParseKeyValueOpt(invalid); err == nil || err.Error() != expectedError {
|
||||
|
|
|
@ -62,13 +62,11 @@ func NewTarSumHash(r io.Reader, dc bool, v Version, tHash THash) (TarSum, error)
|
|||
|
||||
// NewTarSumForLabel creates a new TarSum using the provided TarSum version+hash label.
|
||||
func NewTarSumForLabel(r io.Reader, disableCompression bool, label string) (TarSum, error) {
|
||||
parts := strings.SplitN(label, "+", 2)
|
||||
if len(parts) != 2 {
|
||||
versionName, hashName, ok := strings.Cut(label, "+")
|
||||
if !ok {
|
||||
return nil, errors.New("tarsum label string should be of the form: {tarsum_version}+{hash_name}")
|
||||
}
|
||||
|
||||
versionName, hashName := parts[0], parts[1]
|
||||
|
||||
version, ok := tarSumVersionsByName[versionName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown TarSum version name: %q", versionName)
|
||||
|
|
|
@ -69,16 +69,12 @@ func (tsv Version) String() string {
|
|||
|
||||
// GetVersionFromTarsum returns the Version from the provided string.
|
||||
func GetVersionFromTarsum(tarsum string) (Version, error) {
|
||||
tsv := tarsum
|
||||
if strings.Contains(tarsum, "+") {
|
||||
tsv = strings.SplitN(tarsum, "+", 2)[0]
|
||||
versionName, _, _ := strings.Cut(tarsum, "+")
|
||||
version, ok := tarSumVersionsByName[versionName]
|
||||
if !ok {
|
||||
return -1, ErrNotVersion
|
||||
}
|
||||
for v, s := range tarSumVersions {
|
||||
if s == tsv {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
return -1, ErrNotVersion
|
||||
return version, nil
|
||||
}
|
||||
|
||||
// Errors that may be returned by functions in this package
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package plugin // import "github.com/docker/docker/plugin"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
|
@ -56,15 +55,13 @@ func WithEnv(env []string) CreateOpt {
|
|||
}
|
||||
}
|
||||
for _, line := range env {
|
||||
if pair := strings.SplitN(line, "=", 2); len(pair) > 1 {
|
||||
effectiveEnv[pair[0]] = pair[1]
|
||||
if k, v, ok := strings.Cut(line, "="); ok {
|
||||
effectiveEnv[k] = v
|
||||
}
|
||||
}
|
||||
p.PluginObj.Settings.Env = make([]string, len(effectiveEnv))
|
||||
i := 0
|
||||
p.PluginObj.Settings.Env = make([]string, 0, len(effectiveEnv))
|
||||
for key, value := range effectiveEnv {
|
||||
p.PluginObj.Settings.Env[i] = fmt.Sprintf("%s=%s", key, value)
|
||||
i++
|
||||
p.PluginObj.Settings.Env = append(p.PluginObj.Settings.Env, key+"="+value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,11 +92,11 @@ func (set *settable) isSettable(allowedSettableFields []string, settable []strin
|
|||
|
||||
func updateSettingsEnv(env *[]string, set *settable) {
|
||||
for i, e := range *env {
|
||||
if parts := strings.SplitN(e, "=", 2); parts[0] == set.name {
|
||||
(*env)[i] = fmt.Sprintf("%s=%s", set.name, set.value)
|
||||
if name, _, _ := strings.Cut(e, "="); name == set.name {
|
||||
(*env)[i] = set.name + "=" + set.value
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
*env = append(*env, fmt.Sprintf("%s=%s", set.name, set.value))
|
||||
*env = append(*env, set.name+"="+set.value)
|
||||
}
|
||||
|
|
|
@ -8,12 +8,8 @@ import (
|
|||
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]
|
||||
}
|
||||
k, v, _ := strings.Cut(value, "=")
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
return result
|
||||
|
|
|
@ -371,11 +371,9 @@ func (v *localVolume) saveOpts() error {
|
|||
|
||||
// getAddress finds out address/hostname from options
|
||||
func getAddress(opts string) string {
|
||||
optsList := strings.Split(opts, ",")
|
||||
for i := 0; i < len(optsList); i++ {
|
||||
if strings.HasPrefix(optsList[i], "addr=") {
|
||||
addr := strings.SplitN(optsList[i], "=", 2)[1]
|
||||
return addr
|
||||
for _, opt := range strings.Split(opts, ",") {
|
||||
if strings.HasPrefix(opt, "addr=") {
|
||||
return strings.TrimPrefix(opt, "addr=")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
|
@ -383,11 +381,9 @@ func getAddress(opts string) string {
|
|||
|
||||
// getPassword finds out a password from options
|
||||
func getPassword(opts string) string {
|
||||
optsList := strings.Split(opts, ",")
|
||||
for i := 0; i < len(optsList); i++ {
|
||||
if strings.HasPrefix(optsList[i], "password=") {
|
||||
passwd := strings.SplitN(optsList[i], "=", 2)[1]
|
||||
return passwd
|
||||
for _, opt := range strings.Split(opts, ",") {
|
||||
if strings.HasPrefix(opt, "password=") {
|
||||
return strings.TrimPrefix(opt, "password=")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
|
|
|
@ -23,18 +23,6 @@ type linuxParser struct {
|
|||
fi fileInfoProvider
|
||||
}
|
||||
|
||||
func linuxSplitRawSpec(raw string) ([]string, error) {
|
||||
if strings.Count(raw, ":") > 2 {
|
||||
return nil, errInvalidSpec(raw)
|
||||
}
|
||||
|
||||
arr := strings.SplitN(raw, ":", 3)
|
||||
if arr[0] == "" {
|
||||
return nil, errInvalidSpec(raw)
|
||||
}
|
||||
return arr, nil
|
||||
}
|
||||
|
||||
func linuxValidateNotRoot(p string) error {
|
||||
p = path.Clean(strings.ReplaceAll(p, `\`, `/`))
|
||||
if p == "/" {
|
||||
|
@ -214,9 +202,9 @@ func (p *linuxParser) ReadWrite(mode string) bool {
|
|||
}
|
||||
|
||||
func (p *linuxParser) ParseMountRaw(raw, volumeDriver string) (*MountPoint, error) {
|
||||
arr, err := linuxSplitRawSpec(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
arr := strings.SplitN(raw, ":", 4)
|
||||
if arr[0] == "" {
|
||||
return nil, errInvalidSpec(raw)
|
||||
}
|
||||
|
||||
var spec mount.Mount
|
||||
|
@ -334,26 +322,23 @@ func (p *linuxParser) ParseVolumesFrom(spec string) (string, string, error) {
|
|||
return "", "", fmt.Errorf("volumes-from specification cannot be an empty string")
|
||||
}
|
||||
|
||||
specParts := strings.SplitN(spec, ":", 2)
|
||||
id := specParts[0]
|
||||
mode := "rw"
|
||||
|
||||
if len(specParts) == 2 {
|
||||
mode = specParts[1]
|
||||
if !linuxValidMountMode(mode) {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
// For now don't allow propagation properties while importing
|
||||
// volumes from data container. These volumes will inherit
|
||||
// the same propagation property as of the original volume
|
||||
// in data container. This probably can be relaxed in future.
|
||||
if linuxHasPropagation(mode) {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
// Do not allow copy modes on volumes-from
|
||||
if _, isSet := getCopyMode(mode, p.DefaultCopyMode()); isSet {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
id, mode, _ := strings.Cut(spec, ":")
|
||||
if mode == "" {
|
||||
return id, "rw", nil
|
||||
}
|
||||
if !linuxValidMountMode(mode) {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
// For now don't allow propagation properties while importing
|
||||
// volumes from data container. These volumes will inherit
|
||||
// the same propagation property as of the original volume
|
||||
// in data container. This probably can be relaxed in future.
|
||||
if linuxHasPropagation(mode) {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
// Do not allow copy modes on volumes-from
|
||||
if _, isSet := getCopyMode(mode, p.DefaultCopyMode()); isSet {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
return id, mode, nil
|
||||
}
|
||||
|
|
|
@ -415,20 +415,18 @@ func (p *windowsParser) ParseVolumesFrom(spec string) (string, string, error) {
|
|||
return "", "", fmt.Errorf("volumes-from specification cannot be an empty string")
|
||||
}
|
||||
|
||||
specParts := strings.SplitN(spec, ":", 2)
|
||||
id := specParts[0]
|
||||
mode := "rw"
|
||||
id, mode, _ := strings.Cut(spec, ":")
|
||||
if mode == "" {
|
||||
return id, "rw", nil
|
||||
}
|
||||
|
||||
if len(specParts) == 2 {
|
||||
mode = specParts[1]
|
||||
if !windowsValidMountMode(mode) {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
if !windowsValidMountMode(mode) {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
|
||||
// Do not allow copy modes on volumes-from
|
||||
if _, isSet := getCopyMode(mode, p.DefaultCopyMode()); isSet {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
// Do not allow copy modes on volumes-from
|
||||
if _, isSet := getCopyMode(mode, p.DefaultCopyMode()); isSet {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
return id, mode, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue