Merge pull request #33299 from thaJeztah/explain-relation-between-paused-and-stopped

Improve description of Running and Paused booleans
diff --git a/client/container_wait.go b/client/container_wait.go
index edfa5d3..af4559c 100644
--- a/client/container_wait.go
+++ b/client/container_wait.go
@@ -31,7 +31,7 @@
 	}
 
 	resultC := make(chan container.ContainerWaitOKBody)
-	errC := make(chan error)
+	errC := make(chan error, 1)
 
 	query := url.Values{}
 	query.Set("condition", string(condition))
diff --git a/daemon/cluster/convert/network.go b/daemon/cluster/convert/network.go
index 0ce450b..143869a 100644
--- a/daemon/cluster/convert/network.go
+++ b/daemon/cluster/convert/network.go
@@ -29,7 +29,7 @@
 				IPv6Enabled: n.Spec.Ipv6Enabled,
 				Internal:    n.Spec.Internal,
 				Attachable:  n.Spec.Attachable,
-				Ingress:     n.Spec.Ingress,
+				Ingress:     IsIngressNetwork(n),
 				IPAMOptions: ipamFromGRPC(n.Spec.IPAM),
 				Scope:       netconst.SwarmScope,
 			},
@@ -165,7 +165,7 @@
 		IPAM:       ipam,
 		Internal:   spec.Internal,
 		Attachable: spec.Attachable,
-		Ingress:    spec.Ingress,
+		Ingress:    IsIngressNetwork(&n),
 		Labels:     n.Spec.Annotations.Labels,
 	}
 
@@ -225,3 +225,13 @@
 	}
 	return ns
 }
+
+// IsIngressNetwork check if the swarm network is an ingress network
+func IsIngressNetwork(n *swarmapi.Network) bool {
+	if n.Spec.Ingress {
+		return true
+	}
+	// Check if legacy defined ingress network
+	_, ok := n.Spec.Annotations.Labels["com.docker.swarm.internal"]
+	return ok && n.Spec.Annotations.Name == "ingress"
+}
diff --git a/daemon/cluster/executor/container/container.go b/daemon/cluster/executor/container/container.go
index 44d5f1d..bc98e53 100644
--- a/daemon/cluster/executor/container/container.go
+++ b/daemon/cluster/executor/container/container.go
@@ -18,6 +18,7 @@
 	enginemount "github.com/docker/docker/api/types/mount"
 	"github.com/docker/docker/api/types/network"
 	volumetypes "github.com/docker/docker/api/types/volume"
+	"github.com/docker/docker/daemon/cluster/convert"
 	executorpkg "github.com/docker/docker/daemon/cluster/executor"
 	clustertypes "github.com/docker/docker/daemon/cluster/provider"
 	"github.com/docker/go-connections/nat"
@@ -590,7 +591,7 @@
 		Labels:         na.Network.Spec.Annotations.Labels,
 		Internal:       na.Network.Spec.Internal,
 		Attachable:     na.Network.Spec.Attachable,
-		Ingress:        na.Network.Spec.Ingress,
+		Ingress:        convert.IsIngressNetwork(na.Network),
 		EnableIPv6:     na.Network.Spec.Ipv6Enabled,
 		CheckDuplicate: true,
 		Scope:          netconst.SwarmScope,
diff --git a/daemon/cluster/filters_test.go b/daemon/cluster/filters_test.go
index 6a67a10..fd0c8c3 100644
--- a/daemon/cluster/filters_test.go
+++ b/daemon/cluster/filters_test.go
@@ -51,7 +51,7 @@
 
 	for _, filter := range invalidFilters {
 		if _, err := newListSecretsFilters(filter); err == nil {
-			t.Fatalf("Should get an error for filter %s, while got nil", filter)
+			t.Fatalf("Should get an error for filter %v, while got nil", filter)
 		}
 	}
 }
@@ -96,7 +96,7 @@
 
 	for _, filter := range invalidFilters {
 		if _, err := newListConfigsFilters(filter); err == nil {
-			t.Fatalf("Should get an error for filter %s, while got nil", filter)
+			t.Fatalf("Should get an error for filter %v, while got nil", filter)
 		}
 	}
 }
