Browse Source

api/types/container: use strings.Cut() and DRY

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 2 years ago
parent
commit
1bd486666b
1 changed files with 38 additions and 36 deletions
  1. 38 36
      api/types/container/hostconfig.go

+ 38 - 36
api/types/container/hostconfig.go

@@ -147,17 +147,14 @@ func (n NetworkMode) IsPrivate() bool {
 
 // IsContainer indicates whether container uses a container network stack.
 func (n NetworkMode) IsContainer() bool {
-	parts := strings.SplitN(string(n), ":", 2)
-	return len(parts) > 1 && parts[0] == "container"
+	_, ok := containerID(string(n))
+	return ok
 }
 
 // ConnectedContainer is the id of the container which network this container is connected to.
-func (n NetworkMode) ConnectedContainer() string {
-	parts := strings.SplitN(string(n), ":", 2)
-	if len(parts) > 1 {
-		return parts[1]
-	}
-	return ""
+func (n NetworkMode) ConnectedContainer() (idOrName string) {
+	idOrName, _ = containerID(string(n))
+	return idOrName
 }
 
 // UserDefined indicates user-created network
@@ -183,13 +180,16 @@ func (n UsernsMode) IsPrivate() bool {
 
 // Valid indicates whether the userns is valid.
 func (n UsernsMode) Valid() bool {
-	parts := strings.Split(string(n), ":")
-	switch mode := parts[0]; mode {
-	case "", "host":
+	if string(n) == "" {
+		return true
+	}
+
+	switch mode, _, _ := strings.Cut(string(n), ":"); mode {
+	case "host":
+		return true
 	default:
 		return false
 	}
-	return true
 }
 
 // CgroupSpec represents the cgroup to use for the container.
@@ -197,22 +197,19 @@ type CgroupSpec string
 
 // IsContainer indicates whether the container is using another container cgroup
 func (c CgroupSpec) IsContainer() bool {
-	parts := strings.SplitN(string(c), ":", 2)
-	return len(parts) > 1 && parts[0] == "container"
+	_, ok := containerID(string(c))
+	return ok
 }
 
 // Valid indicates whether the cgroup spec is valid.
 func (c CgroupSpec) Valid() bool {
-	return c.IsContainer() || c == ""
+	return c == "" || c.IsContainer()
 }
 
-// Container returns the name of the container whose cgroup will be used.
-func (c CgroupSpec) Container() string {
-	parts := strings.SplitN(string(c), ":", 2)
-	if len(parts) > 1 {
-		return parts[1]
-	}
-	return ""
+// Container returns the ID or name of the container whose cgroup will be used.
+func (c CgroupSpec) Container() (idOrName string) {
+	idOrName, _ = containerID(string(c))
+	return idOrName
 }
 
 // UTSMode represents the UTS namespace of the container.
@@ -254,32 +251,27 @@ func (n PidMode) IsHost() bool {
 
 // IsContainer indicates whether the container uses a container's pid namespace.
 func (n PidMode) IsContainer() bool {
-	parts := strings.SplitN(string(n), ":", 2)
-	return len(parts) > 1 && parts[0] == "container"
+	_, ok := containerID(string(n))
+	return ok
 }
 
 // Valid indicates whether the pid namespace is valid.
 func (n PidMode) Valid() bool {
-	parts := strings.Split(string(n), ":")
-	switch mode := parts[0]; mode {
+	mode, v, ok := strings.Cut(string(n), ":")
+	switch mode {
 	case "", "host":
+		return true
 	case "container":
-		if len(parts) != 2 || parts[1] == "" {
-			return false
-		}
+		return ok && v != ""
 	default:
 		return false
 	}
-	return true
 }
 
 // Container returns the name of the container whose pid namespace is going to be used.
-func (n PidMode) Container() string {
-	parts := strings.SplitN(string(n), ":", 2)
-	if len(parts) > 1 {
-		return parts[1]
-	}
-	return ""
+func (n PidMode) Container() (idOrName string) {
+	idOrName, _ = containerID(string(n))
+	return idOrName
 }
 
 // DeviceRequest represents a request for devices from a device driver.
@@ -463,3 +455,13 @@ type HostConfig struct {
 	// Run a custom init inside the container, if null, use the daemon's configured settings
 	Init *bool `json:",omitempty"`
 }
+
+// containerID splits "container:<ID|name>" values. It returns the container
+// ID or name, and whether an ID/name was found. It returns an empty string and
+// a "false" if the value does not have a "container:" prefix. Further validation
+// of the returned, including checking if the value is empty, should be handled
+// by the caller.
+func containerID(val string) (idOrName string, ok bool) {
+	k, idOrName, ok := strings.Cut(val, ":")
+	return idOrName, ok && k == "container"
+}