From b8f39b715a5fe6357d3c2395119797017a414a96 Mon Sep 17 00:00:00 2001 From: Liron Levin Date: Wed, 19 Jul 2017 18:32:08 +0300 Subject: [PATCH] Plugable secret backend This commit extends SwarmKit secret management with pluggable secret backends support. Following previous commits: 1. docker/swarmkit@eebac27434d34708fac993f9f5181d106c5c2fae 2. docker/docker@08f7cf05268782a0dd8e4c41a4cc65fdf78d09f2 Added driver parameter to `docker secret` command. Specifically: 1. `docker secret create [secret_name] --driver [driver_name]` 2. Displaying the driver in ``` $ docker secret ls $ docker secret inspect [secret_name] $ docker secret inspect [secret_name] -pretty ``` 3. Add driver parameter to secrets in `docker-compose`. There is a bug in serialization of the secret data. Handled in docker/docker#34157. Signed-off-by: Liron Levin --- cli/command/formatter/secret.go | 26 ++++++++-- cli/command/formatter/secret_test.go | 6 +-- cli/command/formatter/service.go | 3 ++ cli/command/secret/create.go | 48 ++++++++++++++----- cli/command/secret/create_test.go | 6 +-- cli/command/secret/inspect_test.go | 1 + cli/command/secret/ls_test.go | 1 + .../secret-inspect-pretty.simple.golden | 1 + .../testdata/secret-list-with-filter.golden | 6 +-- .../secret/testdata/secret-list.golden | 6 +-- cli/command/service/inspect_test.go | 2 +- cli/command/service/opts.go | 2 +- cli/command/service/update.go | 2 +- cli/command/service/update_test.go | 12 ++--- cli/command/stack/deploy_bundlefile.go | 2 +- cli/compose/convert/compose.go | 18 +++++-- cli/compose/convert/compose_test.go | 16 ++++++- cli/compose/convert/service.go | 2 +- cli/compose/schema/bindata.go | 4 +- .../schema/data/config_schema_v3.3.json | 1 + cli/compose/types/types.go | 7 ++- cli/internal/test/builders/secret.go | 9 ++++ cli/internal/test/builders/service.go | 2 +- cli/internal/test/builders/task.go | 2 +- 24 files changed, 131 insertions(+), 54 deletions(-) diff --git a/cli/command/formatter/secret.go b/cli/command/formatter/secret.go index 04bf944ecd07..d025cd8f3b53 100644 --- a/cli/command/formatter/secret.go +++ b/cli/command/formatter/secret.go @@ -12,19 +12,20 @@ import ( ) const ( - defaultSecretTableFormat = "table {{.ID}}\t{{.Name}}\t{{.CreatedAt}}\t{{.UpdatedAt}}" + defaultSecretTableFormat = "table {{.ID}}\t{{.Name}}\t{{.Driver}}\t{{.CreatedAt}}\t{{.UpdatedAt}}" secretIDHeader = "ID" secretCreatedHeader = "CREATED" secretUpdatedHeader = "UPDATED" - secretInspectPrettyTemplate Format = `ID: {{.ID}} -Name: {{.Name}} + secretInspectPrettyTemplate Format = `ID: {{.ID}} +Name: {{.Name}} {{- if .Labels }} Labels: {{- range $k, $v := .Labels }} - {{ $k }}{{if $v }}={{ $v }}{{ end }} {{- end }}{{ end }} -Created at: {{.CreatedAt}} -Updated at: {{.UpdatedAt}}` +Driver: {{.Driver}} +Created at: {{.CreatedAt}} +Updated at: {{.UpdatedAt}}` ) // NewSecretFormat returns a Format for rendering using a secret Context @@ -61,6 +62,7 @@ func newSecretContext() *secretContext { sCtx.header = map[string]string{ "ID": secretIDHeader, "Name": nameHeader, + "Driver": driverHeader, "CreatedAt": secretCreatedHeader, "UpdatedAt": secretUpdatedHeader, "Labels": labelsHeader, @@ -89,6 +91,13 @@ func (c *secretContext) CreatedAt() string { return units.HumanDuration(time.Now().UTC().Sub(c.s.Meta.CreatedAt)) + " ago" } +func (c *secretContext) Driver() string { + if c.s.Spec.Driver == nil { + return "" + } + return c.s.Spec.Driver.Name +} + func (c *secretContext) UpdatedAt() string { return units.HumanDuration(time.Now().UTC().Sub(c.s.Meta.UpdatedAt)) + " ago" } @@ -153,6 +162,13 @@ func (ctx *secretInspectContext) Labels() map[string]string { return ctx.Secret.Spec.Labels } +func (ctx *secretInspectContext) Driver() string { + if ctx.Secret.Spec.Driver == nil { + return "" + } + return ctx.Secret.Spec.Driver.Name +} + func (ctx *secretInspectContext) CreatedAt() string { return command.PrettyPrint(ctx.Secret.CreatedAt) } diff --git a/cli/command/formatter/secret_test.go b/cli/command/formatter/secret_test.go index 98fe61315f49..03f6ac1f5789 100644 --- a/cli/command/formatter/secret_test.go +++ b/cli/command/formatter/secret_test.go @@ -28,9 +28,9 @@ func TestSecretContextFormatWrite(t *testing.T) { }, // Table format {Context{Format: NewSecretFormat("table", false)}, - `ID NAME CREATED UPDATED -1 passwords Less than a second ago Less than a second ago -2 id_rsa Less than a second ago Less than a second ago + `ID NAME DRIVER CREATED UPDATED +1 passwords Less than a second ago Less than a second ago +2 id_rsa Less than a second ago Less than a second ago `}, {Context{Format: NewSecretFormat("table {{.Name}}", true)}, `NAME diff --git a/cli/command/formatter/service.go b/cli/command/formatter/service.go index 27200b8be955..d92f92b6f65a 100644 --- a/cli/command/formatter/service.go +++ b/cli/command/formatter/service.go @@ -504,6 +504,9 @@ func (c *serviceContext) Replicas() string { } func (c *serviceContext) Image() string { + if c.service.Spec.TaskTemplate.ContainerSpec == nil { + return "" + } image := c.service.Spec.TaskTemplate.ContainerSpec.Image if ref, err := reference.ParseNormalizedNamed(image); err == nil { // update image string for display, (strips any digest) diff --git a/cli/command/secret/create.go b/cli/command/secret/create.go index 20efaec752a9..8d9c4e0d6d8c 100644 --- a/cli/command/secret/create.go +++ b/cli/command/secret/create.go @@ -17,6 +17,7 @@ import ( type createOptions struct { name string + driver string file string labels opts.ListOpts } @@ -27,17 +28,20 @@ func newSecretCreateCommand(dockerCli command.Cli) *cobra.Command { } cmd := &cobra.Command{ - Use: "create [OPTIONS] SECRET file|-", + Use: "create [OPTIONS] SECRET [file|-]", Short: "Create a secret from a file or STDIN as content", - Args: cli.ExactArgs(2), + Args: cli.RequiresRangeArgs(1, 2), RunE: func(cmd *cobra.Command, args []string) error { options.name = args[0] - options.file = args[1] + if len(args) == 2 { + options.file = args[1] + } return runSecretCreate(dockerCli, options) }, } flags := cmd.Flags() flags.VarP(&options.labels, "label", "l", "Secret labels") + flags.StringVar(&options.driver, "driver", "", "Secret driver") return cmd } @@ -46,21 +50,14 @@ func runSecretCreate(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() + if options.driver != "" && options.file != "" { + return errors.Errorf("When using secret driver secret data must be empty") } - secretData, err := ioutil.ReadAll(in) + secretData, err := readSecretData(dockerCli.In(), options.file) if err != nil { return errors.Errorf("Error reading content from %q: %v", options.file, err) } - spec := swarm.SecretSpec{ Annotations: swarm.Annotations{ Name: options.name, @@ -68,6 +65,11 @@ func runSecretCreate(dockerCli command.Cli, options createOptions) error { }, Data: secretData, } + if options.driver != "" { + spec.Driver = &swarm.Driver{ + Name: options.driver, + } + } r, err := client.SecretCreate(ctx, spec) if err != nil { @@ -77,3 +79,23 @@ func runSecretCreate(dockerCli command.Cli, options createOptions) error { fmt.Fprintln(dockerCli.Out(), r.ID) return nil } + +func readSecretData(in io.ReadCloser, file string) ([]byte, error) { + // Read secret value from external driver + if file == "" { + return nil, nil + } + if file != "-" { + var err error + in, err = system.OpenSequential(file) + if err != nil { + return nil, err + } + defer in.Close() + } + data, err := ioutil.ReadAll(in) + if err != nil { + return nil, err + } + return data, nil +} diff --git a/cli/command/secret/create_test.go b/cli/command/secret/create_test.go index 2c4f9f5d9cb5..90dfcf59bb20 100644 --- a/cli/command/secret/create_test.go +++ b/cli/command/secret/create_test.go @@ -25,12 +25,8 @@ func TestSecretCreateErrors(t *testing.T) { secretCreateFunc func(swarm.SecretSpec) (types.SecretCreateResponse, error) expectedError string }{ - { - args: []string{"too_few"}, - expectedError: "requires exactly 2 argument(s)", - }, {args: []string{"too", "many", "arguments"}, - expectedError: "requires exactly 2 argument(s)", + expectedError: "requires at least 1 and at most 2", }, { args: []string{"name", filepath.Join("testdata", secretDataFile)}, diff --git a/cli/command/secret/inspect_test.go b/cli/command/secret/inspect_test.go index 093624ddfed9..2e8f7f862e12 100644 --- a/cli/command/secret/inspect_test.go +++ b/cli/command/secret/inspect_test.go @@ -164,6 +164,7 @@ func TestSecretInspectPretty(t *testing.T) { }), SecretID("secretID"), SecretName("secretName"), + SecretDriver("driver"), SecretCreatedAt(time.Time{}), SecretUpdatedAt(time.Time{}), ), []byte{}, nil diff --git a/cli/command/secret/ls_test.go b/cli/command/secret/ls_test.go index fb033efea6ec..fae668e999c8 100644 --- a/cli/command/secret/ls_test.go +++ b/cli/command/secret/ls_test.go @@ -64,6 +64,7 @@ func TestSecretList(t *testing.T) { SecretVersion(swarm.Version{Index: 11}), SecretCreatedAt(time.Now().Add(-2*time.Hour)), SecretUpdatedAt(time.Now().Add(-1*time.Hour)), + SecretDriver("driver"), ), }, nil }, diff --git a/cli/command/secret/testdata/secret-inspect-pretty.simple.golden b/cli/command/secret/testdata/secret-inspect-pretty.simple.golden index cc14091e8bb6..efb1e34f2020 100644 --- a/cli/command/secret/testdata/secret-inspect-pretty.simple.golden +++ b/cli/command/secret/testdata/secret-inspect-pretty.simple.golden @@ -2,5 +2,6 @@ ID: secretID Name: secretName Labels: - lbl1=value1 +Driver: driver Created at: 0001-01-01 00:00:00+0000 utc Updated at: 0001-01-01 00:00:00+0000 utc diff --git a/cli/command/secret/testdata/secret-list-with-filter.golden b/cli/command/secret/testdata/secret-list-with-filter.golden index 29983de8e92e..ab7044617977 100644 --- a/cli/command/secret/testdata/secret-list-with-filter.golden +++ b/cli/command/secret/testdata/secret-list-with-filter.golden @@ -1,3 +1,3 @@ -ID NAME CREATED UPDATED -ID-foo foo 2 hours ago About an hour ago -ID-bar bar 2 hours ago About an hour ago +ID NAME DRIVER CREATED UPDATED +ID-foo foo 2 hours ago About an hour ago +ID-bar bar 2 hours ago About an hour ago diff --git a/cli/command/secret/testdata/secret-list.golden b/cli/command/secret/testdata/secret-list.golden index 29983de8e92e..03a553dd0ee4 100644 --- a/cli/command/secret/testdata/secret-list.golden +++ b/cli/command/secret/testdata/secret-list.golden @@ -1,3 +1,3 @@ -ID NAME CREATED UPDATED -ID-foo foo 2 hours ago About an hour ago -ID-bar bar 2 hours ago About an hour ago +ID NAME DRIVER CREATED UPDATED +ID-foo foo 2 hours ago About an hour ago +ID-bar bar driver 2 hours ago About an hour ago diff --git a/cli/command/service/inspect_test.go b/cli/command/service/inspect_test.go index e7b34da2125e..d464197202a0 100644 --- a/cli/command/service/inspect_test.go +++ b/cli/command/service/inspect_test.go @@ -41,7 +41,7 @@ func formatServiceInspect(t *testing.T, format formatter.Format, now time.Time) Labels: map[string]string{"com.label": "foo"}, }, TaskTemplate: swarm.TaskSpec{ - ContainerSpec: swarm.ContainerSpec{ + ContainerSpec: &swarm.ContainerSpec{ Image: "foo/bar@sha256:this_is_a_test", }, Networks: []swarm.NetworkAttachmentConfig{ diff --git a/cli/command/service/opts.go b/cli/command/service/opts.go index f2381881d7c7..fc94c7d913a1 100644 --- a/cli/command/service/opts.go +++ b/cli/command/service/opts.go @@ -592,7 +592,7 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N Labels: opts.ConvertKVStringsToMap(options.labels.GetAll()), }, TaskTemplate: swarm.TaskSpec{ - ContainerSpec: swarm.ContainerSpec{ + ContainerSpec: &swarm.ContainerSpec{ Image: options.image, Args: options.args, Command: options.entrypoint.Value(), diff --git a/cli/command/service/update.go b/cli/command/service/update.go index dba05a1b1eef..03783d8c2c0d 100644 --- a/cli/command/service/update.go +++ b/cli/command/service/update.go @@ -270,7 +270,7 @@ func updateService(ctx context.Context, apiClient client.NetworkAPIClient, flags } } - cspec := &spec.TaskTemplate.ContainerSpec + cspec := spec.TaskTemplate.ContainerSpec task := &spec.TaskTemplate taskResources := func() *swarm.ResourceRequirements { diff --git a/cli/command/service/update_test.go b/cli/command/service/update_test.go index 8f49d52ab8b6..0374e7f28a38 100644 --- a/cli/command/service/update_test.go +++ b/cli/command/service/update_test.go @@ -19,8 +19,8 @@ func TestUpdateServiceArgs(t *testing.T) { flags := newUpdateCommand(nil).Flags() flags.Set("args", "the \"new args\"") - spec := &swarm.ServiceSpec{} - cspec := &spec.TaskTemplate.ContainerSpec + spec := &swarm.ServiceSpec{TaskTemplate: swarm.TaskSpec{ContainerSpec: &swarm.ContainerSpec{}}} + cspec := spec.TaskTemplate.ContainerSpec cspec.Args = []string{"old", "args"} updateService(nil, nil, flags, spec) @@ -452,8 +452,8 @@ func TestUpdateSecretUpdateInPlace(t *testing.T) { } func TestUpdateReadOnly(t *testing.T) { - spec := &swarm.ServiceSpec{} - cspec := &spec.TaskTemplate.ContainerSpec + spec := &swarm.ServiceSpec{TaskTemplate: swarm.TaskSpec{ContainerSpec: &swarm.ContainerSpec{}}} + cspec := spec.TaskTemplate.ContainerSpec // Update with --read-only=true, changed to true flags := newUpdateCommand(nil).Flags() @@ -474,8 +474,8 @@ func TestUpdateReadOnly(t *testing.T) { } func TestUpdateStopSignal(t *testing.T) { - spec := &swarm.ServiceSpec{} - cspec := &spec.TaskTemplate.ContainerSpec + spec := &swarm.ServiceSpec{TaskTemplate: swarm.TaskSpec{ContainerSpec: &swarm.ContainerSpec{}}} + cspec := spec.TaskTemplate.ContainerSpec // Update with --stop-signal=SIGUSR1 flags := newUpdateCommand(nil).Flags() diff --git a/cli/command/stack/deploy_bundlefile.go b/cli/command/stack/deploy_bundlefile.go index 1074210e97dd..5c4d4546f0a9 100644 --- a/cli/command/stack/deploy_bundlefile.go +++ b/cli/command/stack/deploy_bundlefile.go @@ -64,7 +64,7 @@ func deployBundle(ctx context.Context, dockerCli command.Cli, opts deployOptions Labels: convert.AddStackLabel(namespace, service.Labels), }, TaskTemplate: swarm.TaskSpec{ - ContainerSpec: swarm.ContainerSpec{ + ContainerSpec: &swarm.ContainerSpec{ Image: service.Image, Command: service.Command, Args: service.Args, diff --git a/cli/compose/convert/compose.go b/cli/compose/convert/compose.go index 02b1dccb6a4c..0d5f84a75c82 100644 --- a/cli/compose/convert/compose.go +++ b/cli/compose/convert/compose.go @@ -101,9 +101,18 @@ func Secrets(namespace Namespace, secrets map[string]composetypes.SecretConfig) continue } - data, err := ioutil.ReadFile(secret.File) - if err != nil { - return nil, err + var data []byte + var err error + var driver *swarm.Driver + if secret.Driver == "" { + data, err = ioutil.ReadFile(secret.File) + if err != nil { + return nil, err + } + } else { + driver = &swarm.Driver{ + Name: secret.Driver, + } } result = append(result, swarm.SecretSpec{ @@ -111,7 +120,8 @@ func Secrets(namespace Namespace, secrets map[string]composetypes.SecretConfig) Name: namespace.Scope(name), Labels: AddStackLabel(namespace, secret.Labels), }, - Data: data, + Data: data, + Driver: driver, }) } return result, nil diff --git a/cli/compose/convert/compose_test.go b/cli/compose/convert/compose_test.go index 57849dd9bc05..b1a4830d3d8b 100644 --- a/cli/compose/convert/compose_test.go +++ b/cli/compose/convert/compose_test.go @@ -6,6 +6,7 @@ import ( composetypes "github.com/docker/cli/cli/compose/types" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/network" + "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil/tempfile" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -105,6 +106,7 @@ func TestNetworks(t *testing.T) { func TestSecrets(t *testing.T) { namespace := Namespace{name: "foo"} + const driver = "my-driver" secretText := "this is the first secret" secretFile := tempfile.NewTempFile(t, "convert-secrets", secretText) @@ -120,12 +122,22 @@ func TestSecrets(t *testing.T) { External: true, }, }, + "driver": { + Driver: driver, + }, } specs, err := Secrets(namespace, source) assert.NoError(t, err) - require.Len(t, specs, 1) - secret := specs[0] + require.Len(t, specs, 2) + secrets := make(map[string]swarm.SecretSpec) + for _, secret := range specs { + secrets[secret.Annotations.Name] = secret + } + + assert.Equal(t, driver, secrets["foo_driver"].Driver.Name) + + secret := secrets["foo_one"] assert.Equal(t, "foo_one", secret.Name) assert.Equal(t, map[string]string{ "monster": "mash", diff --git a/cli/compose/convert/service.go b/cli/compose/convert/service.go index 730f5e1ee5b5..2140b5d5e550 100644 --- a/cli/compose/convert/service.go +++ b/cli/compose/convert/service.go @@ -128,7 +128,7 @@ func Service( Labels: AddStackLabel(namespace, service.Deploy.Labels), }, TaskTemplate: swarm.TaskSpec{ - ContainerSpec: swarm.ContainerSpec{ + ContainerSpec: &swarm.ContainerSpec{ Image: service.Image, Command: service.Entrypoint, Args: service.Command, diff --git a/cli/compose/schema/bindata.go b/cli/compose/schema/bindata.go index 06fcae3591b1..57a654b6bade 100644 --- a/cli/compose/schema/bindata.go +++ b/cli/compose/schema/bindata.go @@ -131,7 +131,7 @@ func dataConfig_schema_v32Json() (*asset, error) { return a, nil } -var _dataConfig_schema_v33Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x4b\x93\xdb\x2a\x16\xde\xfb\x57\xa8\x74\xef\x2e\xfd\x48\x55\x52\x53\x35\xd9\xcd\x72\x56\x33\xeb\xe9\x72\x54\x18\x1d\xdb\xa4\x11\x10\x40\xee\x76\x52\xfd\xdf\xa7\xf4\x34\x20\x10\xd8\x56\xa7\x7b\xe6\x66\xd5\x6d\xe9\x3b\xc0\x79\x9f\x03\xe8\xe7\x2a\xcb\xf2\x3f\x15\xde\x43\x85\xf2\x2f\x59\xbe\xd7\x5a\x7c\xb9\xbf\xff\xa6\x38\xbb\xed\x9e\xde\x71\xb9\xbb\x2f\x25\xda\xea\xdb\x8f\x9f\xef\xbb\x67\x7f\xe4\x37\x0d\x1d\x29\x1b\x12\xcc\xd9\x96\xec\x8a\xee\x4d\x71\xf8\x74\xf7\xe9\xae\x21\xef\x20\xfa\x28\xa0\x01\xf1\xcd\x37\xc0\xba\x7b\x26\xe1\x7b\x4d\x24\x34\xc4\x0f\xf9\x01\xa4\x22\x9c\xe5\xeb\x9b\x55\xf3\x4e\x48\x2e\x40\x6a\x02\x2a\xff\x92\x35\x8b\xcb\xb2\x11\x32\x3c\x30\x86\x55\x5a\x12\xb6\xcb\xdb\xc7\x2f\xed\x08\x59\x96\x2b\x90\x07\x82\x8d\x11\xc6\xa5\xfe\x71\x7f\x1a\xff\x7e\x84\xdd\xb8\xa3\x1a\x8b\x6d\x9f\x0b\xa4\x35\x48\xf6\xef\xe9\xda\xda\xd7\x5f\x1f\xd0\xed\x8f\x7f\xdc\xfe\xe7\xe3\xed\xdf\xef\x8a\xdb\xf5\x87\x3f\xad\xd7\x8d\x7c\x25\x6c\xbb\xe9\x4b\xd8\x12\x46\x34\xe1\x6c\x9c\x3f\x1f\x91\x2f\xfd\x7f\x2f\xe3\xc4\xa8\x2c\x5b\x30\xa2\xd6\xdc\x5b\x44\x15\xd8\x3c\x33\xd0\x4f\x5c\x3e\xc6\x78\x1e\x61\x6f\xc4\x73\x3f\xbf\x87\x67\x9b\x9d\x03\xa7\x75\x15\xd5\xe0\x80\x7a\x23\x66\xba\xe9\x97\xd1\x9f\x02\x2c\x41\xc7\x4d\xb6\x43\xbd\x99\xc5\x36\xd3\x2f\xc3\x70\x17\x35\x62\x0c\x0f\xa8\x37\x62\xb8\x9b\xfe\x3a\x86\x57\x03\xd3\xb3\xd8\x0e\x61\xcc\xdd\x2e\xd0\x8a\x67\x3e\x51\xf9\xe2\x49\x58\x56\xa3\xb0\x02\x52\x2a\x41\x50\x7e\x6c\x9e\x05\xe4\xd1\x01\x2a\x60\x3a\x1f\x45\x90\x65\xf9\xa6\x26\xb4\x74\x25\xca\x19\xfc\xab\x19\xe2\xc1\x78\x98\x65\x3f\xdd\xd0\x6d\x8c\xd3\xbe\xb7\x7e\x85\x15\x3e\xbe\x0f\xf0\x32\xbe\xc7\x9c\x69\x78\xd6\x2d\x53\xf3\x53\x77\x22\xe0\xf8\x11\xe4\x96\x50\x48\xa5\x40\xb2\xb3\xe2\x80\xc8\x28\x51\xba\xe0\xb2\x28\x09\xd6\x5e\x7a\x8a\x36\x40\xaf\x1a\x01\x23\xbc\x87\x62\x2b\x79\x15\x1d\x65\x5b\x74\x9c\xa8\xfc\xc5\x19\x67\x32\x70\xdc\xb4\x47\x52\xe3\xd7\x7a\xe5\x19\x30\xc7\x48\x14\xa8\x2c\x2d\x91\x22\x29\xd1\x31\xbf\xc9\x72\xa2\xa1\x52\x7e\x69\x67\x79\xcd\xc8\xf7\x1a\xfe\xd9\x43\xb4\xac\xc1\x1d\xb7\x94\x5c\x2c\x3f\xf0\x4e\xf2\x5a\x14\x02\xc9\xc6\xd6\xe7\x2d\x21\xc7\xbc\xaa\x10\x5b\xca\x01\xce\xe1\x23\x41\xf2\x93\x30\x9b\x99\x5e\xd5\xcf\x61\xbe\x1a\x67\xb3\x96\x15\xe0\x26\xce\xcf\xd4\xa5\xe3\x4e\x1d\x77\xeb\x26\x2a\xf2\x5a\xe2\x54\x2f\x6d\xe6\x44\x72\x07\xa9\x71\x20\xcb\xf2\x9a\x94\xe9\xe0\xdd\x39\xe0\x8a\x97\xf6\xba\x59\x5d\x6d\x40\x4e\x5c\xd2\xf6\xac\xe9\xef\xf5\xca\xf7\xc6\xd1\xbe\x46\x84\x81\x2c\x18\xaa\x62\xb2\xca\xb1\x84\x12\x98\x26\x88\x16\x4a\x00\xb6\xe0\x83\xa6\x66\x34\x93\x27\x45\xcd\x5c\xc2\x8e\x28\x2d\x8f\x5e\xe4\x89\x0b\x73\x61\x25\x08\x60\xa5\x2a\xba\x1e\x20\x35\xc0\x59\x03\x8c\x0d\xc1\xa2\x61\xa2\x64\x73\x81\xbb\x1b\xa6\x09\xdd\xcd\xda\x72\x87\xb0\x50\x80\x24\xde\x5f\x48\xcf\x2b\x44\x58\x8a\x52\x81\x69\x79\x14\x9c\x74\x61\xec\xdd\xc5\x27\x60\x87\x62\xb4\x9b\xb3\xc5\x00\xec\x40\x24\x67\xd5\x10\xa4\xd3\x12\xa8\x41\xff\x2c\xb8\x82\xeb\x83\x63\x4f\xf1\x30\x30\x7e\x33\xfa\xf4\xda\x96\x5e\xbe\xe5\xb2\x42\xcd\x62\x87\xb9\x4d\x1f\xb6\xa6\x9a\x5a\x9e\x29\x40\x93\x87\xa6\xf0\x45\xb4\xa0\x84\x3d\x2e\x6f\xe2\xf0\xac\x25\x2a\xf6\x5c\xe9\x4b\x6a\x94\x7c\x0f\x88\xea\x3d\xde\x03\x7e\x9c\x21\x37\x51\x16\x35\x57\x3a\xc5\xc8\x49\x85\x76\x71\x90\xc0\x31\xc8\xc5\xb5\x58\xbe\xa8\xf0\x8d\x61\xf9\x6e\xd7\x40\x43\x16\x37\xa9\xed\xfb\xd7\xb1\xaa\xb8\x94\xe4\x00\x32\xb5\xc4\xe5\xe2\xd4\x92\xb8\x2f\x53\xb2\x79\xb4\x3f\xb3\xa0\x5f\xef\xba\xf6\x6c\xc6\xab\xda\xff\x28\xcd\xd7\xd3\x94\x39\x4d\x9a\xee\x13\x87\xc3\xb4\x3a\xd7\xd2\x4a\x85\x70\x53\xce\x4a\x50\x01\xbd\x9e\xa0\xfd\x86\x47\x31\xc9\xf9\x27\xec\x04\x3c\x49\xac\xa1\x48\x7d\x76\x22\xcc\x2e\xea\xb0\x92\x54\x17\x6d\xb1\x23\xdc\x84\x96\x97\xba\xcc\xd3\x72\xe3\x26\xd6\xe2\x10\x25\x48\x41\xdc\xd9\x83\x82\xb4\x46\x23\xe2\xf0\x39\xd1\x26\x7c\xb4\x7f\x9b\xa5\x0d\x90\x06\xc7\x4c\x6f\xdd\x22\x43\x99\x25\x2a\xa5\xde\x85\xac\xe3\x45\xeb\x6b\x76\x96\xc2\x2e\xbc\xed\x58\xd1\x46\x08\xd3\xc1\x04\x97\xfa\x97\xf4\x42\xa7\x38\x75\x4a\xf8\xdd\xe4\xd3\xf6\xc8\x55\x77\x12\xd1\xeb\xf4\x54\x33\x51\xca\x83\xf6\x74\x54\x84\x69\xd8\x35\xad\x8c\x3f\x09\xd4\x1b\x4a\xd4\x1e\xca\x73\x68\x24\xd7\x1c\x73\x9a\xe6\x18\xde\x0d\x9a\x74\x67\x98\xe9\xaf\x2e\xaa\xcd\x84\x24\x07\x42\x61\xe7\x70\xbc\xe1\x9c\x02\x62\x56\xa2\x90\x80\xca\x82\x33\x7a\x4c\x40\x2a\x8d\x64\x74\x57\x42\x01\xae\x25\xd1\xc7\x82\x0b\xbd\x78\x55\xa8\xf6\x55\xa1\xc8\x0f\xb0\x7d\xef\x64\xf5\xfd\x40\x6b\x67\x41\xce\x16\x77\xf6\x7b\x2b\xe2\x2f\xb3\x15\xa1\x8e\x0a\xeb\xcb\x6a\x6b\xa5\x4b\xc2\x0a\x2e\x80\x45\x7d\x43\x69\x2e\x8a\x9d\x44\x18\x0a\x01\x92\x70\xaf\x28\xac\x00\x5b\xd6\x12\x35\xf3\x4f\x87\x51\x64\xc7\x90\x3f\xee\x18\x50\x5d\x89\xed\x85\x9b\x00\x5a\xc7\x9d\xbd\xa6\xa4\x22\x61\xa7\xf1\x58\x6d\x42\xbd\xd6\xd5\x6a\xfe\x12\x6d\xa6\x3c\x4b\x0a\xd9\x33\x1d\xc2\x7c\x83\x90\xd0\x19\xec\x91\x3c\x23\x75\xb4\x8e\xb9\x0d\xe4\x27\x5f\xdf\xe0\x5d\x97\x75\x58\xdd\x8e\x77\xd3\x2f\x64\xed\xc5\x9f\x55\x7a\xb9\xcb\x58\x07\xab\x1f\xbf\x53\xd5\x2a\xda\xc4\xb5\x18\xa6\xe6\x1a\x90\x11\x3a\x3d\x75\xcd\xfe\x27\x22\xb4\xa5\xa3\x16\xee\xd1\x4d\x42\x1c\xef\x67\x4a\x8c\x9d\xaf\x1d\xf5\x93\x2b\x02\x83\x06\x73\xa6\x88\xd2\xc0\xb0\x7f\x7f\xd5\x4b\xb4\x21\x93\xc3\x8b\xa9\x50\xe6\xfb\xae\xb4\xae\xab\x45\xa1\x5d\x17\x6f\x93\x1b\x9d\x74\x5f\xed\x0f\xe4\x7f\x09\x2b\x8c\x63\x2e\x02\xaa\x49\x67\xe3\xdc\x34\xeb\x6c\x5d\xcc\xd4\xa1\xa1\x90\xf1\xc4\xe5\x63\x93\x90\x4a\xe2\x8f\x1c\x2b\x87\xe4\x8c\x23\x7d\x67\xaf\x6f\x18\xc0\x77\x56\x6d\x42\xa3\x67\xfb\xf3\xe7\xe6\x3d\x28\x78\xa6\x4d\x14\xda\x38\xe7\x12\xbe\x44\xdb\x64\x06\x79\x88\xe7\x7b\x09\x5a\x12\xe7\x28\x61\x28\x9a\xcc\xdc\x0e\xea\x7d\x6e\xb8\x6b\x52\x01\xaf\xfd\x61\x68\x65\x1a\x4e\x4f\x94\x1b\x67\xfe\x11\xa5\x1a\x48\x57\xa7\x0f\xc6\x01\x52\xd7\x97\x47\x15\x97\x92\xb0\x80\x95\xed\xd1\x46\x52\x76\x93\x20\x28\xc1\x48\xc5\x2a\x88\x2b\x76\x81\x6b\x51\x22\x0d\x45\x7f\x6d\xe4\x9c\x9a\x6d\xa6\x58\x13\x48\x22\x4a\x81\x12\x55\xa5\x14\x3f\x79\x09\x14\x79\xa3\x7f\xb4\xee\x6d\xc9\xb7\x88\xd0\x5a\x42\x81\x70\x30\x4c\x3b\x14\x15\x67\x44\x73\x6f\x38\x49\x9b\xb2\x42\xcf\xc5\x30\x6d\x0b\x89\xb5\x24\x76\x37\x9e\xba\x81\x6b\x58\x42\x97\xbb\xcf\x2b\xab\x67\x54\x74\x2a\xd2\x03\x16\x33\xcc\x38\x61\x5d\x82\x6a\xc2\xce\xb8\xbf\x1e\xa5\x8f\x06\xf8\x7e\x7b\xa0\x10\x9c\x92\xae\x0a\x58\x82\x43\xcc\x59\x27\xe4\x14\x83\xb8\xd2\x02\x1b\x73\x68\x7a\x98\x4a\xe8\xa8\xb3\xb6\x04\x4f\x84\x95\xfc\xe9\x8c\x09\x97\x33\x25\x41\x11\x06\x27\x38\x5e\x2b\x68\xa5\x25\x22\x4c\x9f\x7d\x9c\xe4\x8a\x45\x48\xd8\x82\x04\x36\x35\xf4\x6c\xbe\xac\xcf\xc2\xa5\x7d\x8c\xb7\x38\x87\x3d\x42\x89\xa6\xbe\x7d\x83\x5d\xbd\x6b\x95\x7f\x45\x81\x34\x7a\x71\x24\x91\x8e\xb8\x68\x69\x14\x4a\x9e\x58\xd4\xd1\xa3\xa9\x0a\x2a\x3e\x7f\x0d\xe3\x8a\x8b\xc8\x31\x16\x07\xd8\x02\x85\x42\xd2\x59\x66\x8f\x2a\xb8\x58\x7e\x33\x25\x7e\x5e\xb9\x8e\x87\x6d\x22\x50\xb5\x54\x0c\x49\x3e\xdd\xcd\xbd\x95\x4a\xf6\x0e\xa2\x43\xbd\x61\x81\x5e\xf9\x7d\x47\x07\xfb\xe6\x44\x7b\x31\x23\xa0\xd5\x87\xb1\x0d\xb9\x19\x65\xb5\x4e\x56\x71\xf0\x56\xc4\x72\xeb\x6f\x3b\x22\x77\x07\xd4\xd7\x3a\x21\xad\x11\xde\x27\x75\x59\x67\x96\xd6\x57\xc4\xa1\xc9\x5e\x80\x37\x0c\xf5\xa8\xdf\x51\xe8\xff\xc4\x66\x7f\x9d\x7d\xf5\xdf\x42\x44\xef\xe4\xb7\xa8\x8b\xf3\x78\xc2\x95\xca\x77\xa0\xb3\x37\x56\xc5\x24\x89\x79\x55\xd1\xa3\x7e\xab\xe2\x55\xbd\xc2\x3e\xed\x32\x54\x32\xdd\xfc\x9a\x93\xe4\xb9\x5f\x31\xac\xed\x65\xb8\x30\xcf\x97\x83\x76\x5d\x33\x77\x16\x3e\x40\x02\x9b\xad\xce\xa4\xbd\x10\xe7\x39\x5f\x30\xee\xdf\x7d\x98\xa9\xde\xe6\xae\xce\xbd\x52\xd9\xb3\xc0\x3d\x03\xbf\x4e\x9d\xc6\x78\x90\xee\xf4\xe3\xa8\xb0\xff\x0f\xf4\x93\x4f\xa5\x1a\x3e\xd9\x71\xb2\x39\xfb\xd3\x3e\x59\xea\x3e\x73\x5a\x5b\xf2\x71\x20\xdd\x45\x54\x23\xd1\xae\xcd\xbd\x82\xe0\xcd\x79\xdf\x07\x54\xee\xb9\xd6\xf0\x21\x53\xe0\xa8\x7d\x65\xfe\x6d\x3f\x3a\x5b\xbd\xac\xfe\x1b\x00\x00\xff\xff\x88\x06\xbb\x83\xde\x3b\x00\x00") +var _dataConfig_schema_v33Json = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5b\x4b\x93\xdb\x2a\x16\xde\xfb\x57\xa8\x74\xef\xee\xf6\x23\x55\x49\x4d\xd5\x64\x37\xcb\x59\xcd\xac\xa7\xcb\x51\x61\x74\x6c\x93\x46\x40\x00\xb9\xdb\x49\xf5\x7f\x9f\xd2\xd3\x80\x40\x60\x5b\x9d\xee\x99\x64\xd5\x6d\xe9\x3b\xc0\x79\x9f\x03\xe8\xc7\x2a\xcb\xf2\x3f\x15\xde\x43\x85\xf2\xcf\x59\xbe\xd7\x5a\x7c\xbe\xbf\xff\xaa\x38\xbb\xed\x9e\xde\x71\xb9\xbb\x2f\x25\xda\xea\xdb\x0f\x9f\xee\xbb\x67\x7f\xe4\x37\x0d\x1d\x29\x1b\x12\xcc\xd9\x96\xec\x8a\xee\x4d\x71\xf8\x78\xf7\xf1\xae\x21\xef\x20\xfa\x28\xa0\x01\xf1\xcd\x57\xc0\xba\x7b\x26\xe1\x5b\x4d\x24\x34\xc4\x0f\xf9\x01\xa4\x22\x9c\xe5\xeb\x9b\x55\xf3\x4e\x48\x2e\x40\x6a\x02\x2a\xff\x9c\x35\x8b\xcb\xb2\x11\x32\x3c\x30\x86\x55\x5a\x12\xb6\xcb\xdb\xc7\x2f\xed\x08\x59\x96\x2b\x90\x07\x82\x8d\x11\xc6\xa5\xfe\x71\x7f\x1a\xff\x7e\x84\xdd\xb8\xa3\x1a\x8b\x6d\x9f\x0b\xa4\x35\x48\xf6\xef\xe9\xda\xda\xd7\x5f\x1e\xd0\xed\xf7\x7f\xdc\xfe\xe7\xc3\xed\xdf\xef\x8a\xdb\xf5\x5f\x7f\x5a\xaf\x1b\xf9\x4a\xd8\x76\xd3\x97\xb0\x25\x8c\x68\xc2\xd9\x38\x7f\x3e\x22\x5f\xfa\xff\x5e\xc6\x89\x51\x59\xb6\x60\x44\xad\xb9\xb7\x88\x2a\xb0\x79\x66\xa0\x9f\xb8\x7c\x8c\xf1\x3c\xc2\xde\x88\xe7\x7e\x7e\x0f\xcf\x36\x3b\x07\x4e\xeb\x2a\xaa\xc1\x01\xf5\x46\xcc\x74\xd3\x2f\xa3\x3f\x05\x58\x82\x8e\x9b\x6c\x87\x7a\x33\x8b\x6d\xa6\x5f\x86\xe1\x2e\x6a\xc4\x18\x1e\x50\x6f\xc4\x70\x37\xfd\x75\x0c\xaf\x06\xa6\x67\xb1\x1d\xc2\x98\xbb\x5d\xa0\x15\xcf\x7c\xa2\xf2\xc5\x93\xb0\xac\x46\x61\x05\xa4\x54\x82\xa0\xfc\xd8\x3c\x0b\xc8\xa3\x03\x54\xc0\x74\x3e\x8a\x20\xcb\xf2\x4d\x4d\x68\xe9\x4a\x94\x33\xf8\x57\x33\xc4\x83\xf1\x30\xcb\x7e\xb8\xa1\xdb\x18\xa7\x7d\x6f\xfd\x0a\x2b\x7c\x7c\x1f\xe0\x65\x7c\x8f\x39\xd3\xf0\xac\x5b\xa6\xe6\xa7\xee\x44\xc0\xf1\x23\xc8\x2d\xa1\x90\x4a\x81\x64\x67\xc5\x01\x91\x51\xa2\x74\xc1\x65\x51\x12\xac\xbd\xf4\x14\x6d\x80\x5e\x35\x02\x46\x78\x0f\xc5\x56\xf2\x2a\x3a\xca\xb6\xe8\x38\x51\xf9\x8b\x33\xce\x64\xe0\xb8\x69\x8f\xa4\xc6\xaf\xf5\xca\x33\x60\x8e\x91\x28\x50\x59\x5a\x22\x45\x52\xa2\x63\x7e\x93\xe5\x44\x43\xa5\xfc\xd2\xce\xf2\x9a\x91\x6f\x35\xfc\xb3\x87\x68\x59\x83\x3b\x6e\x29\xb9\x58\x7e\xe0\x9d\xe4\xb5\x28\x04\x92\x8d\xad\xcf\x5b\x42\x8e\x79\x55\x21\xb6\x94\x03\x9c\xc3\x47\x82\xe4\x27\x61\x36\x33\xbd\xaa\x9f\xc3\x7c\x35\xce\x66\x2d\x2b\xc0\x4d\x9c\x9f\xa9\x4b\xc7\x9d\x3a\xee\xd6\x4d\x54\xe4\xb5\xc4\xa9\x5e\xda\xcc\x89\xe4\x0e\x52\xe3\x40\x96\xe5\x35\x29\xd3\xc1\xbb\x73\xc0\x15\x2f\xed\x75\xb3\xba\xda\x80\x9c\xb8\xa4\xed\x59\xd3\xdf\xeb\x95\xef\x8d\xa3\x7d\x8d\x08\x03\x59\x30\x54\xc5\x64\x95\x63\x09\x25\x30\x4d\x10\x2d\x94\x00\x6c\xc1\x07\x4d\xcd\x68\x26\x4f\x8a\x9a\xb9\x84\x1d\x51\x5a\x1e\xbd\xc8\x13\x17\xe6\xc2\x4a\x10\xc0\x4a\x55\x74\x3d\x40\x6a\x80\xb3\x06\x18\x1b\x82\x45\xc3\x44\xc9\xe6\x02\x77\x37\x4c\x13\xba\x9b\xb5\xe5\x0e\x61\xa1\x00\x49\xbc\xbf\x90\x9e\x57\x88\xb0\x14\xa5\x02\xd3\xf2\x28\x38\xe9\xc2\xd8\xbb\x8b\x4f\xc0\x0e\xc5\x68\x37\x67\x8b\x01\xd8\x81\x48\xce\xaa\x21\x48\xa7\x25\x50\x83\xfe\x59\x70\x05\xd7\x07\xc7\x9e\xe2\x61\x60\xfc\x66\xf4\xe9\xb5\x2d\xbd\x7c\xcb\x65\x85\x9a\xc5\x0e\x73\x9b\x3e\x6c\x4d\x35\xb5\x3c\x53\x80\x26\x0f\x4d\xe1\x8b\x68\x41\x09\x7b\x5c\xde\xc4\xe1\x59\x4b\x54\xec\xb9\xd2\x97\xd4\x28\xf9\x1e\x10\xd5\x7b\xbc\x07\xfc\x38\x43\x6e\xa2\x2c\x6a\xae\x74\x8a\x91\x93\x0a\xed\xe2\x20\x81\x63\x90\x8b\x6b\xb1\x7c\x51\xe1\x1b\xc3\xf2\xdd\xae\x81\x86\x2c\x6e\x52\xdb\xf7\xaf\x63\x55\x71\x29\xc9\x01\x64\x6a\x89\xcb\xc5\xa9\x25\x71\x5f\xa6\x64\xf3\x68\x7f\x66\x41\xbf\xdc\x75\xed\xd9\x8c\x57\xb5\xff\x51\x9a\xaf\xa7\x29\x73\x9a\x34\xdd\x27\x0e\x87\x69\x75\xae\xa5\x95\x0a\xe1\xa6\x9c\x95\xa0\x02\x7a\x3d\x41\xfb\x0d\x8f\x62\x92\xf3\x4f\xd8\x09\x78\x92\x58\x43\x91\xfa\xec\x44\x98\x5d\xd4\x61\x25\xa9\x2e\xda\x62\x47\xb8\x09\x2d\x2f\x75\x99\xa7\xe5\xc6\x4d\xac\xc5\x21\x4a\x90\x82\xb8\xb3\x07\x05\x69\x8d\x46\xc4\xe1\x53\xa2\x4d\xf8\x68\xff\x36\x4b\x1b\x20\x0d\x8e\x99\xde\xba\x45\x86\x32\x4b\x54\x4a\xbd\x0b\x59\xc7\x8b\xd6\xd7\xec\x2c\x85\x5d\x78\xdb\xb1\xa2\x8d\x10\xa6\x83\x09\x2e\xf5\x4f\xe9\x85\x4e\x71\xea\x94\xf0\xbb\xc9\xa7\xed\x91\xab\xee\x24\xa2\xd7\xe9\xa9\x66\xa2\x94\x07\xed\xe9\xa8\x08\xd3\xb0\x6b\x5a\x19\x7f\x12\xa8\x37\x94\xa8\x3d\x94\xe7\xd0\x48\xae\x39\xe6\x34\xcd\x31\xbc\x1b\x34\xe9\xce\x30\xd3\x5f\x5d\x54\x9b\x09\x49\x0e\x84\xc2\xce\xe1\x78\xc3\x39\x05\xc4\xac\x44\x21\x01\x95\x05\x67\xf4\x98\x80\x54\x1a\xc9\xe8\xae\x84\x02\x5c\x4b\xa2\x8f\x05\x17\x7a\xf1\xaa\x50\xed\xab\x42\x91\xef\x60\xfb\xde\xc9\xea\xfb\x81\xd6\xce\x82\x9c\x2d\xee\xec\xf7\x56\xc4\x2f\xb3\x15\xa1\x8e\x0a\xeb\xcb\x6a\x6b\xa5\x4b\xc2\x0a\x2e\x80\x45\x7d\x43\x69\x2e\x8a\x9d\x44\x18\x0a\x01\x92\x70\xaf\x28\xac\x00\x5b\xd6\x12\x35\xf3\x4f\x87\x51\x64\xc7\x90\x3f\xee\x18\x50\x5d\x89\xed\x85\x9b\x00\x5a\xc7\x9d\xbd\xa6\xa4\x22\x61\xa7\xf1\x58\x6d\x42\xbd\xd6\xd5\x6a\xfe\x12\x6d\xa6\x3c\x4b\x0a\xd9\x33\x1d\xc2\x7c\x83\x90\xd0\x19\xec\x91\x3c\x23\x75\xb4\x8e\xb9\x0d\xe4\x27\x5f\xdf\xe0\x5d\x97\x75\x58\xdd\x8e\x77\xd3\x2f\x64\xed\xc5\x9f\x55\x7a\xb9\xcb\x58\x07\xab\x1f\xbf\x53\xd5\x2a\xda\xc4\xb5\x18\xa6\xe6\x1a\x90\x11\x3a\x3d\x75\xcd\xfe\x27\x22\xb4\xa5\xa3\x16\xee\xd1\x4d\x42\x1c\xef\x67\x4a\x8c\x9d\xaf\x1d\xf5\x93\x2b\x02\x83\x06\x73\xa6\x88\xd2\xc0\xb0\x7f\x7f\xd5\x4b\xb4\x21\x93\xc3\x8b\xa9\x50\xe6\xfb\xae\xb4\xae\xab\x45\xa1\x5d\x17\x6f\x93\x1b\x9d\x74\x5f\xed\x0f\xe4\x7f\x0a\x2b\x8c\x63\x2e\x02\xaa\x49\x67\xe3\xdc\x34\xeb\x6c\x5d\xcc\xd4\xa1\xa1\x90\xf1\xc4\xe5\x63\x93\x90\x4a\xe2\x8f\x1c\x2b\x87\xe4\x8c\x23\x7d\x67\xaf\x6f\x18\xc0\x77\x56\x6d\x42\xa3\x67\xfb\xf3\xe7\xe6\x3d\x28\x78\xa6\x4d\x14\xda\x38\xe7\x12\xbe\x44\xdb\x64\x06\x79\x88\xe7\x7b\x09\x5a\x12\xe7\x28\x61\x28\x9a\xcc\xdc\x0e\xea\x7d\x6e\xb8\x6b\x52\x01\xaf\xfd\x61\x68\x65\x1a\x4e\x4f\x94\x1b\x67\xfe\x11\xa5\x1a\x48\x57\xa7\x0f\xc6\x01\x52\xd7\x97\x47\x15\x97\x92\xb0\x80\x95\xed\xd1\x46\x52\x76\x93\x20\x28\xc1\x48\xc5\x2a\x88\x2b\x76\x81\x6b\x51\x22\x0d\x45\x7f\x6d\xe4\x9c\x9a\x6d\xa6\x58\x13\x48\x22\x4a\x81\x12\x55\xa5\x14\x3f\x79\x09\x14\x79\xa3\x7f\xb4\xee\x6d\xc9\xb7\x88\xd0\x5a\x42\x81\x70\x30\x4c\x3b\x14\x15\x67\x44\x73\x6f\x38\x49\x9b\xb2\x42\xcf\xc5\x30\x6d\x0b\x89\xb5\x24\x76\x37\x9e\xba\x81\x6b\x58\x42\x97\xbb\xcf\x2b\xab\x67\x54\x74\x2a\xd2\x03\x16\x33\xcc\x38\x61\x5d\x82\x6a\xc2\xce\xb8\xbf\x1e\xa5\x8f\x06\xf8\x7e\x7b\xa0\x10\x9c\x92\xae\x0a\x58\x82\x43\xcc\x59\x27\xe4\x14\x83\xb8\xd2\x02\x1b\x73\x68\x7a\x98\x4a\xe8\xa8\xb3\xb6\x04\x4f\x84\x95\xfc\xe9\x8c\x09\x97\x33\x25\x41\x11\x06\x27\x38\x5e\x2b\x68\xa5\x25\x22\x4c\x9f\x7d\x9c\xe4\x8a\x45\x48\xd8\x82\x04\x36\x35\xf4\x6c\xbe\xac\xcf\xc2\xa5\x7d\x8c\xb7\x38\x87\x3d\x42\x89\xa6\xbe\x7d\x83\x5d\xbd\x6b\x95\x7f\x45\x81\x34\x7a\x71\x24\x91\x8e\xb8\x68\x69\x14\x4a\x9e\x58\xd4\xd1\xa3\xa9\x0a\x2a\x3e\x7f\x0d\xe3\x8a\x8b\xc8\x31\x16\x07\xd8\x02\x85\x42\xd2\x59\x66\x8f\x2a\xb8\x58\x7e\x33\x25\x7e\x5e\xb9\x8e\x87\x6d\x22\x50\xb5\x54\x0c\x49\x3e\xdd\xcd\xbd\x95\x4a\xf6\x0e\xa2\x43\xbd\x61\x81\x5e\xf9\x7d\x47\x07\xfb\xe6\x44\x7b\x31\x23\xa0\xd5\x87\xb1\x0d\xb9\x19\x65\xb5\x4e\x56\x71\xf0\x56\xc4\x72\xeb\x6f\x3b\x22\x77\x07\xd4\xd7\x3a\x21\xad\x11\xde\x27\x75\x59\x67\x96\xd6\x57\xc4\xa1\xc9\x5e\x80\x37\x0c\xf5\xa8\xdf\x51\xe8\xff\xc4\x66\x7f\x9e\x7d\xf5\xdf\x42\x44\xef\xe4\xb7\xa8\x8b\xf3\x78\xc2\x95\xca\x44\xcb\x7b\x7b\xcd\xbe\xb1\xc2\x26\xa9\xce\xab\xb0\x1e\xf5\xaa\x0a\xfb\xe5\x55\xe1\x9c\x89\x19\x2a\x99\x6e\x91\xcd\x49\xf2\xdc\x6f\x1d\xd6\xf6\x32\x5c\x98\xe7\xfb\x42\xbb\xfa\x99\x3b\x31\x1f\x20\x81\x2d\x59\x67\xd2\x5e\x88\xf3\x9c\x2f\x98\x1d\xee\xfe\x9a\xa9\xf1\xe6\x2e\xd8\xbd\x52\x71\xb4\xc0\x6d\x04\xbf\x4e\x9d\xf6\x79\x90\xee\xf4\x13\xaa\xb0\xff\x0f\xf4\x93\x0f\xaa\x1a\x3e\xd9\x71\xb2\x85\xfb\xc3\x3e\x7f\xea\x3e\x86\x5a\x5b\xf2\x71\x20\xdd\x75\x55\x23\x1d\xaf\xcd\x1d\x85\xe0\xfd\x7a\xdf\x67\x56\xee\xe9\xd7\xf0\xb9\x53\xe0\x40\x7e\x65\xfe\x6d\x3f\x4d\x5b\xbd\xac\xfe\x1b\x00\x00\xff\xff\x1a\xbe\xa0\x35\x04\x3c\x00\x00") func dataConfig_schema_v33JsonBytes() ([]byte, error) { return bindataRead( @@ -248,6 +248,7 @@ type bintree struct { Func func() (*asset, error) Children map[string]*bintree } + var _bintree = &bintree{nil, map[string]*bintree{ "data": &bintree{nil, map[string]*bintree{ "config_schema_v3.0.json": &bintree{dataConfig_schema_v30Json, map[string]*bintree{}}, @@ -303,4 +304,3 @@ func _filePath(dir, name string) string { cannonicalName := strings.Replace(name, "\\", "/", -1) return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) } - diff --git a/cli/compose/schema/data/config_schema_v3.3.json b/cli/compose/schema/data/config_schema_v3.3.json index e69116c3889e..c202b2ddca0b 100644 --- a/cli/compose/schema/data/config_schema_v3.3.json +++ b/cli/compose/schema/data/config_schema_v3.3.json @@ -461,6 +461,7 @@ "type": "object", "properties": { "file": {"type": "string"}, + "driver": {"type": "string"}, "external": { "type": ["boolean", "object"], "properties": { diff --git a/cli/compose/types/types.go b/cli/compose/types/types.go index 1eecc124f6b1..fd3422fd2825 100644 --- a/cli/compose/types/types.go +++ b/cli/compose/types/types.go @@ -331,7 +331,12 @@ type fileObjectConfig struct { } // SecretConfig for a secret -type SecretConfig fileObjectConfig +type SecretConfig struct { + File string + External External + Labels Labels + Driver string +} // ConfigObjConfig is the config for the swarm "Config" object type ConfigObjConfig fileObjectConfig diff --git a/cli/internal/test/builders/secret.go b/cli/internal/test/builders/secret.go index 9e0f910e9373..3cd5f7872ae2 100644 --- a/cli/internal/test/builders/secret.go +++ b/cli/internal/test/builders/secret.go @@ -32,6 +32,15 @@ func SecretName(name string) func(secret *swarm.Secret) { } } +// SecretDriver sets the secret's driver name +func SecretDriver(driver string) func(secret *swarm.Secret) { + return func(secret *swarm.Secret) { + secret.Spec.Driver = &swarm.Driver{ + Name: driver, + } + } +} + // SecretID sets the secret's ID func SecretID(ID string) func(secret *swarm.Secret) { return func(secret *swarm.Secret) { diff --git a/cli/internal/test/builders/service.go b/cli/internal/test/builders/service.go index 71718268e17e..0970e5449bcb 100644 --- a/cli/internal/test/builders/service.go +++ b/cli/internal/test/builders/service.go @@ -56,7 +56,7 @@ func ReplicatedService(replicas uint64) func(*swarm.Service) { // ServiceImage sets the service's image func ServiceImage(image string) func(*swarm.Service) { return func(service *swarm.Service) { - service.Spec.TaskTemplate = swarm.TaskSpec{ContainerSpec: swarm.ContainerSpec{Image: image}} + service.Spec.TaskTemplate = swarm.TaskSpec{ContainerSpec: &swarm.ContainerSpec{Image: image}} } } diff --git a/cli/internal/test/builders/task.go b/cli/internal/test/builders/task.go index 479b6f14c5fb..40efc3d93a3d 100644 --- a/cli/internal/test/builders/task.go +++ b/cli/internal/test/builders/task.go @@ -140,7 +140,7 @@ func WithTaskSpec(specBuilders ...func(*swarm.TaskSpec)) func(*swarm.Task) { // Any number of taskSpec function builder can be pass to augment it. func TaskSpec(specBuilders ...func(*swarm.TaskSpec)) *swarm.TaskSpec { taskSpec := &swarm.TaskSpec{ - ContainerSpec: swarm.ContainerSpec{ + ContainerSpec: &swarm.ContainerSpec{ Image: "myimage:mytag", }, }