Merge component 'cli' from git@github.com:docker/cli master

This commit is contained in:
GordonTheTurtle
2018-06-01 16:41:21 +00:00
9 changed files with 189 additions and 86 deletions

View File

@ -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),

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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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
`,
},

View File

@ -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
},

View File

@ -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",

View File

@ -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"]

View File

@ -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)
})