Update CredentialSpec code to allow using configs

Updates the CredentialSpec handling code for services to allow using
swarm Configs.

Additionally, fixes a bug where the `--credential-spec` flag would not
be respected on service updates.

Signed-off-by: Drew Erny <drew.erny@docker.com>
This commit is contained in:
Drew Erny
2019-03-27 15:44:32 -05:00
parent 6511da877f
commit 01f4f2e80a
5 changed files with 188 additions and 16 deletions

View File

@ -8,7 +8,9 @@ import (
"github.com/docker/cli/cli/command"
cliopts "github.com/docker/cli/opts"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/client"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@ -95,15 +97,7 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *serviceOptions
service.TaskTemplate.ContainerSpec.Secrets = secrets
}
specifiedConfigs := opts.configs.Value()
if len(specifiedConfigs) > 0 {
// parse and validate configs
configs, err := ParseConfigs(apiClient, specifiedConfigs)
if err != nil {
return err
}
service.TaskTemplate.ContainerSpec.Configs = configs
}
setConfigs(apiClient, &service, opts)
if err := resolveServiceImageDigestContentTrust(dockerCli, &service); err != nil {
return err
@ -141,3 +135,42 @@ func runCreate(dockerCli command.Cli, flags *pflag.FlagSet, opts *serviceOptions
return waitOnService(ctx, dockerCli, response.ID, opts.quiet)
}
// setConfigs does double duty: it both sets the ConfigReferences of the
// service, and it sets the service CredentialSpec. This is because there is an
// interplay between the CredentialSpec and the Config it depends on.
func setConfigs(apiClient client.ConfigAPIClient, service *swarm.ServiceSpec, opts *serviceOptions) error {
specifiedConfigs := opts.configs.Value()
// if the user has requested to use a Config, for the CredentialSpec add it
// to the specifiedConfigs as a RuntimeTarget.
if cs := opts.credentialSpec.Value(); cs != nil && cs.Config != "" {
specifiedConfigs = append(specifiedConfigs, &swarm.ConfigReference{
ConfigName: cs.Config,
Runtime: &swarm.ConfigReferenceRuntimeTarget{},
})
}
if len(specifiedConfigs) > 0 {
// parse and validate configs
configs, err := ParseConfigs(apiClient, specifiedConfigs)
if err != nil {
return err
}
service.TaskTemplate.ContainerSpec.Configs = configs
// if we have a CredentialSpec Config, find its ID and rewrite the
// field on the spec
//
// we check the opts instead of the service directly because there are
// a few layers of nullable objects in the service, which is a PITA
// to traverse, but the existence of the option implies that those are
// non-null.
if cs := opts.credentialSpec.Value(); cs != nil && cs.Config != "" {
for _, config := range configs {
if config.ConfigName == cs.Config {
service.TaskTemplate.ContainerSpec.Privileges.CredentialSpec.Config = config.ConfigID
}
}
}
}
return nil
}