Merge component 'cli' from git@github.com:docker/cli master
This commit is contained in:
@ -9,11 +9,15 @@ import (
|
||||
// NewCheckpointCommand returns the `checkpoint` subcommand (only in experimental)
|
||||
func NewCheckpointCommand(dockerCli command.Cli) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "checkpoint",
|
||||
Short: "Manage checkpoints",
|
||||
Args: cli.NoArgs,
|
||||
RunE: command.ShowHelp(dockerCli.Err()),
|
||||
Annotations: map[string]string{"experimental": "", "version": "1.25"},
|
||||
Use: "checkpoint",
|
||||
Short: "Manage checkpoints",
|
||||
Args: cli.NoArgs,
|
||||
RunE: command.ShowHelp(dockerCli.Err()),
|
||||
Annotations: map[string]string{
|
||||
"experimental": "",
|
||||
"ostype": "linux",
|
||||
"version": "1.25",
|
||||
},
|
||||
}
|
||||
cmd.AddCommand(
|
||||
newCreateCommand(dockerCli),
|
||||
|
||||
@ -47,8 +47,10 @@ func NewStartCommand(dockerCli command.Cli) *cobra.Command {
|
||||
|
||||
flags.StringVar(&opts.checkpoint, "checkpoint", "", "Restore from this checkpoint")
|
||||
flags.SetAnnotation("checkpoint", "experimental", nil)
|
||||
flags.SetAnnotation("checkpoint", "ostype", []string{"linux"})
|
||||
flags.StringVar(&opts.checkpointDir, "checkpoint-dir", "", "Use a custom checkpoint storage directory")
|
||||
flags.SetAnnotation("checkpoint-dir", "experimental", nil)
|
||||
flags.SetAnnotation("checkpoint-dir", "ostype", []string{"linux"})
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
||||
@ -2,13 +2,13 @@ package kubernetes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/cli/cli/command/formatter"
|
||||
"github.com/docker/cli/cli/command/stack/options"
|
||||
"github.com/docker/cli/kubernetes/labels"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
appsv1beta2 "k8s.io/api/apps/v1beta2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
@ -49,15 +49,7 @@ func parseLabelFilters(rawFilters []string) map[string][]string {
|
||||
}
|
||||
|
||||
func generateLabelSelector(f filters.Args, stackName string) string {
|
||||
names := f.Get("name")
|
||||
sort.Strings(names)
|
||||
for _, n := range names {
|
||||
if strings.HasPrefix(n, stackName+"_") {
|
||||
// also accepts with unprefixed service name (for compat with existing swarm scripts where service names are prefixed by stack names)
|
||||
names = append(names, strings.TrimPrefix(n, stackName+"_"))
|
||||
}
|
||||
}
|
||||
selectors := append(generateSelector(parseLabelFilters(f.Get("label"))), labels.SelectorForStack(stackName, names...))
|
||||
selectors := append(generateSelector(parseLabelFilters(f.Get("label"))), labels.SelectorForStack(stackName))
|
||||
return strings.Join(selectors, ",")
|
||||
}
|
||||
|
||||
@ -120,6 +112,7 @@ func RunServices(dockerCli *KubeCli, opts options.Services) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
services = filterServicesByName(services, filters.Get("name"), stackName)
|
||||
|
||||
if opts.Quiet {
|
||||
info = map[string]formatter.ServiceListInfo{}
|
||||
@ -140,3 +133,26 @@ func RunServices(dockerCli *KubeCli, opts options.Services) error {
|
||||
}
|
||||
return formatter.ServiceListWrite(servicesCtx, services, info)
|
||||
}
|
||||
|
||||
func filterServicesByName(services []swarm.Service, names []string, stackName string) []swarm.Service {
|
||||
if len(names) == 0 {
|
||||
return services
|
||||
}
|
||||
prefix := stackName + "_"
|
||||
// Accepts unprefixed service name (for compatibility with existing swarm scripts where service names are prefixed by stack names)
|
||||
for i, n := range names {
|
||||
if !strings.HasPrefix(n, prefix) {
|
||||
names[i] = stackName + "_" + n
|
||||
}
|
||||
}
|
||||
// Filter services
|
||||
result := []swarm.Service{}
|
||||
for _, s := range services {
|
||||
for _, n := range names {
|
||||
if strings.HasPrefix(s.Spec.Name, n) {
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/api/types/swarm"
|
||||
"github.com/gotestyourself/gotestyourself/assert"
|
||||
"github.com/gotestyourself/gotestyourself/assert/cmp"
|
||||
)
|
||||
@ -23,27 +24,6 @@ func TestServiceFiltersLabelSelectorGen(t *testing.T) {
|
||||
"com.docker.stack.namespace=test",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single-name filter",
|
||||
stackName: "test",
|
||||
filters: filters.NewArgs(filters.KeyValuePair{Key: "name", Value: "svc-test"}),
|
||||
expectedSelectorParts: []string{
|
||||
"com.docker.stack.namespace=test",
|
||||
"com.docker.service.name=svc-test",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multi-name filter",
|
||||
stackName: "test",
|
||||
filters: filters.NewArgs(
|
||||
filters.KeyValuePair{Key: "name", Value: "svc-test"},
|
||||
filters.KeyValuePair{Key: "name", Value: "svc-test2"},
|
||||
),
|
||||
expectedSelectorParts: []string{
|
||||
"com.docker.stack.namespace=test",
|
||||
"com.docker.service.name in (svc-test,svc-test2)",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "label present filter",
|
||||
stackName: "test",
|
||||
@ -92,17 +72,6 @@ func TestServiceFiltersLabelSelectorGen(t *testing.T) {
|
||||
"label2=test2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "name filter with stackName prefix",
|
||||
stackName: "test",
|
||||
filters: filters.NewArgs(
|
||||
filters.KeyValuePair{Key: "name", Value: "test_svc1"},
|
||||
),
|
||||
expectedSelectorParts: []string{
|
||||
"com.docker.stack.namespace=test",
|
||||
"com.docker.service.name in (test_svc1,svc1)",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
@ -114,3 +83,56 @@ func TestServiceFiltersLabelSelectorGen(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestServiceFiltersServiceByName(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
filters []string
|
||||
services []swarm.Service
|
||||
expectedServices []swarm.Service
|
||||
}{
|
||||
{
|
||||
name: "no filter",
|
||||
filters: []string{},
|
||||
services: makeServices("s1", "s2"),
|
||||
expectedServices: makeServices("s1", "s2"),
|
||||
},
|
||||
{
|
||||
name: "single-name filter",
|
||||
filters: []string{"s1"},
|
||||
services: makeServices("s1", "s2"),
|
||||
expectedServices: makeServices("s1"),
|
||||
},
|
||||
{
|
||||
name: "filter by prefix",
|
||||
filters: []string{"prefix"},
|
||||
services: makeServices("prefix-s1", "prefix-s2", "s2"),
|
||||
expectedServices: makeServices("prefix-s1", "prefix-s2"),
|
||||
},
|
||||
{
|
||||
name: "multi-name filter",
|
||||
filters: []string{"s1", "s2"},
|
||||
services: makeServices("s1", "s2", "s3"),
|
||||
expectedServices: makeServices("s1", "s2"),
|
||||
},
|
||||
{
|
||||
name: "stack name prefix is valid",
|
||||
filters: []string{"stack_s1"},
|
||||
services: makeServices("s1", "s11", "s2"),
|
||||
expectedServices: makeServices("s1", "s11"),
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
result := filterServicesByName(c.services, c.filters, "stack")
|
||||
assert.DeepEqual(t, c.expectedServices, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func makeServices(names ...string) []swarm.Service {
|
||||
result := make([]swarm.Service, len(names))
|
||||
for i, n := range names {
|
||||
result[i] = swarm.Service{Spec: swarm.ServiceSpec{Annotations: swarm.Annotations{Name: "stack_" + n}}}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@ -467,44 +467,44 @@ DoTuq9lAU9Q4O1xV/59X/w8AAP//zRo7vm9CAAA=
|
||||
|
||||
"/data/config_schema_v3.7.json": {
|
||||
local: "data/config_schema_v3.7.json",
|
||||
size: 17540,
|
||||
size: 17740,
|
||||
modtime: 1518458244,
|
||||
compressed: `
|
||||
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
|
||||
`,
|
||||
},
|
||||
|
||||
|
||||
@ -319,6 +319,7 @@
|
||||
},
|
||||
"working_dir": {"type": "string"}
|
||||
},
|
||||
"patternProperties": {"^x-": {}},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
@ -489,6 +490,7 @@
|
||||
"attachable": {"type": "boolean"},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"}
|
||||
},
|
||||
"patternProperties": {"^x-": {}},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
@ -513,6 +515,7 @@
|
||||
},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"}
|
||||
},
|
||||
"patternProperties": {"^x-": {}},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
@ -530,6 +533,7 @@
|
||||
},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"}
|
||||
},
|
||||
"patternProperties": {"^x-": {}},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
@ -547,6 +551,7 @@
|
||||
},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"}
|
||||
},
|
||||
"patternProperties": {"^x-": {}},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
|
||||
@ -45,6 +45,39 @@ func TestValidateAllowsXTopLevelFields(t *testing.T) {
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestValidateAllowsXFields(t *testing.T) {
|
||||
config := dict{
|
||||
"version": "3.7",
|
||||
"services": dict{
|
||||
"bar": dict{
|
||||
"x-extra-stuff": dict{},
|
||||
},
|
||||
},
|
||||
"volumes": dict{
|
||||
"bar": dict{
|
||||
"x-extra-stuff": dict{},
|
||||
},
|
||||
},
|
||||
"networks": dict{
|
||||
"bar": dict{
|
||||
"x-extra-stuff": dict{},
|
||||
},
|
||||
},
|
||||
"configs": dict{
|
||||
"bar": dict{
|
||||
"x-extra-stuff": dict{},
|
||||
},
|
||||
},
|
||||
"secrets": dict{
|
||||
"bar": dict{
|
||||
"x-extra-stuff": dict{},
|
||||
},
|
||||
},
|
||||
}
|
||||
err := Validate(config, "3.7")
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
func TestValidateSecretConfigNames(t *testing.T) {
|
||||
config := dict{
|
||||
"version": "3.5",
|
||||
|
||||
@ -256,6 +256,9 @@ func hideUnsupportedFeatures(cmd *cobra.Command, details versionDetails) {
|
||||
if subcmdVersion, ok := subcmd.Annotations["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) {
|
||||
subcmd.Hidden = true
|
||||
}
|
||||
if v, ok := subcmd.Annotations["ostype"]; ok && v != osType {
|
||||
subcmd.Hidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,14 +285,14 @@ func areFlagsSupported(cmd *cobra.Command, details versionDetails) error {
|
||||
return
|
||||
}
|
||||
if !isOSTypeSupported(f, osType) {
|
||||
errs = append(errs, fmt.Sprintf("\"--%s\" requires the Docker daemon to run on %s, but the Docker daemon is running on %s", f.Name, getFlagAnnotation(f, "ostype"), osType))
|
||||
errs = append(errs, fmt.Sprintf("\"--%s\" is only supported on a Docker daemon running on %s, but the Docker daemon is running on %s", f.Name, getFlagAnnotation(f, "ostype"), osType))
|
||||
return
|
||||
}
|
||||
if _, ok := f.Annotations["experimental"]; ok && !hasExperimental {
|
||||
errs = append(errs, fmt.Sprintf("\"--%s\" is only supported on a Docker daemon with experimental features enabled", f.Name))
|
||||
}
|
||||
if _, ok := f.Annotations["experimentalCLI"]; ok && !hasExperimentalCLI {
|
||||
errs = append(errs, fmt.Sprintf("\"--%s\" is only supported when experimental cli features are enabled", f.Name))
|
||||
errs = append(errs, fmt.Sprintf("\"--%s\" is on a Docker cli with experimental cli features enabled", f.Name))
|
||||
}
|
||||
_, isKubernetesAnnotated := f.Annotations["kubernetes"]
|
||||
_, isSwarmAnnotated := f.Annotations["swarm"]
|
||||
@ -310,6 +313,7 @@ func areFlagsSupported(cmd *cobra.Command, details versionDetails) error {
|
||||
// Check recursively so that, e.g., `docker stack ls` returns the same output as `docker stack`
|
||||
func areSubcommandsSupported(cmd *cobra.Command, details versionDetails) error {
|
||||
clientVersion := details.Client().ClientVersion()
|
||||
osType := details.ServerInfo().OSType
|
||||
hasExperimental := details.ServerInfo().HasExperimental
|
||||
hasExperimentalCLI := details.ClientInfo().HasExperimental
|
||||
hasKubernetes := details.ClientInfo().HasKubernetes()
|
||||
@ -319,11 +323,14 @@ func areSubcommandsSupported(cmd *cobra.Command, details versionDetails) error {
|
||||
if cmdVersion, ok := curr.Annotations["version"]; ok && versions.LessThan(clientVersion, cmdVersion) {
|
||||
return fmt.Errorf("%s requires API version %s, but the Docker daemon API version is %s", cmd.CommandPath(), cmdVersion, clientVersion)
|
||||
}
|
||||
if os, ok := curr.Annotations["ostype"]; ok && os != osType {
|
||||
return fmt.Errorf("%s is only supported on a Docker daemon running on %s, but the Docker daemon is running on %s", cmd.CommandPath(), os, osType)
|
||||
}
|
||||
if _, ok := curr.Annotations["experimental"]; ok && !hasExperimental {
|
||||
return fmt.Errorf("%s is only supported on a Docker daemon with experimental features enabled", cmd.CommandPath())
|
||||
}
|
||||
if _, ok := curr.Annotations["experimentalCLI"]; ok && !hasExperimentalCLI {
|
||||
return fmt.Errorf("%s is only supported when experimental cli features are enabled", cmd.CommandPath())
|
||||
return fmt.Errorf("%s is only supported on a Docker cli with experimental cli features enabled", cmd.CommandPath())
|
||||
}
|
||||
_, isKubernetesAnnotated := curr.Annotations["kubernetes"]
|
||||
_, isSwarmAnnotated := curr.Annotations["swarm"]
|
||||
|
||||
@ -25,6 +25,7 @@ type cmdOption struct {
|
||||
ExperimentalCLI bool
|
||||
Kubernetes bool
|
||||
Swarm bool
|
||||
OSType string `yaml:"os_type,omitempty"`
|
||||
}
|
||||
|
||||
type cmdDoc struct {
|
||||
@ -48,6 +49,7 @@ type cmdDoc struct {
|
||||
ExperimentalCLI bool
|
||||
Kubernetes bool
|
||||
Swarm bool
|
||||
OSType string `yaml:"os_type,omitempty"`
|
||||
}
|
||||
|
||||
// GenYamlTree creates yaml structured ref files
|
||||
@ -121,6 +123,9 @@ func GenYamlCustom(cmd *cobra.Command, w io.Writer) error {
|
||||
if _, ok := curr.Annotations["swarm"]; ok && !cliDoc.Swarm {
|
||||
cliDoc.Swarm = true
|
||||
}
|
||||
if os, ok := curr.Annotations["ostype"]; ok && cliDoc.OSType == "" {
|
||||
cliDoc.OSType = os
|
||||
}
|
||||
}
|
||||
|
||||
flags := cmd.NonInheritedFlags()
|
||||
@ -207,6 +212,15 @@ func genFlagResult(flags *pflag.FlagSet) []cmdOption {
|
||||
opt.Swarm = true
|
||||
}
|
||||
|
||||
// Note that the annotation can have multiple ostypes set, however, multiple
|
||||
// values are currently not used (and unlikely will).
|
||||
//
|
||||
// To simplify usage of the os_type property in the YAML, and for consistency
|
||||
// with the same property for commands, we're only using the first ostype that's set.
|
||||
if ostypes, ok := flag.Annotations["ostype"]; ok && len(opt.OSType) == 0 && len(ostypes) > 0 {
|
||||
opt.OSType = ostypes[0]
|
||||
}
|
||||
|
||||
result = append(result, opt)
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user