This patch fixes a bug where labels use the same behavior as `--env`, resulting in a value to be copied from environment variables with the same name as the label if no value is set (i.e. a simple key, no `=` sign, no value). An earlier pull request addressed similar cases for `docker run`;2b17f4c8a8, but this did not address the same situation for (e.g.) `docker service create`. Digging in history for this bug, I found that use of the `ValidateEnv` function for labels was added in the original implementation of the labels feature inabb5e9a077 (diff-ae476143d40e21ac0918630f7365ed3cR34)However, the design never intended it to expand environment variables, and use of this function was either due to either a "copy/paste" of the equivalent `--env` flags, or a misunderstanding (the name `ValidateEnv` does not communicate that it also expands environment variables), and the existing `ValidateLabel` was designed for _engine_ labels (which required a value to be set). Following the initial implementation, other parts of the code followed the same (incorrect) approach, therefore leading the bug to be introduced in services as well. This patch: - updates the `ValidateLabel` to match the expected validation rules (this function is no longer used since31dc5c0a9a), and the daemon has its own implementation) - corrects various locations in the code where `ValidateEnv` was used instead of `ValidateLabel`. Before this patch: ```bash export SOME_ENV_VAR=I_AM_SOME_ENV_VAR docker service create --label SOME_ENV_VAR --tty --name test busybox docker service inspect --format '{{json .Spec.Labels}}' test {"SOME_ENV_VAR":"I_AM_SOME_ENV_VAR"} ``` After this patch: ```bash export SOME_ENV_VAR=I_AM_SOME_ENV_VAR docker service create --label SOME_ENV_VAR --tty --name test busybox docker container inspect --format '{{json .Config.Labels}}' test {"SOME_ENV_VAR":""} ``` Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
89 lines
2.1 KiB
Go
89 lines
2.1 KiB
Go
package config
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
|
|
"github.com/docker/cli/cli"
|
|
"github.com/docker/cli/cli/command"
|
|
"github.com/docker/cli/opts"
|
|
"github.com/docker/docker/api/types/swarm"
|
|
"github.com/docker/docker/pkg/system"
|
|
"github.com/pkg/errors"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
// CreateOptions specifies some options that are used when creating a config.
|
|
type CreateOptions struct {
|
|
Name string
|
|
TemplateDriver string
|
|
File string
|
|
Labels opts.ListOpts
|
|
}
|
|
|
|
func newConfigCreateCommand(dockerCli command.Cli) *cobra.Command {
|
|
createOpts := CreateOptions{
|
|
Labels: opts.NewListOpts(opts.ValidateLabel),
|
|
}
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "create [OPTIONS] CONFIG file|-",
|
|
Short: "Create a config from a file or STDIN",
|
|
Args: cli.ExactArgs(2),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
createOpts.Name = args[0]
|
|
createOpts.File = args[1]
|
|
return RunConfigCreate(dockerCli, createOpts)
|
|
},
|
|
}
|
|
flags := cmd.Flags()
|
|
flags.VarP(&createOpts.Labels, "label", "l", "Config labels")
|
|
flags.StringVar(&createOpts.TemplateDriver, "template-driver", "", "Template driver")
|
|
flags.SetAnnotation("driver", "version", []string{"1.37"})
|
|
|
|
return cmd
|
|
}
|
|
|
|
// RunConfigCreate creates a config with the given options.
|
|
func RunConfigCreate(dockerCli command.Cli, options CreateOptions) error {
|
|
client := dockerCli.Client()
|
|
ctx := context.Background()
|
|
|
|
var in io.Reader = dockerCli.In()
|
|
if options.File != "-" {
|
|
file, err := system.OpenSequential(options.File)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
in = file
|
|
defer file.Close()
|
|
}
|
|
|
|
configData, err := ioutil.ReadAll(in)
|
|
if err != nil {
|
|
return errors.Errorf("Error reading content from %q: %v", options.File, err)
|
|
}
|
|
|
|
spec := swarm.ConfigSpec{
|
|
Annotations: swarm.Annotations{
|
|
Name: options.Name,
|
|
Labels: opts.ConvertKVStringsToMap(options.Labels.GetAll()),
|
|
},
|
|
Data: configData,
|
|
}
|
|
if options.TemplateDriver != "" {
|
|
spec.Templating = &swarm.Driver{
|
|
Name: options.TemplateDriver,
|
|
}
|
|
}
|
|
r, err := client.ConfigCreate(ctx, spec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Fprintln(dockerCli.Out(), r.ID)
|
|
return nil
|
|
}
|