From f05cd11ee234804d85b3aadae0777610809530a4 Mon Sep 17 00:00:00 2001 From: John Stephens Date: Fri, 26 May 2017 17:30:33 -0700 Subject: [PATCH] Remove stack configs on stack removal Signed-off-by: John Stephens --- cli/command/stack/client_test.go | 37 ++++++++++++++++++++++++++++++++ cli/command/stack/common.go | 10 +++++++++ cli/command/stack/remove.go | 23 +++++++++++++++++++- cli/command/stack/remove_test.go | 19 ++++++++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/cli/command/stack/client_test.go b/cli/command/stack/client_test.go index 5b51575580..d4c373ce12 100644 --- a/cli/command/stack/client_test.go +++ b/cli/command/stack/client_test.go @@ -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+"=") diff --git a/cli/command/stack/common.go b/cli/command/stack/common.go index 27d664bdc9..d9f921af56 100644 --- a/cli/command/stack/common.go +++ b/cli/command/stack/common.go @@ -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)}) +} diff --git a/cli/command/stack/remove.go b/cli/command/stack/remove.go index 27258850d2..09431dad70 100644 --- a/cli/command/stack/remove.go +++ b/cli/command/stack/remove.go @@ -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 +} diff --git a/cli/command/stack/remove_test.go b/cli/command/stack/remove_test.go index a2be8c5f4c..d6efb90106 100644 --- a/cli/command/stack/remove_test.go +++ b/cli/command/stack/remove_test.go @@ -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) }