diff --git a/opts/config.go b/opts/config.go
deleted file mode 100644
index 82fd2bc..0000000
--- a/opts/config.go
+++ /dev/null
@@ -1,98 +0,0 @@
-package opts
-
-import (
-	"encoding/csv"
-	"fmt"
-	"os"
-	"strconv"
-	"strings"
-
-	swarmtypes "github.com/docker/docker/api/types/swarm"
-)
-
-// ConfigOpt is a Value type for parsing configs
-type ConfigOpt struct {
-	values []*swarmtypes.ConfigReference
-}
-
-// Set a new config value
-func (o *ConfigOpt) Set(value string) error {
-	csvReader := csv.NewReader(strings.NewReader(value))
-	fields, err := csvReader.Read()
-	if err != nil {
-		return err
-	}
-
-	options := &swarmtypes.ConfigReference{
-		File: &swarmtypes.ConfigReferenceFileTarget{
-			UID:  "0",
-			GID:  "0",
-			Mode: 0444,
-		},
-	}
-
-	// support a simple syntax of --config foo
-	if len(fields) == 1 {
-		options.File.Name = fields[0]
-		options.ConfigName = fields[0]
-		o.values = append(o.values, options)
-		return nil
-	}
-
-	for _, field := range fields {
-		parts := strings.SplitN(field, "=", 2)
-		key := strings.ToLower(parts[0])
-
-		if len(parts) != 2 {
-			return fmt.Errorf("invalid field '%s' must be a key=value pair", field)
-		}
-
-		value := parts[1]
-		switch key {
-		case "source", "src":
-			options.ConfigName = value
-		case "target":
-			options.File.Name = value
-		case "uid":
-			options.File.UID = value
-		case "gid":
-			options.File.GID = value
-		case "mode":
-			m, err := strconv.ParseUint(value, 0, 32)
-			if err != nil {
-				return fmt.Errorf("invalid mode specified: %v", err)
-			}
-
-			options.File.Mode = os.FileMode(m)
-		default:
-			return fmt.Errorf("invalid field in config request: %s", key)
-		}
-	}
-
-	if options.ConfigName == "" {
-		return fmt.Errorf("source is required")
-	}
-
-	o.values = append(o.values, options)
-	return nil
-}
-
-// Type returns the type of this option
-func (o *ConfigOpt) Type() string {
-	return "config"
-}
-
-// String returns a string repr of this option
-func (o *ConfigOpt) String() string {
-	configs := []string{}
-	for _, config := range o.values {
-		repr := fmt.Sprintf("%s -> %s", config.ConfigName, config.File.Name)
-		configs = append(configs, repr)
-	}
-	return strings.Join(configs, ", ")
-}
-
-// Value returns the config requests
-func (o *ConfigOpt) Value() []*swarmtypes.ConfigReference {
-	return o.values
-}
diff --git a/opts/opts.go b/opts/opts.go
index f76f308..8d82f76 100644
--- a/opts/opts.go
+++ b/opts/opts.go
@@ -2,13 +2,11 @@
 
 import (
 	"fmt"
-	"math/big"
 	"net"
 	"path"
 	"regexp"
 	"strings"
 
-	"github.com/docker/docker/api/types/filters"
 	units "github.com/docker/go-units"
 )
 
@@ -236,15 +234,6 @@
 	return "", fmt.Errorf("%s is not an ip address", val)
 }
 
-// ValidateMACAddress validates a MAC address.
-func ValidateMACAddress(val string) (string, error) {
-	_, err := net.ParseMAC(strings.TrimSpace(val))
-	if err != nil {
-		return "", err
-	}
-	return val, nil
-}
-
 // ValidateDNSSearch validates domain for resolvconf search configuration.
 // A zero length domain is represented by a dot (.).
 func ValidateDNSSearch(val string) (string, error) {
@@ -274,114 +263,6 @@
 	return val, nil
 }
 
