Merge component 'cli' from git@github.com:docker/cli master
This commit is contained in:
@ -28,7 +28,9 @@ func ElectAuthServer(ctx context.Context, cli Cli) string {
|
||||
// the default registry URL might be Windows specific.
|
||||
serverAddress := registry.IndexServer
|
||||
if info, err := cli.Client().Info(ctx); err != nil {
|
||||
fmt.Fprintf(cli.Out(), "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress)
|
||||
fmt.Fprintf(cli.Err(), "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress)
|
||||
} else if info.IndexServerAddress == "" {
|
||||
fmt.Fprintf(cli.Err(), "Warning: Empty registry endpoint from daemon. Using system default: %s\n", serverAddress)
|
||||
} else {
|
||||
serverAddress = info.IndexServerAddress
|
||||
}
|
||||
|
||||
79
components/cli/cli/command/registry_test.go
Normal file
79
components/cli/cli/command/registry_test.go
Normal file
@ -0,0 +1,79 @@
|
||||
package command_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
// Prevents a circular import with "github.com/docker/cli/cli/internal/test"
|
||||
. "github.com/docker/cli/cli/command"
|
||||
"github.com/docker/cli/cli/internal/test"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
)
|
||||
|
||||
type fakeClient struct {
|
||||
client.Client
|
||||
infoFunc func() (types.Info, error)
|
||||
}
|
||||
|
||||
func (cli *fakeClient) Info(_ context.Context) (types.Info, error) {
|
||||
if cli.infoFunc != nil {
|
||||
return cli.infoFunc()
|
||||
}
|
||||
return types.Info{}, nil
|
||||
}
|
||||
|
||||
func TestElectAuthServer(t *testing.T) {
|
||||
testCases := []struct {
|
||||
expectedAuthServer string
|
||||
expectedWarning string
|
||||
infoFunc func() (types.Info, error)
|
||||
}{
|
||||
{
|
||||
expectedAuthServer: "https://index.docker.io/v1/",
|
||||
expectedWarning: "",
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{IndexServerAddress: "https://index.docker.io/v1/"}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedAuthServer: "https://index.docker.io/v1/",
|
||||
expectedWarning: "Empty registry endpoint from daemon",
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{IndexServerAddress: ""}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedAuthServer: "https://foo.bar",
|
||||
expectedWarning: "",
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{IndexServerAddress: "https://foo.bar"}, nil
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedAuthServer: "https://index.docker.io/v1/",
|
||||
expectedWarning: "failed to get default registry endpoint from daemon",
|
||||
infoFunc: func() (types.Info, error) {
|
||||
return types.Info{}, errors.Errorf("error getting info")
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
buf := new(bytes.Buffer)
|
||||
cli := test.NewFakeCli(&fakeClient{infoFunc: tc.infoFunc}, buf)
|
||||
errBuf := new(bytes.Buffer)
|
||||
cli.SetErr(errBuf)
|
||||
server := ElectAuthServer(context.Background(), cli)
|
||||
assert.Equal(t, tc.expectedAuthServer, server)
|
||||
actual := errBuf.String()
|
||||
if tc.expectedWarning == "" {
|
||||
assert.Empty(t, actual)
|
||||
} else {
|
||||
assert.Contains(t, actual, tc.expectedWarning)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -17,17 +17,21 @@ type fakeClient struct {
|
||||
services []string
|
||||
networks []string
|
||||
secrets []string
|
||||
configs []string
|
||||
|
||||
removedServices []string
|
||||
removedNetworks []string
|
||||
removedSecrets []string
|
||||
removedConfigs []string
|
||||
|
||||
serviceListFunc func(options types.ServiceListOptions) ([]swarm.Service, error)
|
||||
networkListFunc func(options types.NetworkListOptions) ([]types.NetworkResource, error)
|
||||
secretListFunc func(options types.SecretListOptions) ([]swarm.Secret, error)
|
||||
configListFunc func(options types.ConfigListOptions) ([]swarm.Config, error)
|
||||
serviceRemoveFunc func(serviceID string) error
|
||||
networkRemoveFunc func(networkID string) error
|
||||
secretRemoveFunc func(secretID string) error
|
||||
configRemoveFunc func(configID string) error
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceList(ctx context.Context, options types.ServiceListOptions) ([]swarm.Service, error) {
|
||||
@ -75,6 +79,21 @@ func (cli *fakeClient) SecretList(ctx context.Context, options types.SecretListO
|
||||
return secretsList, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
|
||||
if cli.configListFunc != nil {
|
||||
return cli.configListFunc(options)
|
||||
}
|
||||
|
||||
namespace := namespaceFromFilters(options.Filters)
|
||||
configsList := []swarm.Config{}
|
||||
for _, name := range cli.configs {
|
||||
if belongToNamespace(name, namespace) {
|
||||
configsList = append(configsList, configFromName(name))
|
||||
}
|
||||
}
|
||||
return configsList, nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ServiceRemove(ctx context.Context, serviceID string) error {
|
||||
if cli.serviceRemoveFunc != nil {
|
||||
return cli.serviceRemoveFunc(serviceID)
|
||||
@ -102,6 +121,15 @@ func (cli *fakeClient) SecretRemove(ctx context.Context, secretID string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *fakeClient) ConfigRemove(ctx context.Context, configID string) error {
|
||||
if cli.configRemoveFunc != nil {
|
||||
return cli.configRemoveFunc(configID)
|
||||
}
|
||||
|
||||
cli.removedConfigs = append(cli.removedConfigs, configID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func serviceFromName(name string) swarm.Service {
|
||||
return swarm.Service{
|
||||
ID: "ID-" + name,
|
||||
@ -127,6 +155,15 @@ func secretFromName(name string) swarm.Secret {
|
||||
}
|
||||
}
|
||||
|
||||
func configFromName(name string) swarm.Config {
|
||||
return swarm.Config{
|
||||
ID: "ID-" + name,
|
||||
Spec: swarm.ConfigSpec{
|
||||
Annotations: swarm.Annotations{Name: name},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func namespaceFromFilters(filters filters.Args) string {
|
||||
label := filters.Get("label")[0]
|
||||
return strings.TrimPrefix(label, convert.LabelNamespace+"=")
|
||||
|
||||
@ -61,3 +61,13 @@ func getStackSecrets(
|
||||
ctx,
|
||||
types.SecretListOptions{Filters: getStackFilter(namespace)})
|
||||
}
|
||||
|
||||
func getStackConfigs(
|
||||
ctx context.Context,
|
||||
apiclient client.APIClient,
|
||||
namespace string,
|
||||
) ([]swarm.Config, error) {
|
||||
return apiclient.ConfigList(
|
||||
ctx,
|
||||
types.ConfigListOptions{Filters: getStackFilter(namespace)})
|
||||
}
|
||||
|
||||
@ -55,13 +55,19 @@ func runRemove(dockerCli command.Cli, opts removeOptions) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(services)+len(networks)+len(secrets) == 0 {
|
||||
configs, err := getStackConfigs(ctx, client, namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(services)+len(networks)+len(secrets)+len(configs) == 0 {
|
||||
fmt.Fprintf(dockerCli.Out(), "Nothing found in stack: %s\n", namespace)
|
||||
continue
|
||||
}
|
||||
|
||||
hasError := removeServices(ctx, dockerCli, services)
|
||||
hasError = removeSecrets(ctx, dockerCli, secrets) || hasError
|
||||
hasError = removeConfigs(ctx, dockerCli, configs) || hasError
|
||||
hasError = removeNetworks(ctx, dockerCli, networks) || hasError
|
||||
|
||||
if hasError {
|
||||
@ -119,3 +125,18 @@ func removeSecrets(
|
||||
}
|
||||
return err != nil
|
||||
}
|
||||
|
||||
func removeConfigs(
|
||||
ctx context.Context,
|
||||
dockerCli command.Cli,
|
||||
configs []swarm.Config,
|
||||
) bool {
|
||||
var err error
|
||||
for _, config := range configs {
|
||||
fmt.Fprintf(dockerCli.Err(), "Removing config %s\n", config.Spec.Name)
|
||||
if err = dockerCli.Client().ConfigRemove(ctx, config.ID); err != nil {
|
||||
fmt.Fprintf(dockerCli.Err(), "Failed to remove config %s: %s", config.ID, err)
|
||||
}
|
||||
}
|
||||
return err != nil
|
||||
}
|
||||
|
||||
@ -32,10 +32,18 @@ func TestRemoveStack(t *testing.T) {
|
||||
}
|
||||
allSecretIDs := buildObjectIDs(allSecrets)
|
||||
|
||||
allConfigs := []string{
|
||||
objectName("foo", "config1"),
|
||||
objectName("foo", "config2"),
|
||||
objectName("bar", "config1"),
|
||||
}
|
||||
allConfigIDs := buildObjectIDs(allConfigs)
|
||||
|
||||
cli := &fakeClient{
|
||||
services: allServices,
|
||||
networks: allNetworks,
|
||||
secrets: allSecrets,
|
||||
configs: allConfigs,
|
||||
}
|
||||
cmd := newRemoveCommand(test.NewFakeCli(cli, &bytes.Buffer{}))
|
||||
cmd.SetArgs([]string{"foo", "bar"})
|
||||
@ -44,6 +52,7 @@ func TestRemoveStack(t *testing.T) {
|
||||
assert.Equal(t, allServiceIDs, cli.removedServices)
|
||||
assert.Equal(t, allNetworkIDs, cli.removedNetworks)
|
||||
assert.Equal(t, allSecretIDs, cli.removedSecrets)
|
||||
assert.Equal(t, allConfigIDs, cli.removedConfigs)
|
||||
}
|
||||
|
||||
func TestSkipEmptyStack(t *testing.T) {
|
||||
@ -57,10 +66,14 @@ func TestSkipEmptyStack(t *testing.T) {
|
||||
allSecrets := []string{objectName("bar", "secret1")}
|
||||
allSecretIDs := buildObjectIDs(allSecrets)
|
||||
|
||||
allConfigs := []string{objectName("bar", "config1")}
|
||||
allConfigIDs := buildObjectIDs(allConfigs)
|
||||
|
||||
cli := &fakeClient{
|
||||
services: allServices,
|
||||
networks: allNetworks,
|
||||
secrets: allSecrets,
|
||||
configs: allConfigs,
|
||||
}
|
||||
cmd := newRemoveCommand(test.NewFakeCli(cli, buf))
|
||||
cmd.SetArgs([]string{"foo", "bar"})
|
||||
@ -70,6 +83,7 @@ func TestSkipEmptyStack(t *testing.T) {
|
||||
assert.Equal(t, allServiceIDs, cli.removedServices)
|
||||
assert.Equal(t, allNetworkIDs, cli.removedNetworks)
|
||||
assert.Equal(t, allSecretIDs, cli.removedSecrets)
|
||||
assert.Equal(t, allConfigIDs, cli.removedConfigs)
|
||||
}
|
||||
|
||||
func TestContinueAfterError(t *testing.T) {
|
||||
@ -82,11 +96,15 @@ func TestContinueAfterError(t *testing.T) {
|
||||
allSecrets := []string{objectName("foo", "secret1"), objectName("bar", "secret1")}
|
||||
allSecretIDs := buildObjectIDs(allSecrets)
|
||||
|
||||
allConfigs := []string{objectName("foo", "config1"), objectName("bar", "config1")}
|
||||
allConfigIDs := buildObjectIDs(allConfigs)
|
||||
|
||||
removedServices := []string{}
|
||||
cli := &fakeClient{
|
||||
services: allServices,
|
||||
networks: allNetworks,
|
||||
secrets: allSecrets,
|
||||
configs: allConfigs,
|
||||
|
||||
serviceRemoveFunc: func(serviceID string) error {
|
||||
removedServices = append(removedServices, serviceID)
|
||||
@ -104,4 +122,5 @@ func TestContinueAfterError(t *testing.T) {
|
||||
assert.Equal(t, allServiceIDs, removedServices)
|
||||
assert.Equal(t, allNetworkIDs, cli.removedNetworks)
|
||||
assert.Equal(t, allSecretIDs, cli.removedSecrets)
|
||||
assert.Equal(t, allConfigIDs, cli.removedConfigs)
|
||||
}
|
||||
|
||||
@ -12,9 +12,10 @@ import (
|
||||
)
|
||||
|
||||
type pruneOptions struct {
|
||||
force bool
|
||||
all bool
|
||||
filter opts.FilterOpt
|
||||
force bool
|
||||
all bool
|
||||
pruneVolumes bool
|
||||
filter opts.FilterOpt
|
||||
}
|
||||
|
||||
// NewPruneCommand creates a new cobra.Command for `docker prune`
|
||||
@ -34,6 +35,7 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVarP(&options.force, "force", "f", false, "Do not prompt for confirmation")
|
||||
flags.BoolVarP(&options.all, "all", "a", false, "Remove all unused images not just dangling ones")
|
||||
flags.BoolVar(&options.pruneVolumes, "volumes", false, "Prune volumes")
|
||||
flags.Var(&options.filter, "filter", "Provide filter values (e.g. 'label=<key>=<value>')")
|
||||
// "filter" flag is available in 1.28 (docker 17.04) and up
|
||||
flags.SetAnnotation("filter", "version", []string{"1.28"})
|
||||
@ -67,12 +69,15 @@ func runPrune(dockerCli command.Cli, options pruneOptions) error {
|
||||
}
|
||||
|
||||
var spaceReclaimed uint64
|
||||
|
||||
for _, pruneFn := range []func(dockerCli command.Cli, filter opts.FilterOpt) (uint64, string, error){
|
||||
pruneFuncs := []func(dockerCli command.Cli, filter opts.FilterOpt) (uint64, string, error){
|
||||
prune.RunContainerPrune,
|
||||
prune.RunVolumePrune,
|
||||
prune.RunNetworkPrune,
|
||||
} {
|
||||
}
|
||||
if options.pruneVolumes {
|
||||
pruneFuncs = append(pruneFuncs, prune.RunVolumePrune)
|
||||
}
|
||||
|
||||
for _, pruneFn := range pruneFuncs {
|
||||
spc, output, err := pruneFn(dockerCli, options.filter)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -141,6 +141,7 @@ func convertService(
|
||||
TTY: service.Tty,
|
||||
OpenStdin: service.StdinOpen,
|
||||
Secrets: secrets,
|
||||
Configs: configs,
|
||||
ReadOnly: service.ReadOnly,
|
||||
Privileges: &privileges,
|
||||
},
|
||||
|
||||
@ -11,10 +11,6 @@ RUN apt-get update -qq && apt-get install -y -q \
|
||||
parallel \
|
||||
;
|
||||
|
||||
RUN go get github.com/mitchellh/gox && \
|
||||
cp /go/bin/gox /usr/bin && \
|
||||
rm -rf /go/src/* /go/pkg/* /go/bin/*
|
||||
|
||||
COPY dockerfiles/osx-cross.sh /tmp/
|
||||
RUN /tmp/osx-cross.sh
|
||||
ENV PATH /osxcross/target/bin:$PATH
|
||||
|
||||
@ -7,10 +7,6 @@ RUN go get github.com/LK4D4/vndr && \
|
||||
cp /go/bin/vndr /usr/bin && \
|
||||
rm -rf /go/src/* /go/pkg/* /go/bin/*
|
||||
|
||||
RUN go get github.com/mitchellh/gox && \
|
||||
cp /go/bin/gox /usr/bin && \
|
||||
rm -rf /go/src/* /go/pkg/* /go/bin/*
|
||||
|
||||
RUN go get github.com/jteeuwen/go-bindata/go-bindata && \
|
||||
cp /go/bin/go-bindata /usr/bin && \
|
||||
rm -rf /go/src/* /go/pkg/* /go/bin/*
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
VERSION=${VERSION:-"unknown-version"}
|
||||
@ -14,5 +13,7 @@ export LDFLAGS="\
|
||||
${LDFLAGS:-} \
|
||||
"
|
||||
|
||||
export TARGET="build/docker-$(go env GOHOSTOS)-$(go env GOHOSTARCH)"
|
||||
GOOS="${GOOS:-$(go env GOHOSTOS)}"
|
||||
GOARCH="${GOARCH:-$(go env GOHOSTARCH)}"
|
||||
export TARGET="build/docker-$GOOS-$GOARCH"
|
||||
export SOURCE="github.com/docker/cli/cmd/docker"
|
||||
|
||||
@ -1,12 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Build a binary for all supported platforms
|
||||
#
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
BUILDDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
echo "Building all binaries"
|
||||
echo "Building binaries for all platforms"
|
||||
SHELL=/bin/bash parallel ::: \
|
||||
"$BUILDDIR/linux-cross" \
|
||||
"$BUILDDIR/windows" \
|
||||
"$BUILDDIR/osx" \
|
||||
"GOOS=linux GOARCH=amd64 $BUILDDIR/binary" \
|
||||
"GOOS=linux GOARCH=arm $BUILDDIR/binary" \
|
||||
"GOOS=linux GOARCH=ppc64le $BUILDDIR/binary" \
|
||||
"GOOS=linux GOARCH=s390x $BUILDDIR/binary" \
|
||||
;
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Build static linux binary for multiple architectures
|
||||
#
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
source ./scripts/build/.variables
|
||||
|
||||
CROSS_OSARCH="linux/amd64 linux/arm linux/ppc64le"
|
||||
|
||||
# Not yet supported by gox
|
||||
# linux/s390x
|
||||
|
||||
echo "Building all linux binaries"
|
||||
gox -output build/docker-{{.OS}}-{{.Arch}} \
|
||||
-osarch "${CROSS_OSARCH}" \
|
||||
--ldflags "${LDFLAGS}" \
|
||||
"${SOURCE}"
|
||||
Reference in New Issue
Block a user