Signed-off-by: Daniel Nephin <dnephin@docker.com>
| ... | ... |
@@ -62,7 +62,7 @@ func runCreate(dockerCli *command.DockerCli, opts *serviceOptions) error {
|
| 62 | 62 |
specifiedSecrets := opts.secrets.Value() |
| 63 | 63 |
if len(specifiedSecrets) > 0 {
|
| 64 | 64 |
// parse and validate secrets |
| 65 |
- secrets, err := parseSecrets(apiClient, specifiedSecrets) |
|
| 65 |
+ secrets, err := ParseSecrets(apiClient, specifiedSecrets) |
|
| 66 | 66 |
if err != nil {
|
| 67 | 67 |
return err |
| 68 | 68 |
} |
| ... | ... |
@@ -10,9 +10,9 @@ import ( |
| 10 | 10 |
"golang.org/x/net/context" |
| 11 | 11 |
) |
| 12 | 12 |
|
| 13 |
-// parseSecrets retrieves the secrets from the requested names and converts |
|
| 13 |
+// ParseSecrets retrieves the secrets from the requested names and converts |
|
| 14 | 14 |
// them to secret references to use with the spec |
| 15 |
-func parseSecrets(client client.SecretAPIClient, requestedSecrets []*types.SecretRequestOption) ([]*swarmtypes.SecretReference, error) {
|
|
| 15 |
+func ParseSecrets(client client.SecretAPIClient, requestedSecrets []*types.SecretRequestOption) ([]*swarmtypes.SecretReference, error) {
|
|
| 16 | 16 |
secretRefs := make(map[string]*swarmtypes.SecretReference) |
| 17 | 17 |
ctx := context.Background() |
| 18 | 18 |
|
| ... | ... |
@@ -443,7 +443,7 @@ func getUpdatedSecrets(apiClient client.SecretAPIClient, flags *pflag.FlagSet, s |
| 443 | 443 |
if flags.Changed(flagSecretAdd) {
|
| 444 | 444 |
values := flags.Lookup(flagSecretAdd).Value.(*opts.SecretOpt).Value() |
| 445 | 445 |
|
| 446 |
- addSecrets, err := parseSecrets(apiClient, values) |
|
| 446 |
+ addSecrets, err := ParseSecrets(apiClient, values) |
|
| 447 | 447 |
if err != nil {
|
| 448 | 448 |
return nil, err |
| 449 | 449 |
} |
| ... | ... |
@@ -126,7 +126,16 @@ func deployCompose(ctx context.Context, dockerCli *command.DockerCli, opts deplo |
| 126 | 126 |
if err := createNetworks(ctx, dockerCli, namespace, networks); err != nil {
|
| 127 | 127 |
return err |
| 128 | 128 |
} |
| 129 |
- services, err := convert.Services(namespace, config) |
|
| 129 |
+ |
|
| 130 |
+ secrets, err := convert.Secrets(namespace, config.Secrets) |
|
| 131 |
+ if err != nil {
|
|
| 132 |
+ return err |
|
| 133 |
+ } |
|
| 134 |
+ if err := createSecrets(ctx, dockerCli, namespace, secrets); err != nil {
|
|
| 135 |
+ return err |
|
| 136 |
+ } |
|
| 137 |
+ |
|
| 138 |
+ services, err := convert.Services(namespace, config, dockerCli.Client()) |
|
| 130 | 139 |
if err != nil {
|
| 131 | 140 |
return err |
| 132 | 141 |
} |
| ... | ... |
@@ -211,6 +220,24 @@ func validateExternalNetworks( |
| 211 | 211 |
return nil |
| 212 | 212 |
} |
| 213 | 213 |
|
| 214 |
+func createSecrets( |
|
| 215 |
+ ctx context.Context, |
|
| 216 |
+ dockerCli *command.DockerCli, |
|
| 217 |
+ namespace convert.Namespace, |
|
| 218 |
+ secrets []swarm.SecretSpec, |
|
| 219 |
+) error {
|
|
| 220 |
+ client := dockerCli.Client() |
|
| 221 |
+ |
|
| 222 |
+ for _, secret := range secrets {
|
|
| 223 |
+ fmt.Fprintf(dockerCli.Out(), "Creating secret %s\n", secret.Name) |
|
| 224 |
+ _, err := client.SecretCreate(ctx, secret) |
|
| 225 |
+ if err != nil {
|
|
| 226 |
+ return err |
|
| 227 |
+ } |
|
| 228 |
+ } |
|
| 229 |
+ return nil |
|
| 230 |
+} |
|
| 231 |
+ |
|
| 214 | 232 |
func createNetworks( |
| 215 | 233 |
ctx context.Context, |
| 216 | 234 |
dockerCli *command.DockerCli, |
| ... | ... |
@@ -1,8 +1,11 @@ |
| 1 | 1 |
package convert |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "io/ioutil" |
|
| 5 |
+ |
|
| 4 | 6 |
"github.com/docker/docker/api/types" |
| 5 | 7 |
networktypes "github.com/docker/docker/api/types/network" |
| 8 |
+ "github.com/docker/docker/api/types/swarm" |
|
| 6 | 9 |
composetypes "github.com/docker/docker/cli/compose/types" |
| 7 | 10 |
) |
| 8 | 11 |
|
| ... | ... |
@@ -82,3 +85,27 @@ func Networks(namespace Namespace, networks networkMap, servicesNetworks map[str |
| 82 | 82 |
|
| 83 | 83 |
return result, externalNetworks |
| 84 | 84 |
} |
| 85 |
+ |
|
| 86 |
+// Secrets converts secrets from the Compose type to the engine API type |
|
| 87 |
+func Secrets(namespace Namespace, secrets map[string]composetypes.SecretConfig) ([]swarm.SecretSpec, error) {
|
|
| 88 |
+ result := []swarm.SecretSpec{}
|
|
| 89 |
+ for name, secret := range secrets {
|
|
| 90 |
+ if secret.External.External {
|
|
| 91 |
+ continue |
|
| 92 |
+ } |
|
| 93 |
+ |
|
| 94 |
+ data, err := ioutil.ReadFile(secret.File) |
|
| 95 |
+ if err != nil {
|
|
| 96 |
+ return nil, err |
|
| 97 |
+ } |
|
| 98 |
+ |
|
| 99 |
+ result = append(result, swarm.SecretSpec{
|
|
| 100 |
+ Annotations: swarm.Annotations{
|
|
| 101 |
+ Name: namespace.Scope(name), |
|
| 102 |
+ Labels: AddStackLabel(namespace, secret.Labels), |
|
| 103 |
+ }, |
|
| 104 |
+ Data: data, |
|
| 105 |
+ }) |
|
| 106 |
+ } |
|
| 107 |
+ return result, nil |
|
| 108 |
+} |
| ... | ... |
@@ -2,20 +2,26 @@ package convert |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 |
+ "os" |
|
| 5 | 6 |
"time" |
| 6 | 7 |
|
| 8 |
+ "github.com/docker/docker/api/types" |
|
| 7 | 9 |
"github.com/docker/docker/api/types/container" |
| 8 | 10 |
"github.com/docker/docker/api/types/swarm" |
| 11 |
+ servicecli "github.com/docker/docker/cli/command/service" |
|
| 9 | 12 |
composetypes "github.com/docker/docker/cli/compose/types" |
| 13 |
+ "github.com/docker/docker/client" |
|
| 10 | 14 |
"github.com/docker/docker/opts" |
| 11 | 15 |
runconfigopts "github.com/docker/docker/runconfig/opts" |
| 12 | 16 |
"github.com/docker/go-connections/nat" |
| 13 | 17 |
) |
| 14 | 18 |
|
| 15 | 19 |
// Services from compose-file types to engine API types |
| 20 |
+// TODO: fix secrets API so that SecretAPIClient is not required here |
|
| 16 | 21 |
func Services( |
| 17 | 22 |
namespace Namespace, |
| 18 | 23 |
config *composetypes.Config, |
| 24 |
+ client client.SecretAPIClient, |
|
| 19 | 25 |
) (map[string]swarm.ServiceSpec, error) {
|
| 20 | 26 |
result := make(map[string]swarm.ServiceSpec) |
| 21 | 27 |
|
| ... | ... |
@@ -24,7 +30,12 @@ func Services( |
| 24 | 24 |
networks := config.Networks |
| 25 | 25 |
|
| 26 | 26 |
for _, service := range services {
|
| 27 |
- serviceSpec, err := convertService(namespace, service, networks, volumes) |
|
| 27 |
+ |
|
| 28 |
+ secrets, err := convertServiceSecrets(client, namespace, service.Secrets) |
|
| 29 |
+ if err != nil {
|
|
| 30 |
+ return nil, err |
|
| 31 |
+ } |
|
| 32 |
+ serviceSpec, err := convertService(namespace, service, networks, volumes, secrets) |
|
| 28 | 33 |
if err != nil {
|
| 29 | 34 |
return nil, err |
| 30 | 35 |
} |
| ... | ... |
@@ -39,6 +50,7 @@ func convertService( |
| 39 | 39 |
service composetypes.ServiceConfig, |
| 40 | 40 |
networkConfigs map[string]composetypes.NetworkConfig, |
| 41 | 41 |
volumes map[string]composetypes.VolumeConfig, |
| 42 |
+ secrets []*swarm.SecretReference, |
|
| 42 | 43 |
) (swarm.ServiceSpec, error) {
|
| 43 | 44 |
name := namespace.Scope(service.Name) |
| 44 | 45 |
|
| ... | ... |
@@ -108,6 +120,7 @@ func convertService( |
| 108 | 108 |
StopGracePeriod: service.StopGracePeriod, |
| 109 | 109 |
TTY: service.Tty, |
| 110 | 110 |
OpenStdin: service.StdinOpen, |
| 111 |
+ Secrets: secrets, |
|
| 111 | 112 |
}, |
| 112 | 113 |
LogDriver: logDriver, |
| 113 | 114 |
Resources: resources, |
| ... | ... |
@@ -163,6 +176,30 @@ func convertServiceNetworks( |
| 163 | 163 |
return nets, nil |
| 164 | 164 |
} |
| 165 | 165 |
|
| 166 |
+// TODO: fix secrets API so that SecretAPIClient is not required here |
|
| 167 |
+func convertServiceSecrets( |
|
| 168 |
+ client client.SecretAPIClient, |
|
| 169 |
+ namespace Namespace, |
|
| 170 |
+ secrets []composetypes.ServiceSecretConfig, |
|
| 171 |
+) ([]*swarm.SecretReference, error) {
|
|
| 172 |
+ opts := []*types.SecretRequestOption{}
|
|
| 173 |
+ for _, secret := range secrets {
|
|
| 174 |
+ target := secret.Target |
|
| 175 |
+ if target == "" {
|
|
| 176 |
+ target = secret.Source |
|
| 177 |
+ } |
|
| 178 |
+ opts = append(opts, &types.SecretRequestOption{
|
|
| 179 |
+ Source: namespace.Scope(secret.Source), |
|
| 180 |
+ Target: target, |
|
| 181 |
+ UID: secret.UID, |
|
| 182 |
+ GID: secret.GID, |
|
| 183 |
+ Mode: os.FileMode(secret.Mode), |
|
| 184 |
+ }) |
|
| 185 |
+ } |
|
| 186 |
+ |
|
| 187 |
+ return servicecli.ParseSecrets(client, opts) |
|
| 188 |
+} |
|
| 189 |
+ |
|
| 166 | 190 |
func convertExtraHosts(extraHosts map[string]string) []string {
|
| 167 | 191 |
hosts := []string{}
|
| 168 | 192 |
for host, ip := range extraHosts {
|
| ... | ... |
@@ -109,6 +109,20 @@ func Load(configDetails types.ConfigDetails) (*types.Config, error) {
|
| 109 | 109 |
cfg.Volumes = volumesMapping |
| 110 | 110 |
} |
| 111 | 111 |
|
| 112 |
+ if secrets, ok := configDict["secrets"]; ok {
|
|
| 113 |
+ secretsConfig, err := interpolation.Interpolate(secrets.(types.Dict), "secret", os.LookupEnv) |
|
| 114 |
+ if err != nil {
|
|
| 115 |
+ return nil, err |
|
| 116 |
+ } |
|
| 117 |
+ |
|
| 118 |
+ secretsMapping, err := loadSecrets(secretsConfig, configDetails.WorkingDir) |
|
| 119 |
+ if err != nil {
|
|
| 120 |
+ return nil, err |
|
| 121 |
+ } |
|
| 122 |
+ |
|
| 123 |
+ cfg.Secrets = secretsMapping |
|
| 124 |
+ } |
|
| 125 |
+ |
|
| 112 | 126 |
return &cfg, nil |
| 113 | 127 |
} |
| 114 | 128 |
|
| ... | ... |
@@ -210,13 +224,15 @@ func transformHook( |
| 210 | 210 |
) (interface{}, error) {
|
| 211 | 211 |
switch target {
|
| 212 | 212 |
case reflect.TypeOf(types.External{}):
|
| 213 |
- return transformExternal(source, target, data) |
|
| 213 |
+ return transformExternal(data) |
|
| 214 | 214 |
case reflect.TypeOf(make(map[string]string, 0)): |
| 215 | 215 |
return transformMapStringString(source, target, data) |
| 216 | 216 |
case reflect.TypeOf(types.UlimitsConfig{}):
|
| 217 |
- return transformUlimits(source, target, data) |
|
| 217 |
+ return transformUlimits(data) |
|
| 218 | 218 |
case reflect.TypeOf(types.UnitBytes(0)): |
| 219 | 219 |
return loadSize(data) |
| 220 |
+ case reflect.TypeOf(types.ServiceSecretConfig{}):
|
|
| 221 |
+ return transformServiceSecret(data) |
|
| 220 | 222 |
} |
| 221 | 223 |
switch target.Kind() {
|
| 222 | 224 |
case reflect.Struct: |
| ... | ... |
@@ -311,7 +327,7 @@ func resolveEnvironment(serviceConfig *types.ServiceConfig, serviceDict types.Di |
| 311 | 311 |
var envVars []string |
| 312 | 312 |
|
| 313 | 313 |
for _, file := range envFiles {
|
| 314 |
- filePath := path.Join(workingDir, file) |
|
| 314 |
+ filePath := absPath(workingDir, file) |
|
| 315 | 315 |
fileVars, err := opts.ParseEnvFile(filePath) |
| 316 | 316 |
if err != nil {
|
| 317 | 317 |
return err |
| ... | ... |
@@ -341,7 +357,7 @@ func resolveVolumePaths(volumes []string, workingDir string) error {
|
| 341 | 341 |
} |
| 342 | 342 |
|
| 343 | 343 |
if strings.HasPrefix(parts[0], ".") {
|
| 344 |
- parts[0] = path.Join(workingDir, parts[0]) |
|
| 344 |
+ parts[0] = absPath(workingDir, parts[0]) |
|
| 345 | 345 |
} |
| 346 | 346 |
parts[0] = expandUser(parts[0]) |
| 347 | 347 |
|
| ... | ... |
@@ -359,11 +375,7 @@ func expandUser(path string) string {
|
| 359 | 359 |
return path |
| 360 | 360 |
} |
| 361 | 361 |
|
| 362 |
-func transformUlimits( |
|
| 363 |
- source reflect.Type, |
|
| 364 |
- target reflect.Type, |
|
| 365 |
- data interface{},
|
|
| 366 |
-) (interface{}, error) {
|
|
| 362 |
+func transformUlimits(data interface{}) (interface{}, error) {
|
|
| 367 | 363 |
switch value := data.(type) {
|
| 368 | 364 |
case int: |
| 369 | 365 |
return types.UlimitsConfig{Single: value}, nil
|
| ... | ... |
@@ -407,6 +419,32 @@ func loadVolumes(source types.Dict) (map[string]types.VolumeConfig, error) {
|
| 407 | 407 |
return volumes, nil |
| 408 | 408 |
} |
| 409 | 409 |
|
| 410 |
+// TODO: remove duplicate with networks/volumes |
|
| 411 |
+func loadSecrets(source types.Dict, workingDir string) (map[string]types.SecretConfig, error) {
|
|
| 412 |
+ secrets := make(map[string]types.SecretConfig) |
|
| 413 |
+ err := transform(source, &secrets) |
|
| 414 |
+ if err != nil {
|
|
| 415 |
+ return secrets, err |
|
| 416 |
+ } |
|
| 417 |
+ for name, secret := range secrets {
|
|
| 418 |
+ if secret.External.External && secret.External.Name == "" {
|
|
| 419 |
+ secret.External.Name = name |
|
| 420 |
+ secrets[name] = secret |
|
| 421 |
+ } |
|
| 422 |
+ if secret.File != "" {
|
|
| 423 |
+ secret.File = absPath(workingDir, secret.File) |
|
| 424 |
+ } |
|
| 425 |
+ } |
|
| 426 |
+ return secrets, nil |
|
| 427 |
+} |
|
| 428 |
+ |
|
| 429 |
+func absPath(workingDir string, filepath string) string {
|
|
| 430 |
+ if path.IsAbs(filepath) {
|
|
| 431 |
+ return filepath |
|
| 432 |
+ } |
|
| 433 |
+ return path.Join(workingDir, filepath) |
|
| 434 |
+} |
|
| 435 |
+ |
|
| 410 | 436 |
func transformStruct( |
| 411 | 437 |
source reflect.Type, |
| 412 | 438 |
target reflect.Type, |
| ... | ... |
@@ -490,11 +528,7 @@ func convertField( |
| 490 | 490 |
return data, nil |
| 491 | 491 |
} |
| 492 | 492 |
|
| 493 |
-func transformExternal( |
|
| 494 |
- source reflect.Type, |
|
| 495 |
- target reflect.Type, |
|
| 496 |
- data interface{},
|
|
| 497 |
-) (interface{}, error) {
|
|
| 493 |
+func transformExternal(data interface{}) (interface{}, error) {
|
|
| 498 | 494 |
switch value := data.(type) {
|
| 499 | 495 |
case bool: |
| 500 | 496 |
return map[string]interface{}{"external": value}, nil
|
| ... | ... |
@@ -507,6 +541,20 @@ func transformExternal( |
| 507 | 507 |
} |
| 508 | 508 |
} |
| 509 | 509 |
|
| 510 |
+func transformServiceSecret(data interface{}) (interface{}, error) {
|
|
| 511 |
+ switch value := data.(type) {
|
|
| 512 |
+ case string: |
|
| 513 |
+ return map[string]interface{}{"source": value}, nil
|
|
| 514 |
+ case types.Dict: |
|
| 515 |
+ return data, nil |
|
| 516 |
+ case map[string]interface{}:
|
|
| 517 |
+ return data, nil |
|
| 518 |
+ default: |
|
| 519 |
+ return data, fmt.Errorf("invalid type %T for external", value)
|
|
| 520 |
+ } |
|
| 521 |
+ |
|
| 522 |
+} |
|
| 523 |
+ |
|
| 510 | 524 |
func toYAMLName(name string) string {
|
| 511 | 525 |
nameParts := fieldNameRegexp.FindAllString(name, -1) |
| 512 | 526 |
for i, p := range nameParts {
|
| ... | ... |
@@ -163,6 +163,24 @@ func TestLoad(t *testing.T) {
|
| 163 | 163 |
assert.Equal(t, sampleConfig.Volumes, actual.Volumes) |
| 164 | 164 |
} |
| 165 | 165 |
|
| 166 |
+func TestLoadV31(t *testing.T) {
|
|
| 167 |
+ actual, err := loadYAML(` |
|
| 168 |
+version: "3.1" |
|
| 169 |
+services: |
|
| 170 |
+ foo: |
|
| 171 |
+ image: busybox |
|
| 172 |
+ secrets: [super] |
|
| 173 |
+secrets: |
|
| 174 |
+ super: |
|
| 175 |
+ external: true |
|
| 176 |
+`) |
|
| 177 |
+ if !assert.NoError(t, err) {
|
|
| 178 |
+ return |
|
| 179 |
+ } |
|
| 180 |
+ assert.Equal(t, len(actual.Services), 1) |
|
| 181 |
+ assert.Equal(t, len(actual.Secrets), 1) |
|
| 182 |
+} |
|
| 183 |
+ |
|
| 166 | 184 |
func TestParseAndLoad(t *testing.T) {
|
| 167 | 185 |
actual, err := loadYAML(sampleYAML) |
| 168 | 186 |
if !assert.NoError(t, err) {
|
| ... | ... |
@@ -89,7 +89,7 @@ func dataConfig_schema_v30Json() (*asset, error) {
|
| 89 | 89 |
return a, nil |
| 90 | 90 |
} |
| 91 | 91 |
|
| 92 |
-var _dataConfig_schema_v31Json = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xec\x1a\x4d\x93\xdb\xa8\xf2\xee\x5f\xa1\x52\x72\x8b\x67\x26\xaf\x5e\xea\x55\xbd\xdc\xde\xf1\x9d\x76\xcf\x3b\xe5\xa8\xb0\xd4\x96\xc9\x20\x20\x80\x9c\x71\x52\xfe\xef\x5b\xe8\xcb\x80\x41\x60\x5b\xd9\xa4\x6a\xf7\x34\x63\xd1\xdd\xf4\x77\x37\x0d\xdf\x57\x59\x96\xbf\x95\xe5\x1e\x1a\x94\x7f\xcc\xf2\xbd\x52\xfc\xe3\xd3\xd3\x67\xc9\xe8\x43\xff\xf5\x91\x89\xfa\xa9\x12\x68\xa7\x1e\xde\x7f\x78\xea\xbf\xbd\xc9\xd7\x1a\x0f\x57\x1a\xa5\x64\x74\x87\xeb\xa2\x5f\x29\x0e\xff\x7e\xfc\xd7\xa3\x46\xef\x41\xd4\x91\x83\x06\x62\xdb\xcf\x50\xaa\xfe\x9b\x80\x2f\x2d\x16\xa0\x91\x9f\xf3\x03\x08\x89\x19\xcd\x37\xeb\x95\x5e\xe3\x82\x71\x10\x0a\x83\xcc\x3f\x66\x9a\xb9\x2c\x9b\x40\xc6\x0f\x06\x59\xa9\x04\xa6\x75\xde\x7d\x3e\x75\x14\xb2\x2c\x97\x20\x0e\xb8\x34\x28\x4c\xac\xbe\x79\x3a\xd3\x7f\x9a\xc0\xd6\x2e\x55\x83\xd9\xee\x3b\x47\x4a\x81\xa0\xbf\x5f\xf2\xd6\x2d\x7f\x7a\x46\x0f\xdf\xfe\xf7\xf0\xc7\xfb\x87\xff\x3e\x16\x0f\x9b\x77\x6f\xad\x65\xad\x5f\x01\xbb\x7e\xfb\x0a\x76\x98\x62\x85\x19\x9d\xf6\xcf\x27\xc8\xd3\xf0\xdf\x69\xda\x18\x55\x55\x07\x8c\x88\xb5\xf7\x0e\x11\x09\xb6\xcc\x14\xd4\x57\x26\x5e\x62\x32\x4f\x60\x3f\x49\xe6\x61\x7f\x8f\xcc\xb6\x38\x07\x46\xda\x26\x6a\xc1\x11\xea\x27\x09\xd3\x6f\xbf\x8c\xfd\x24\x94\x02\x54\xdc\x65\x7b\xa8\x9f\xe6\xb1\x7a\xfb\xfb\x04\x5e\x8d\x42\xcf\xc2\xf6\x10\xc6\xde\x1d\x83\x56\x78\xfb\x54\xe5\x0b\xaf\xb0\xae\x26\x65\x05\xb4\x54\x01\x27\xec\xa8\xbf\x05\xf4\xd1\x03\x34\x40\x55\x3e\xa9\x20\xcb\xf2\x6d\x8b\x49\xe5\x6a\x94\x51\xf8\x4d\x93\x78\x36\x3e\x66\xd9\x77\x37\x93\x19\x74\xba\x75\xeb\x57\xd8\xe0\xd3\x7a\x40\x96\x69\xbd\x64\x54\xc1\xab\xea\x84\x9a\xdf\xba\x57\x01\x2b\x5f\x40\xec\x30\x81\x54\x0c\x24\x6a\x39\xa3\x32\x82\xa5\x2a\x98\x28\x2a\x5c\xaa\xfc\xe4\xa0\x5f\xd0\x8b\xfb\xd3\x84\x6a\xfc\xda\xac\x3c\x04\xf3\x12\xf1\x02\x55\x95\x25\x07\x12\x02\x1d\xf3\x75\x96\x63\x05\x8d\xf4\x8b\x98\xe5\x2d\xc5\x5f\x5a\xf8\xff\x00\xa2\x44\x0b\x2e\xdd\x4a\x30\xbe\x3c\xe1\x5a\xb0\x96\x17\x1c\x09\xed\x60\xf3\xea\xcf\x4b\xd6\x34\x88\x2e\xe5\x75\xd7\xc8\x91\xa0\x79\x46\x15\xc2\x14\x44\x41\x51\x13\x73\x24\x1d\x75\x40\x2b\x59\xf4\x05\x7f\xd6\x8d\x76\x45\x8f\x2f\x1d\x02\x53\xf5\x5f\xd4\x1e\x15\x9d\x73\xec\x9e\x8c\x76\x6d\xcd\x5b\xee\x20\x16\x12\x90\x28\xf7\x37\xe2\xb3\x06\x61\x9a\xa2\x3b\xa0\x4a\x1c\x39\xc3\xbd\xbf\xfc\x72\x8e\x00\xf4\x50\x4c\xb9\xe4\x6a\x35\x00\x3d\x60\xc1\x68\x33\x46\x43\x4a\x82\x99\x92\xbc\xc6\x7f\xe5\x4c\x82\xab\x18\x47\x40\x73\x69\x12\xd5\xd2\xc9\x88\xf1\x3c\x0a\xbe\xce\x72\xda\x36\x5b\x10\xba\x87\xb5\x20\x77\x4c\x34\x48\x33\x3b\xee\x6d\x2c\x5b\x9a\xf6\x78\x9e\xa9\x40\x53\x06\x5d\xd6\x11\x29\x08\xa6\x2f\xcb\xbb\x38\xbc\x2a\x81\x8a\x3d\x93\x2a\x3d\x87\x1b\xe8\x7b\x40\x44\xed\xcb\x3d\x94\x2f\x33\xe8\x26\x94\x85\xcd\xa4\x4a\x71\x72\xdc\xa0\x3a\x0e\xc4\xcb\x18\x08\x41\x5b\x20\x37\xc9\xb9\xa8\xf2\x0d\xb2\xac\xae\x35\x68\xc8\xe3\x2e\x3a\x97\x61\x39\x56\xf3\x2b\x81\x0f\x20\x52\x0b\x38\xe3\xe7\x86\xcb\x5d\x8c\x37\x20\x59\xbc\xfb\xb4\x40\x3f\x3d\xf6\xcd\xe7\x4c\x54\x75\xff\x11\x92\x6f\xdc\x76\x21\x73\xea\xbe\xef\x8b\x23\x61\x5a\x43\x61\x59\xa5\x41\xa5\xee\x1b\x04\xc8\x80\x5d\xcf\xa0\xc3\xe9\xa6\x68\x58\x15\x72\xd0\x0b\x60\x57\x37\xc1\x4c\x7d\x75\x21\xcc\x6e\xea\x1f\x93\x4c\x17\x3d\x40\x44\xa4\x09\xb1\x97\xca\xe6\x99\xdd\xb8\x8b\x75\x70\x88\x60\x24\x21\x1e\xec\x41\x45\x5a\xd4\x30\x3f\x7c\x48\xf4\x09\x1f\xee\x7f\x66\x71\x03\xa8\x41\x9a\xe9\x3d\x72\x84\xd4\x99\x95\x2e\xdc\x7c\x8c\x6c\x22\xd1\xf6\x83\x5b\x78\x8e\xab\x70\xae\xe8\x32\x84\x19\x60\x9c\x09\x75\x11\x5d\x7f\x4d\xb9\xef\xb7\xbe\xbb\xda\x73\x81\x0f\x98\x40\x0d\xf6\xa9\x65\xcb\x18\x01\x44\xad\xd4\x23\x00\x55\x05\xa3\xe4\x98\x00\x29\x15\x12\xd1\x03\x85\x84\xb2\x15\x58\x1d\x0b\xc6\xd5\xe2\x7d\x86\xdc\x37\x85\xc4\xdf\xc0\xb6\xe6\x39\xdf\x0f\x84\x36\x0e\x43\xce\x84\xe4\x46\x83\x86\x52\x52\x3c\x8c\x3d\x89\x30\x9a\xa8\xe2\x29\x2a\x97\xac\x15\x65\xea\x01\x5b\xef\x89\x44\x0d\xa9\x47\x78\xed\x6e\x76\xd8\xcc\x03\xd7\xd7\x00\x5f\x14\xba\xc1\x84\xb1\xaa\xec\xfe\x36\xf3\xca\xc9\x1b\xfa\xf2\x28\x4b\x75\x5b\xb7\x26\x55\x85\x69\xc1\x38\xd0\x68\x6c\x48\xc5\x78\x21\x71\x4d\x11\x89\xc6\x87\x06\xad\x05\x2a\xa1\xe0\x20\x30\xf3\x6a\x6d\x6d\x26\x85\xaa\x15\x48\xb3\x6a\x91\x51\x0d\xdf\xdd\x78\xac\x54\x2a\x1e\xec\x2d\xc1\x0d\x0e\x07\x8d\xc7\x6b\x13\x3a\x80\xbe\xfa\xfb\x8b\xfe\x4c\xc1\x3f\x73\x8a\xa9\x82\x5a\xbb\xc9\xa5\x53\xcd\xf4\x9c\xf3\x2d\x67\x42\xaf\xb9\x47\xc2\xb6\xd2\x0c\x1f\x59\x1f\x98\x3b\xe5\x47\xf0\x75\xa2\x5e\xbe\xac\xbb\x8e\x8e\xde\x7a\x60\x64\xe3\x85\xbf\xaa\x98\xbb\x6c\x6c\x82\xf5\xd4\x1f\x54\xad\x8c\x1e\x0b\x3a\x18\x2a\xe7\x5a\xda\x09\xd4\x18\xda\x2f\x5a\x2d\x74\x9b\xac\x83\xa0\xc2\x7e\x6e\x57\x8e\x64\x57\x8c\xdd\x9d\x13\xeb\x48\xc0\x37\x4f\x36\x41\xdd\x99\xf2\xf3\xe4\x9b\x63\x27\x72\x9e\xc4\x07\x86\xcb\xda\x95\xc4\xc1\xca\x33\x3e\x9d\x2a\xdc\x00\x6b\x55\x04\x4a\x80\x12\xd8\xd1\xfc\x98\x8a\x4d\x62\x20\x7f\xcd\xc1\x50\x85\x25\xda\x3a\x33\xe6\x29\x9d\xdd\x64\xde\xec\x3c\xc0\x1f\x07\x46\x73\xc6\x35\x20\x17\xb0\x6d\x4a\xb0\x08\xe0\x04\x97\x48\xc6\x12\xd2\x1d\x63\x8a\x96\x57\x48\x41\xd1\xdf\xcf\x5e\x55\x02\x66\x72\x3f\x47\x02\x11\x02\x04\xcb\x26\x25\x97\xe6\x15\x10\x74\xbc\xa9\x36\x76\xe8\x3b\x84\x49\x2b\xa0\x40\xa5\x1a\xae\x80\x23\x9e\x99\x37\x8c\x62\xc5\xbc\x99\x22\x6d\xcb\x06\xbd\x16\xe3\xb6\x1d\x48\xac\xc3\xb1\x9b\xfb\xd4\x09\x83\xe1\x09\x7d\x03\x78\x5d\x95\x9e\x31\xd1\xb9\xe6\x07\x3c\x66\xdc\xf1\x42\x74\x01\x52\x27\xa5\x69\x00\x14\xc5\x8f\x96\x98\xe1\xb4\x51\x70\x46\x70\x79\x5c\x4a\xc2\x92\xd1\x5e\xc9\x29\x0e\x71\xa7\x07\x6a\x77\xd0\x2d\x51\xc3\x55\x34\x58\x3b\x84\xaf\x98\x56\xec\xeb\x15\x1b\x2e\xe7\x4a\x9c\xa0\x12\x9c\x7c\x77\xaf\xa2\xa5\x12\x08\x53\x75\x75\x59\xbf\x57\xac\x3b\xaa\xfa\xe4\x9f\x91\xac\x3f\xc1\xc5\xef\xd3\x03\x99\xbe\xe4\x6d\x74\x2a\xd8\x40\xc3\x84\xd7\x01\x17\x78\xf0\x11\x13\x71\x04\x5b\xa0\xaa\x25\x8d\x91\x07\xa8\x82\xf1\xe5\x4f\x1d\xf1\x51\xf1\x26\x9e\x90\x30\x47\xcd\x52\xd1\x91\x3c\x58\xcf\xbd\x35\x38\x9b\x9f\x5f\x64\xe1\x19\x46\x8c\xeb\x38\xef\x03\x84\x6c\xb7\x34\x30\x4a\xb8\x3c\x6d\xf8\x6e\xfb\xd3\x8f\x2b\xa7\xf0\xe1\xe4\xbe\xa4\x37\xde\x89\x05\xac\xfa\x3c\x75\x92\xeb\x49\x57\x9b\x64\x13\x07\x2f\xa4\x96\xe3\xff\xca\x06\xef\x8e\x9c\x31\x3c\x58\x8a\xa4\x8c\x01\xea\x9f\x8c\xf1\xcb\xf8\xd7\x4c\x51\xbc\xf1\x74\x70\xf5\xcb\xb4\x98\xd3\x0c\x50\x37\x17\xd2\x84\x27\x46\x7f\x7b\x43\xd8\xa3\x40\xc3\x20\x97\x67\xf8\x39\x3d\x26\xdf\x80\x0d\x18\x1b\x9b\x0d\x17\xcc\xf3\x2a\xd7\xae\x65\x73\xa3\x9f\x11\x24\x70\x23\xe2\x6c\x3a\x28\x6f\x5e\xf2\x05\xf3\xc7\xe3\xbb\x99\x8a\x3d\x77\x53\xfd\x83\x4a\xdd\x02\x63\x35\xbf\x4d\x9d\x36\x7f\xd4\xee\xe5\x4b\xcb\x40\xf4\x1b\xf8\x17\xef\x2e\xb5\x9c\xf4\x78\x31\x63\xfa\x6e\x8f\x46\xfb\x37\x93\x1b\x4b\x3f\x0e\x48\xff\xee\xc3\x48\xd8\x1b\xf3\xe4\x13\x32\xa3\xf7\x35\xa6\x3b\x98\x1d\x5f\x45\x06\xee\x21\x56\xe6\xdf\xee\x05\xeb\xea\xb4\xfa\x33\x00\x00\xff\xff\xb7\x14\xdd\xc9\x3a\x2f\x00\x00")
|
|
| 92 |
+var _dataConfig_schema_v31Json = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xec\x1a\x4d\x93\xdb\xa8\xf2\xee\x5f\xa1\x52\x72\x8b\x67\x26\xaf\x5e\xea\x55\xbd\xdc\xf6\xb8\xa7\xdd\xf3\x4e\x39\x2a\x46\x6a\xcb\x64\x10\x10\x40\xce\x38\x29\xff\xf7\x2d\xf4\x65\xc0\x20\xb0\xad\xec\xcc\x61\x4f\x33\x16\xdd\x4d\x7f\x77\xd3\xf0\x73\x95\x65\xf9\x7b\x59\xee\xa0\x41\xf9\xe7\x2c\xdf\x29\xc5\x3f\x3f\x3c\x7c\x95\x8c\xde\xf5\x5f\xef\x99\xa8\x1f\x2a\x81\xb6\xea\xee\xe3\xa7\x87\xfe\xdb\xbb\x7c\xad\xf1\x70\xa5\x51\x4a\x46\xb7\xb8\x2e\xfa\x95\x62\xff\xdf\xfb\xff\xdc\x6b\xf4\x1e\x44\x1d\x38\x68\x20\xf6\xf4\x15\x4a\xd5\x7f\x13\xf0\xad\xc5\x02\x34\xf2\x63\xbe\x07\x21\x31\xa3\xf9\x66\xbd\xd2\x6b\x5c\x30\x0e\x42\x61\x90\xf9\xe7\x4c\x33\x97\x65\x13\xc8\xf8\xc1\x20\x2b\x95\xc0\xb4\xce\xbb\xcf\xc7\x8e\x42\x96\xe5\x12\xc4\x1e\x97\x06\x85\x89\xd5\x77\x0f\x27\xfa\x0f\x13\xd8\xda\xa5\x6a\x30\xdb\x7d\xe7\x48\x29\x10\xf4\xcf\x73\xde\xba\xe5\x2f\x8f\xe8\xee\xc7\x6f\x77\x7f\x7d\xbc\xfb\xff\x7d\x71\xb7\xf9\xf0\xde\x5a\xd6\xfa\x15\xb0\xed\xb7\xaf\x60\x8b\x29\x56\x98\xd1\x69\xff\x7c\x82\x3c\x0e\xff\x1d\xa7\x8d\x51\x55\x75\xc0\x88\x58\x7b\x6f\x11\x91\x60\xcb\x4c\x41\x7d\x67\xe2\x39\x26\xf3\x04\xf6\x4a\x32\x0f\xfb\x7b\x64\xb6\xc5\xd9\x33\xd2\x36\x51\x0b\x8e\x50\xaf\x24\x4c\xbf\xfd\x32\xf6\x93\x50\x0a\x50\x71\x97\xed\xa1\x5e\xcd\x63\xf5\xf6\xb7\x09\xbc\x1a\x85\x9e\x85\xed\x21\x8c\xbd\x3b\x06\xad\xf0\xf6\xa9\xca\x17\x5e\x61\x5d\x4d\xca\x0a\x68\xa9\x02\x4e\xd8\x41\x7f\x0b\xe8\xa3\x07\x68\x80\xaa\x7c\x52\x41\x96\xe5\x4f\x2d\x26\x95\xab\x51\x46\xe1\x0f\x4d\xe2\xd1\xf8\x98\x65\x3f\xdd\x4c\x66\xd0\xe9\xd6\xad\x5f\x61\x83\x4f\xeb\x01\x59\xa6\xf5\x92\x51\x05\x2f\xaa\x13\x6a\x7e\xeb\x5e\x05\xac\x7c\x06\xb1\xc5\x04\x52\x31\x90\xa8\xe5\x8c\xca\x08\x96\xaa\x60\xa2\xa8\x70\xa9\xf2\xa3\x83\x7e\x46\x2f\xee\x4f\x13\xaa\xf1\x6b\xb3\xf2\x10\xcc\x4b\xc4\x0b\x54\x55\x96\x1c\x48\x08\x74\xc8\xd7\x59\x8e\x15\x34\xd2\x2f\x62\x96\xb7\x14\x7f\x6b\xe1\xf7\x01\x44\x89\x16\x5c\xba\x95\x60\x7c\x79\xc2\xb5\x60\x2d\x2f\x38\x12\xda\xc1\xe6\xd5\x9f\x97\xac\x69\x10\x5d\xca\xeb\x2e\x91\x23\x41\xf3\x8c\x2a\x84\x29\x88\x82\xa2\x26\xe6\x48\x3a\xea\x80\x56\xb2\xe8\x0b\xfe\xac\x1b\x6d\x8b\x1e\x5f\x3a\x04\xa6\xea\xbf\xa8\x3d\x2a\x3a\xe7\xd8\x3d\x19\xed\xda\x9a\xb7\xdc\x41\x2c\x24\x20\x51\xee\xae\xc4\x67\x0d\xc2\x34\x45\x77\x40\x95\x38\x70\x86\x7b\x7f\x79\x73\x8e\x00\x74\x5f\x4c\xb9\xe4\x62\x35\x00\xdd\x63\xc1\x68\x33\x46\x43\x4a\x82\x99\x92\xbc\xc6\x7f\xe1\x4c\x82\xab\x18\x47\x40\x73\x69\x12\xd5\xd2\xc9\x88\xf1\x38\x0a\xbe\xce\x72\xda\x36\x4f\x20\x74\x0f\x6b\x41\x6e\x99\x68\x90\x66\x76\xdc\xdb\x58\xb6\x34\xed\xf1\x3c\x53\x81\xa6\x0c\xba\xac\x23\x52\x10\x4c\x9f\x97\x77\x71\x78\x51\x02\x15\x3b\x26\x55\x7a\x0e\x37\xd0\x77\x80\x88\xda\x95\x3b\x28\x9f\x67\xd0\x4d\x28\x0b\x9b\x49\x95\xe2\xe4\xb8\x41\x75\x1c\x88\x97\x31\x10\x82\x9e\x80\x5c\x25\xe7\xa2\xca\x37\xc8\xb2\xba\xd6\xa0\x21\x8f\x3b\xeb\x5c\x86\xe5\x58\xcd\xaf\x04\xde\x83\x48\x2d\xe0\x8c\x9f\x1a\x2e\x77\x31\xde\x80\x64\xf1\xee\xd3\x02\xfd\x72\xdf\x37\x9f\x33\x51\xd5\xfd\x47\x48\xbe\x71\xdb\x85\xcc\xa9\xfb\xbe\x2f\x8e\x84\x69\x0d\x85\x65\x95\x06\x95\xba\x6f\x10\x20\x03\x76\x3d\x81\x0e\xa7\x9b\xa2\x61\x55\xc8\x41\xcf\x80\x5d\xdd\x04\x33\xf5\xc5\x85\x30\xbb\xaa\x7f\x4c\x32\x5d\xf4\x00\x11\x91\x26\xc4\x5e\x2a\x9b\x27\x76\xe3\x2e\xd6\xc1\x21\x82\x91\x84\x78\xb0\x07\x15\x69\x51\xc3\x7c\xff\x29\xd1\x27\x7c\xb8\xff\x9b\xc5\x0d\xa0\x06\x69\xa6\xf7\xc8\x11\x52\x27\x56\xba\x70\xf3\x31\xb2\x89\x44\xdb\x2f\x6e\xe1\x39\xae\xc2\xb9\xa2\xcb\x10\x66\x80\x71\x26\xd4\x59\x74\xfd\x33\xe5\xbe\xdf\xfa\xe6\x6a\xcf\x05\xde\x63\x02\x35\xd8\xa7\x96\x27\xc6\x08\x20\x6a\xa5\x1e\x01\xa8\x2a\x18\x25\x87\x04\x48\xa9\x90\x88\x1e\x28\x24\x94\xad\xc0\xea\x50\x30\xae\x16\xef\x33\xe4\xae\x29\x24\xfe\x01\xb6\x35\x4f\xf9\x7e\x20\xb4\x71\x18\x72\x26\x24\x57\x1a\x34\x94\x92\xe2\x61\xec\x49\x84\xd1\x44\x15\x4f\x51\xb9\x64\xad\x28\x53\x0f\xd8\x7a\x4f\x24\x6a\x48\x3d\xc2\x6b\x77\xb3\xc3\x66\x1e\xb8\xbe\x04\xf8\xac\xd0\x0d\x26\x8c\x55\x65\xf7\xb7\x99\x57\x8e\xde\xd0\x97\x07\x59\xaa\xeb\xba\x35\xa9\x2a\x4c\x0b\xc6\x81\x46\x63\x43\x2a\xc6\x0b\x89\x6b\x8a\x48\x34\x3e\x34\x68\x2d\x50\x09\x05\x07\x81\x99\x57\x6b\x6b\x33\x29\x54\xad\x40\x9a\x55\x8b\x8c\x6a\xf8\xf6\xca\x63\xa5\x52\xf1\x60\x6f\x09\x6e\x70\x38\x68\x3c\x5e\x9b\xd0\x01\xf4\xd5\xdf\x5f\xf4\x67\x0a\xfe\x89\x53\x4c\x15\xd4\xda\x4d\xce\x9d\x6a\xa6\xe7\x9c\x6f\x39\x13\x7a\xcd\x1d\x12\xb6\x95\x66\xf8\xc8\xfa\xc0\xdc\x2a\x3f\x82\xaf\x13\xf5\xf2\x65\xdd\x75\x74\xf4\xd6\x03\x23\x1b\x2f\xfc\x45\xc5\xdc\x65\x63\x13\xac\xa7\xfe\xa0\x6a\x65\xf4\x58\xd0\xc1\x50\x39\xd7\xd2\x4e\xa0\xc6\xd0\x7e\xd1\x6a\xa1\xdb\x64\x1d\x04\x15\xf6\x73\xbb\x72\x24\xbb\x60\xec\xee\x9c\x58\x47\x02\xbe\x79\xb2\x09\xea\xce\x94\x1f\x27\xdf\x1c\x3b\x91\xd3\x24\x3e\x30\x5c\xd6\xae\x24\xf6\x56\x9e\xf1\xe9\x54\xe1\x06\x58\xab\x22\x50\x02\x94\xc0\x8e\xe6\xc7\x54\x6c\x12\x03\xf9\x36\x07\x43\x15\x96\xe8\xc9\x99\x31\x4f\xe9\xec\x2a\xf3\x66\xa7\x01\xfe\x38\x30\x9a\x33\xae\x01\xb9\x80\x6d\x53\x82\x45\x00\x27\xb8\x44\x32\x96\x90\x6e\x18\x53\xb4\xbc\x42\x0a\x8a\xfe\x7e\xf6\xa2\x12\x30\x93\xfb\x39\x12\x88\x10\x20\x58\x36\x29\xb9\x34\xaf\x80\xa0\xc3\x55\xb5\xb1\x43\xdf\x22\x4c\x5a\x01\x05\x2a\xd5\x70\x05\x1c\xf1\xcc\xbc\x61\x14\x2b\xe6\xcd\x14\x69\x5b\x36\xe8\xa5\x18\xb7\xed\x40\x62\x1d\x8e\xdd\xdc\xa7\x4e\x18\x0c\x4f\xe8\x1b\xc0\xcb\xaa\xf4\x8c\x89\x4e\x35\x3f\xe0\x31\xe3\x8e\x67\xa2\x0b\x90\x3a\x29\x4d\x03\xa0\x28\x7e\xb4\xc4\x0c\xa7\x8d\x82\x33\x82\xcb\xc3\x52\x12\x96\x8c\xf6\x4a\x4e\x71\x88\x1b\x3d\x50\xbb\x83\x6e\x89\x1a\xae\xa2\xc1\xda\x21\x7c\xc7\xb4\x62\xdf\x2f\xd8\x70\x39\x57\xe2\x04\x95\xe0\xe4\xbb\x5b\x15\x2d\x95\x40\x98\xaa\x8b\xcb\xfa\xad\x62\xdd\x50\xd5\x27\xff\x8c\x64\xfd\x09\x2e\x7e\x9f\x1e\xc8\xf4\x25\x6f\xa3\x53\xc1\x06\x1a\x26\xbc\x0e\xb8\xc0\x83\x8f\x98\x88\x23\xd8\x02\x55\x2d\x69\x8c\x3c\x40\x15\x8c\x2f\x7f\xea\x88\x8f\x8a\x37\xf1\x84\x84\x39\x6a\x96\x8a\x8e\xe4\xc1\x7a\xee\xad\xc1\xd9\xfc\xfc\x22\x0b\xcf\x30\x62\x5c\xc7\x79\x1f\x20\x64\xfb\x44\x03\xa3\x84\xf3\xd3\x86\xef\xb6\x3f\xfd\xb8\x72\x0c\x1f\x4e\x6e\x4b\x7a\xe3\x9d\x58\xc0\xaa\x8f\x53\x27\xb9\x9e\x74\xb5\x49\x36\x71\xf0\x42\x6a\x39\xfe\x2f\x6c\xf0\x6e\xc8\x19\xc3\x83\xa5\x48\xca\x18\xa0\xfe\xcd\x18\x6f\xc6\xbf\x66\x8a\xe2\x95\xa7\x83\x8b\x5f\xa6\xc5\x9c\x66\x80\xba\xba\x90\x26\x3c\x31\x7a\x53\x86\x78\x95\xf8\x75\x86\x81\x86\x49\xce\x4f\xf1\x73\x9a\x4c\xbe\x03\x1b\x30\x36\x36\x1b\x2e\x98\xe7\x5d\xae\x5d\xcd\xe6\x86\x3f\x23\x48\xe0\x4e\xc4\xd9\x74\x50\xe2\xbc\xe4\x0b\x66\x90\xfb\x0f\x33\x35\x7b\xee\xae\xfa\x17\x15\xbb\x05\x06\x6b\x7e\x9b\x3a\x8d\xfe\xa8\xdd\xf3\xb7\x96\x81\xf8\x37\xf0\xcf\x5e\x5e\x6a\x39\xe9\xe1\x6c\xca\xf4\xd3\x1e\x8e\xf6\xaf\x26\x37\x96\x7e\x1c\x90\xfe\xe5\x87\x91\xb2\x37\xe6\xd9\x27\x64\x46\xef\x7b\x4c\x77\x34\x3b\xbe\x8b\x0c\xdc\x44\xac\xcc\xbf\xdd\x1b\xd6\xd5\x71\xf5\x77\x00\x00\x00\xff\xff\xc8\x0f\x22\x69\x3c\x2f\x00\x00")
|
|
| 93 | 93 |
|
| 94 | 94 |
func dataConfig_schema_v31JsonBytes() ([]byte, error) {
|
| 95 | 95 |
return bindataRead( |
| ... | ... |
@@ -205,9 +205,9 @@ type bintree struct {
|
| 205 | 205 |
Children map[string]*bintree |
| 206 | 206 |
} |
| 207 | 207 |
var _bintree = &bintree{nil, map[string]*bintree{
|
| 208 |
- "data": {nil, map[string]*bintree{
|
|
| 209 |
- "config_schema_v3.0.json": {dataConfig_schema_v30Json, map[string]*bintree{}},
|
|
| 210 |
- "config_schema_v3.1.json": {dataConfig_schema_v31Json, map[string]*bintree{}},
|
|
| 208 |
+ "data": &bintree{nil, map[string]*bintree{
|
|
| 209 |
+ "config_schema_v3.0.json": &bintree{dataConfig_schema_v30Json, map[string]*bintree{}},
|
|
| 210 |
+ "config_schema_v3.1.json": &bintree{dataConfig_schema_v31Json, map[string]*bintree{}},
|
|
| 211 | 211 |
}}, |
| 212 | 212 |
}} |
| 213 | 213 |
|
| ... | ... |
@@ -71,6 +71,7 @@ type Config struct {
|
| 71 | 71 |
Services []ServiceConfig |
| 72 | 72 |
Networks map[string]NetworkConfig |
| 73 | 73 |
Volumes map[string]VolumeConfig |
| 74 |
+ Secrets map[string]SecretConfig |
|
| 74 | 75 |
} |
| 75 | 76 |
|
| 76 | 77 |
// ServiceConfig is the configuration of one service |
| ... | ... |
@@ -108,6 +109,7 @@ type ServiceConfig struct {
|
| 108 | 108 |
Privileged bool |
| 109 | 109 |
ReadOnly bool `mapstructure:"read_only"` |
| 110 | 110 |
Restart string |
| 111 |
+ Secrets []ServiceSecretConfig |
|
| 111 | 112 |
SecurityOpt []string `mapstructure:"security_opt"` |
| 112 | 113 |
StdinOpen bool `mapstructure:"stdin_open"` |
| 113 | 114 |
StopGracePeriod *time.Duration `mapstructure:"stop_grace_period"` |
| ... | ... |
@@ -191,6 +193,15 @@ type ServiceNetworkConfig struct {
|
| 191 | 191 |
Ipv6Address string `mapstructure:"ipv6_address"` |
| 192 | 192 |
} |
| 193 | 193 |
|
| 194 |
+// ServiceSecretConfig is the secret configuration for a service |
|
| 195 |
+type ServiceSecretConfig struct {
|
|
| 196 |
+ Source string |
|
| 197 |
+ Target string |
|
| 198 |
+ UID string |
|
| 199 |
+ GID string |
|
| 200 |
+ Mode uint32 |
|
| 201 |
+} |
|
| 202 |
+ |
|
| 194 | 203 |
// UlimitsConfig the ulimit configuration |
| 195 | 204 |
type UlimitsConfig struct {
|
| 196 | 205 |
Single int |
| ... | ... |
@@ -233,3 +244,10 @@ type External struct {
|
| 233 | 233 |
Name string |
| 234 | 234 |
External bool |
| 235 | 235 |
} |
| 236 |
+ |
|
| 237 |
+// SecretConfig for a secret |
|
| 238 |
+type SecretConfig struct {
|
|
| 239 |
+ File string |
|
| 240 |
+ External External |
|
| 241 |
+ Labels map[string]string `compose:"list_or_dict_equals"` |
|
| 242 |
+} |