-// ValidateSysctl validates a sysctl and returns it.
-func ValidateSysctl(val string) (string, error) {
-	validSysctlMap := map[string]bool{
-		"kernel.msgmax":          true,
-		"kernel.msgmnb":          true,
-		"kernel.msgmni":          true,
-		"kernel.sem":             true,
-		"kernel.shmall":          true,
-		"kernel.shmmax":          true,
-		"kernel.shmmni":          true,
-		"kernel.shm_rmid_forced": true,
-	}
-	validSysctlPrefixes := []string{
-		"net.",
-		"fs.mqueue.",
-	}
-	arr := strings.Split(val, "=")
-	if len(arr) < 2 {
-		return "", fmt.Errorf("sysctl '%s' is not whitelisted", val)
-	}
-	if validSysctlMap[arr[0]] {
-		return val, nil
-	}
-
-	for _, vp := range validSysctlPrefixes {
-		if strings.HasPrefix(arr[0], vp) {
-			return val, nil
-		}
-	}
-	return "", fmt.Errorf("sysctl '%s' is not whitelisted", val)
-}
-
-// FilterOpt is a flag type for validating filters
-type FilterOpt struct {
-	filter filters.Args
-}
-
-// NewFilterOpt returns a new FilterOpt
-func NewFilterOpt() FilterOpt {
-	return FilterOpt{filter: filters.NewArgs()}
-}
-
-func (o *FilterOpt) String() string {
-	repr, err := filters.ToParam(o.filter)
-	if err != nil {
-		return "invalid filters"
-	}
-	return repr
-}
-
-// Set sets the value of the opt by parsing the command line value
-func (o *FilterOpt) Set(value string) error {
-	var err error
-	o.filter, err = filters.ParseFlag(value, o.filter)
-	return err
-}
-
-// Type returns the option type
-func (o *FilterOpt) Type() string {
-	return "filter"
-}
-
-// Value returns the value of this option
-func (o *FilterOpt) Value() filters.Args {
-	return o.filter
-}
-
-// NanoCPUs is a type for fixed point fractional number.
-type NanoCPUs int64
-
-// String returns the string format of the number
-func (c *NanoCPUs) String() string {
-	if *c == 0 {
-		return ""
-	}
-	return big.NewRat(c.Value(), 1e9).FloatString(3)
-}
-
-// Set sets the value of the NanoCPU by passing a string
-func (c *NanoCPUs) Set(value string) error {
-	cpus, err := ParseCPUs(value)
-	*c = NanoCPUs(cpus)
-	return err
-}
-
-// Type returns the type
-func (c *NanoCPUs) Type() string {
-	return "decimal"
-}
-
-// Value returns the value in int64
-func (c *NanoCPUs) Value() int64 {
-	return int64(*c)
-}
-
-// ParseCPUs takes a string ratio and returns an integer value of nano cpus
-func ParseCPUs(value string) (int64, error) {
-	cpu, ok := new(big.Rat).SetString(value)
-	if !ok {
-		return 0, fmt.Errorf("failed to parse %v as a rational number", value)
-	}
-	nano := cpu.Mul(cpu, big.NewRat(1e9, 1))
-	if !nano.IsInt() {
-		return 0, fmt.Errorf("value is too precise")
-	}
-	return nano.Num().Int64(), nil
-}
-
 // ParseLink parses and validates the specified string as a link format (name:alias)
 func ParseLink(val string) (string, string, error) {
 	if val == "" {
@@ -404,12 +285,6 @@
 	return arr[0], arr[1], nil
 }
 
-// ValidateLink validates that the specified string has a valid link format (containerName:alias).
-func ValidateLink(val string) (string, error) {
-	_, _, err := ParseLink(val)
-	return val, err
-}
-
 // MemBytes is a type for human readable memory bytes (like 128M, 2g, etc)
 type MemBytes int64
 
@@ -450,39 +325,3 @@
 	*m = MemBytes(val)
 	return err
 }
-
-// MemSwapBytes is a type for human readable memory bytes (like 128M, 2g, etc).
-// It differs from MemBytes in that -1 is valid and the default.
-type MemSwapBytes int64
-
-// Set sets the value of the MemSwapBytes by passing a string
-func (m *MemSwapBytes) Set(value string) error {
-	if value == "-1" {
-		*m = MemSwapBytes(-1)
-		return nil
-	}
-	val, err := units.RAMInBytes(value)
-	*m = MemSwapBytes(val)
-	return err
-}
-
-// Type returns the type
-func (m *MemSwapBytes) Type() string {
-	return "bytes"
-}
-
-// Value returns the value in int64
-func (m *MemSwapBytes) Value() int64 {
-	return int64(*m)
-}
-
-func (m *MemSwapBytes) String() string {
-	b := MemBytes(*m)
-	return b.String()
-}
-
-// UnmarshalJSON is the customized unmarshaler for MemSwapBytes
-func (m *MemSwapBytes) UnmarshalJSON(s []byte) error {
-	b := MemBytes(*m)
-	return b.UnmarshalJSON(s)
-}
diff --git a/opts/opts_test.go b/opts/opts_test.go
index c1e7735..1afe3c1 100644
--- a/opts/opts_test.go
+++ b/opts/opts_test.go
@@ -231,49 +231,6 @@
 	}
 }
 
