Remove stack configs on stack removal

Signed-off-by: John Stephens <johnstep@docker.com>
This commit is contained in:
John Stephens 2017-05-26 17:30:33 -07:00
parent 1b8b63be5c
commit f05cd11ee2
No known key found for this signature in database
GPG Key ID: 240549B2101E94D4
4 changed files with 88 additions and 1 deletions

View File

@ -17,17 +17,21 @@ type fakeClient struct {
services []string services []string
networks []string networks []string
secrets []string secrets []string
configs []string
removedServices []string removedServices []string
removedNetworks []string removedNetworks []string
removedSecrets []string removedSecrets []string
removedConfigs []string
serviceListFunc func(options types.ServiceListOptions) ([]swarm.Service, error) serviceListFunc func(options types.ServiceListOptions) ([]swarm.Service, error)
networkListFunc func(options types.NetworkListOptions) ([]types.NetworkResource, error) networkListFunc func(options types.NetworkListOptions) ([]types.NetworkResource, error)
secretListFunc func(options types.SecretListOptions) ([]swarm.Secret, error) secretListFunc func(options types.SecretListOptions) ([]swarm.Secret, error)
configListFunc func(options types.ConfigListOptions) ([]swarm.Config, error)
serviceRemoveFunc func(serviceID string) error serviceRemoveFunc func(serviceID string) error
networkRemoveFunc func(networkID string) error networkRemoveFunc func(networkID string) error
secretRemoveFunc func(secretID 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) { 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 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 { func (cli *fakeClient) ServiceRemove(ctx context.Context, serviceID string) error {
if cli.serviceRemoveFunc != nil { if cli.serviceRemoveFunc != nil {
return cli.serviceRemoveFunc(serviceID) return cli.serviceRemoveFunc(serviceID)
@ -102,6 +121,15 @@ func (cli *fakeClient) SecretRemove(ctx context.Context, secretID string) error
return nil 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 { func serviceFromName(name string) swarm.Service {
return swarm.Service{ return swarm.Service{
ID: "ID-" + name, 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 { func namespaceFromFilters(filters filters.Args) string {
label := filters.Get("label")[0] label := filters.Get("label")[0]
return strings.TrimPrefix(label, convert.LabelNamespace+"=") return strings.TrimPrefix(label, convert.LabelNamespace+"=")

View File

@ -61,3 +61,13 @@ func getStackSecrets(
ctx, ctx,
types.SecretListOptions{Filters: getStackFilter(namespace)}) 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)})
}

View File

@ -55,13 +55,19 @@ func runRemove(dockerCli command.Cli, opts removeOptions) error {
return err 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) fmt.Fprintf(dockerCli.Out(), "Nothing found in stack: %s\n", namespace)
continue continue
} }
hasError := removeServices(ctx, dockerCli, services) hasError := removeServices(ctx, dockerCli, services)
hasError = removeSecrets(ctx, dockerCli, secrets) || hasError hasError = removeSecrets(ctx, dockerCli, secrets) || hasError
hasError = removeConfigs(ctx, dockerCli, configs) || hasError
hasError = removeNetworks(ctx, dockerCli, networks) || hasError hasError = removeNetworks(ctx, dockerCli, networks) || hasError
if hasError { if hasError {
@ -119,3 +125,18 @@ func removeSecrets(
} }
return err != nil 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
}

View File

@ -32,10 +32,18 @@ func TestRemoveStack(t *testing.T) {
} }
allSecretIDs := buildObjectIDs(allSecrets) allSecretIDs := buildObjectIDs(allSecrets)
allConfigs := []string{
objectName("foo", "config1"),
objectName("foo", "config2"),
objectName("bar", "config1"),
}
allConfigIDs := buildObjectIDs(allConfigs)
cli := &fakeClient{ cli := &fakeClient{
services: allServices, services: allServices,
networks: allNetworks, networks: allNetworks,
secrets: allSecrets, secrets: allSecrets,
configs: allConfigs,
} }
cmd := newRemoveCommand(test.NewFakeCli(cli, &bytes.Buffer{})) cmd := newRemoveCommand(test.NewFakeCli(cli, &bytes.Buffer{}))
cmd.SetArgs([]string{"foo", "bar"}) cmd.SetArgs([]string{"foo", "bar"})
@ -44,6 +52,7 @@ func TestRemoveStack(t *testing.T) {
assert.Equal(t, allServiceIDs, cli.removedServices) assert.Equal(t, allServiceIDs, cli.removedServices)
assert.Equal(t, allNetworkIDs, cli.removedNetworks) assert.Equal(t, allNetworkIDs, cli.removedNetworks)
assert.Equal(t, allSecretIDs, cli.removedSecrets) assert.Equal(t, allSecretIDs, cli.removedSecrets)
assert.Equal(t, allConfigIDs, cli.removedConfigs)
} }
func TestSkipEmptyStack(t *testing.T) { func TestSkipEmptyStack(t *testing.T) {
@ -57,10 +66,14 @@ func TestSkipEmptyStack(t *testing.T) {
allSecrets := []string{objectName("bar", "secret1")} allSecrets := []string{objectName("bar", "secret1")}
allSecretIDs := buildObjectIDs(allSecrets) allSecretIDs := buildObjectIDs(allSecrets)
allConfigs := []string{objectName("bar", "config1")}
allConfigIDs := buildObjectIDs(allConfigs)
cli := &fakeClient{ cli := &fakeClient{
services: allServices, services: allServices,
networks: allNetworks, networks: allNetworks,
secrets: allSecrets, secrets: allSecrets,
configs: allConfigs,
} }
cmd := newRemoveCommand(test.NewFakeCli(cli, buf)) cmd := newRemoveCommand(test.NewFakeCli(cli, buf))
cmd.SetArgs([]string{"foo", "bar"}) cmd.SetArgs([]string{"foo", "bar"})
@ -70,6 +83,7 @@ func TestSkipEmptyStack(t *testing.T) {
assert.Equal(t, allServiceIDs, cli.removedServices) assert.Equal(t, allServiceIDs, cli.removedServices)
assert.Equal(t, allNetworkIDs, cli.removedNetworks) assert.Equal(t, allNetworkIDs, cli.removedNetworks)
assert.Equal(t, allSecretIDs, cli.removedSecrets) assert.Equal(t, allSecretIDs, cli.removedSecrets)
assert.Equal(t, allConfigIDs, cli.removedConfigs)
} }
func TestContinueAfterError(t *testing.T) { func TestContinueAfterError(t *testing.T) {
@ -82,11 +96,15 @@ func TestContinueAfterError(t *testing.T) {
allSecrets := []string{objectName("foo", "secret1"), objectName("bar", "secret1")} allSecrets := []string{objectName("foo", "secret1"), objectName("bar", "secret1")}
allSecretIDs := buildObjectIDs(allSecrets) allSecretIDs := buildObjectIDs(allSecrets)
allConfigs := []string{objectName("foo", "config1"), objectName("bar", "config1")}
allConfigIDs := buildObjectIDs(allConfigs)
removedServices := []string{} removedServices := []string{}
cli := &fakeClient{ cli := &fakeClient{
services: allServices, services: allServices,
networks: allNetworks, networks: allNetworks,
secrets: allSecrets, secrets: allSecrets,
configs: allConfigs,
serviceRemoveFunc: func(serviceID string) error { serviceRemoveFunc: func(serviceID string) error {
removedServices = append(removedServices, serviceID) removedServices = append(removedServices, serviceID)
@ -104,4 +122,5 @@ func TestContinueAfterError(t *testing.T) {
assert.Equal(t, allServiceIDs, removedServices) assert.Equal(t, allServiceIDs, removedServices)
assert.Equal(t, allNetworkIDs, cli.removedNetworks) assert.Equal(t, allNetworkIDs, cli.removedNetworks)
assert.Equal(t, allSecretIDs, cli.removedSecrets) assert.Equal(t, allSecretIDs, cli.removedSecrets)
assert.Equal(t, allConfigIDs, cli.removedConfigs)
} }