-func TestValidateMACAddress(t *testing.T) {
-	if _, err := ValidateMACAddress(`92:d0:c6:0a:29:33`); err != nil {
-		t.Fatalf("ValidateMACAddress(`92:d0:c6:0a:29:33`) got %s", err)
-	}
-
-	if _, err := ValidateMACAddress(`92:d0:c6:0a:33`); err == nil {
-		t.Fatalf("ValidateMACAddress(`92:d0:c6:0a:33`) succeeded; expected failure on invalid MAC")
-	}
-
-	if _, err := ValidateMACAddress(`random invalid string`); err == nil {
-		t.Fatalf("ValidateMACAddress(`random invalid string`) succeeded; expected failure on invalid MAC")
-	}
-}
-
-func TestValidateLink(t *testing.T) {
-	valid := []string{
-		"name",
-		"dcdfbe62ecd0:alias",
-		"7a67485460b7642516a4ad82ecefe7f57d0c4916f530561b71a50a3f9c4e33da",
-		"angry_torvalds:linus",
-	}
-	invalid := map[string]string{
-		"":               "empty string specified for links",
-		"too:much:of:it": "bad format for links: too:much:of:it",
-	}
-
-	for _, link := range valid {
-		if _, err := ValidateLink(link); err != nil {
-			t.Fatalf("ValidateLink(`%q`) should succeed: error %q", link, err)
-		}
-	}
-
-	for link, expectedError := range invalid {
-		if _, err := ValidateLink(link); err == nil {
-			t.Fatalf("ValidateLink(`%q`) should have failed validation", link)
-		} else {
-			if !strings.Contains(err.Error(), expectedError) {
-				t.Fatalf("ValidateLink(`%q`) error should contain %q", link, expectedError)
-			}
-		}
-	}
-}
-
 func TestParseLink(t *testing.T) {
 	name, alias, err := ParseLink("name:alias")
 	if err != nil {
diff --git a/opts/throttledevice.go b/opts/throttledevice.go
deleted file mode 100644
index 65dd3eb..0000000
--- a/opts/throttledevice.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package opts
-
-import (
-	"fmt"
-	"strconv"
-	"strings"
-
-	"github.com/docker/docker/api/types/blkiodev"
-	"github.com/docker/go-units"
-)
-
-// ValidatorThrottleFctType defines a validator function that returns a validated struct and/or an error.
-type ValidatorThrottleFctType func(val string) (*blkiodev.ThrottleDevice, error)
-
-// ValidateThrottleBpsDevice validates that the specified string has a valid device-rate format.
-func ValidateThrottleBpsDevice(val string) (*blkiodev.ThrottleDevice, error) {
-	split := strings.SplitN(val, ":", 2)
-	if len(split) != 2 {
-		return nil, fmt.Errorf("bad format: %s", val)
-	}
-	if !strings.HasPrefix(split[0], "/dev/") {
-		return nil, fmt.Errorf("bad format for device path: %s", val)
-	}
-	rate, err := units.RAMInBytes(split[1])
-	if err != nil {
-		return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>[<unit>]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val)
-	}
-	if rate < 0 {
-		return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>[<unit>]. Number must be a positive integer. Unit is optional and can be kb, mb, or gb", val)
-	}
-
-	return &blkiodev.ThrottleDevice{
-		Path: split[0],
-		Rate: uint64(rate),
-	}, nil
-}
-
-// ValidateThrottleIOpsDevice validates that the specified string has a valid device-rate format.
-func ValidateThrottleIOpsDevice(val string) (*blkiodev.ThrottleDevice, error) {
-	split := strings.SplitN(val, ":", 2)
-	if len(split) != 2 {
-		return nil, fmt.Errorf("bad format: %s", val)
-	}
-	if !strings.HasPrefix(split[0], "/dev/") {
-		return nil, fmt.Errorf("bad format for device path: %s", val)
-	}
-	rate, err := strconv.ParseUint(split[1], 10, 64)
-	if err != nil {
-		return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
-	}
-	if rate < 0 {
-		return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
-	}
-
-	return &blkiodev.ThrottleDevice{
-		Path: split[0],
-		Rate: uint64(rate),
-	}, nil
-}
-
-// ThrottledeviceOpt defines a map of ThrottleDevices
-type ThrottledeviceOpt struct {
-	values    []*blkiodev.ThrottleDevice
-	validator ValidatorThrottleFctType
-}
-
-// NewThrottledeviceOpt creates a new ThrottledeviceOpt
-func NewThrottledeviceOpt(validator ValidatorThrottleFctType) ThrottledeviceOpt {
-	values := []*blkiodev.ThrottleDevice{}
-	return ThrottledeviceOpt{
-		values:    values,
-		validator: validator,
-	}
-}
-
-// Set validates a ThrottleDevice and sets its name as a key in ThrottledeviceOpt
-func (opt *ThrottledeviceOpt) Set(val string) error {
-	var value *blkiodev.ThrottleDevice
-	if opt.validator != nil {
-		v, err := opt.validator(val)
-		if err != nil {
-			return err
-		}
-		value = v
-	}
-	(opt.values) = append((opt.values), value)
-	return nil
-}
-
-// String returns ThrottledeviceOpt values as a string.
-func (opt *ThrottledeviceOpt) String() string {
-	var out []string
-	for _, v := range opt.values {
-		out = append(out, v.String())
-	}
-
-	return fmt.Sprintf("%v", out)
-}
-
-// GetList returns a slice of pointers to ThrottleDevices.
-func (opt *ThrottledeviceOpt) GetList() []*blkiodev.ThrottleDevice {
-	var throttledevice []*blkiodev.ThrottleDevice
-	throttledevice = append(throttledevice, opt.values...)
-
-	return throttledevice
-}
-
-// Type returns the option type
-func (opt *ThrottledeviceOpt) Type() string {
-	return "list"
-}