diff --git a/api/types/swarm/container.go b/api/types/swarm/container.go index 4a84f2e53f328..fe036bda852f6 100644 --- a/api/types/swarm/container.go +++ b/api/types/swarm/container.go @@ -12,6 +12,7 @@ type ContainerSpec struct { Labels map[string]string `json:",omitempty"` Command []string `json:",omitempty"` Args []string `json:",omitempty"` + Hostname string `json:",omitempty"` Env []string `json:",omitempty"` Dir string `json:",omitempty"` User string `json:",omitempty"` diff --git a/cli/command/stack/deploy.go b/cli/command/stack/deploy.go index d855da6281883..7f2c7ab1ef0fe 100644 --- a/cli/command/stack/deploy.go +++ b/cli/command/stack/deploy.go @@ -124,7 +124,7 @@ func createNetworks( } for internalName, network := range networks { - if network.ExternalName != "" { + if network.External.Name != "" { continue } @@ -218,8 +218,8 @@ func convertVolumes( return nil, fmt.Errorf("Undefined volume: %s", source) } - if stackVolume.ExternalName != "" { - source = stackVolume.ExternalName + if stackVolume.External.Name != "" { + source = stackVolume.External.Name } else { volumeOptions = &mount.VolumeOptions{ Labels: stackVolume.Labels, @@ -351,14 +351,15 @@ func convertService( }, TaskTemplate: swarm.TaskSpec{ ContainerSpec: swarm.ContainerSpec{ - Image: service.Image, - Command: service.Entrypoint, - Args: service.Command, - Env: convertEnvironment(service.Environment), - Labels: getStackLabels(namespace, service.Deploy.Labels), - Dir: service.WorkingDir, - User: service.User, - Mounts: mounts, + Image: service.Image, + Command: service.Entrypoint, + Args: service.Command, + Hostname: service.Hostname, + Env: convertEnvironment(service.Environment), + Labels: getStackLabels(namespace, service.Deploy.Labels), + Dir: service.WorkingDir, + User: service.User, + Mounts: mounts, }, Placement: &swarm.Placement{ Constraints: service.Deploy.Placement.Constraints, diff --git a/daemon/cluster/convert/container.go b/daemon/cluster/convert/container.go index 7cac7960b6214..71b9587205b8c 100644 --- a/daemon/cluster/convert/container.go +++ b/daemon/cluster/convert/container.go @@ -12,14 +12,15 @@ import ( func containerSpecFromGRPC(c *swarmapi.ContainerSpec) types.ContainerSpec { containerSpec := types.ContainerSpec{ - Image: c.Image, - Labels: c.Labels, - Command: c.Command, - Args: c.Args, - Env: c.Env, - Dir: c.Dir, - User: c.User, - Groups: c.Groups, + Image: c.Image, + Labels: c.Labels, + Command: c.Command, + Args: c.Args, + Hostname: c.Hostname, + Env: c.Env, + Dir: c.Dir, + User: c.User, + Groups: c.Groups, } // Mounts @@ -61,14 +62,15 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) types.ContainerSpec { func containerToGRPC(c types.ContainerSpec) (*swarmapi.ContainerSpec, error) { containerSpec := &swarmapi.ContainerSpec{ - Image: c.Image, - Labels: c.Labels, - Command: c.Command, - Args: c.Args, - Env: c.Env, - Dir: c.Dir, - User: c.User, - Groups: c.Groups, + Image: c.Image, + Labels: c.Labels, + Command: c.Command, + Args: c.Args, + Hostname: c.Hostname, + Env: c.Env, + Dir: c.Dir, + User: c.User, + Groups: c.Groups, } if c.StopGracePeriod != nil { diff --git a/hack/vendor.sh b/hack/vendor.sh index 6d4cf0288ab7b..c18a11710e76d 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -147,7 +147,7 @@ clone git github.com/docker/containerd 52ef1ceb4b660c42cf4ea9013180a5663968d4c7 clone git github.com/tonistiigi/fifo 8c56881ce5e63e19e2dfc495c8af0fb90916467d # cluster -clone git github.com/docker/swarmkit 3b221eb0391d34ae0b9dac65df02b5b64de6dff2 +clone git github.com/docker/swarmkit 056b833c84e3927ae49f5d4ad4fb0d048fdd6f2d clone git github.com/golang/mock bd3c8e81be01eef76d4b503f5e687d2d1354d2d9 clone git github.com/gogo/protobuf v0.3 clone git github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a diff --git a/vendor/src/github.com/aanand/compose-file/Makefile b/vendor/src/github.com/aanand/compose-file/Makefile index 2c060126a2325..b600f6b6ff158 100644 --- a/vendor/src/github.com/aanand/compose-file/Makefile +++ b/vendor/src/github.com/aanand/compose-file/Makefile @@ -2,7 +2,7 @@ SCHEMA_GO := schema/bindata.go SCHEMA_JSON := schema/data/config_schema_v3.json test: - go test ./loader ./schema + go test ./{loader,schema,template,interpolation} schema: $(SCHEMA_GO) diff --git a/vendor/src/github.com/aanand/compose-file/glide.lock b/vendor/src/github.com/aanand/compose-file/glide.lock index 0637414bae8fe..7a9fed82b1b91 100644 --- a/vendor/src/github.com/aanand/compose-file/glide.lock +++ b/vendor/src/github.com/aanand/compose-file/glide.lock @@ -1,10 +1,12 @@ -hash: 9608bf151ad45c1a11b596e0903f3b599dd027a812110b28bb464a8be066a907 -updated: 2016-08-26T18:35:32.56479457Z +hash: a0e98c9874029e2889f0ff0337c77cb523158ec2e1771a0aed11d0bf6c3b99a5 +updated: 2016-10-25T19:46:35.452989008Z imports: - name: github.com/docker/go-units version: eb879ae3e2b84e2a142af415b679ddeda47ec71c - name: github.com/mattn/go-shellwords version: 525bedee691b5a8df547cb5cf9f86b7fb1883e24 +- name: github.com/mitchellh/mapstructure + version: f3009df150dadf309fdee4a54ed65c124afad715 - name: github.com/stretchr/testify version: c5d7a69bf8a2c9c374798160849c071093e41dd1 subpackages: diff --git a/vendor/src/github.com/aanand/compose-file/glide.yaml b/vendor/src/github.com/aanand/compose-file/glide.yaml index 334b39a3f1241..ab822709c56bd 100644 --- a/vendor/src/github.com/aanand/compose-file/glide.yaml +++ b/vendor/src/github.com/aanand/compose-file/glide.yaml @@ -1,8 +1,9 @@ package: . import: - - package: github.com/mattn/go-shellwords - - package: github.com/stretchr/testify - - package: github.com/xeipuuv/gojsonreference - - package: github.com/xeipuuv/gojsonschema - - package: gopkg.in/yaml.v2 - - package: github.com/docker/go-units +- package: github.com/mattn/go-shellwords +- package: github.com/stretchr/testify +- package: github.com/xeipuuv/gojsonreference +- package: github.com/xeipuuv/gojsonschema +- package: gopkg.in/yaml.v2 +- package: github.com/docker/go-units +- package: github.com/mitchellh/mapstructure diff --git a/vendor/src/github.com/aanand/compose-file/interpolation/interpolation.go b/vendor/src/github.com/aanand/compose-file/interpolation/interpolation.go new file mode 100644 index 0000000000000..4f1b61da7b738 --- /dev/null +++ b/vendor/src/github.com/aanand/compose-file/interpolation/interpolation.go @@ -0,0 +1,89 @@ +package interpolation + +import ( + "fmt" + + "github.com/aanand/compose-file/template" + "github.com/aanand/compose-file/types" +) + +func Interpolate(config types.Dict, section string, mapping template.Mapping) (types.Dict, error) { + out := types.Dict{} + + for name, item := range config { + if item == nil { + out[name] = nil + continue + } + interpolatedItem, err := interpolateSectionItem(name, item.(types.Dict), section, mapping) + if err != nil { + return nil, err + } + out[name] = interpolatedItem + } + + return out, nil +} + +func interpolateSectionItem( + name string, + item types.Dict, + section string, + mapping template.Mapping, +) (types.Dict, error) { + + out := types.Dict{} + + for key, value := range item { + interpolatedValue, err := recursiveInterpolate(value, mapping) + if err != nil { + return nil, fmt.Errorf( + "Invalid interpolation format for %#v option in %s %#v: %#v", + key, section, name, err.Template, + ) + } + out[key] = interpolatedValue + } + + return out, nil + +} + +func recursiveInterpolate( + value interface{}, + mapping template.Mapping, +) (interface{}, *template.InvalidTemplateError) { + + switch value := value.(type) { + + case string: + return template.Substitute(value, mapping) + + case types.Dict: + out := types.Dict{} + for key, elem := range value { + interpolatedElem, err := recursiveInterpolate(elem, mapping) + if err != nil { + return nil, err + } + out[key] = interpolatedElem + } + return out, nil + + case []interface{}: + out := make([]interface{}, len(value)) + for i, elem := range value { + interpolatedElem, err := recursiveInterpolate(elem, mapping) + if err != nil { + return nil, err + } + out[i] = interpolatedElem + } + return out, nil + + default: + return value, nil + + } + +} diff --git a/vendor/src/github.com/aanand/compose-file/interpolation/interpolation_test.go b/vendor/src/github.com/aanand/compose-file/interpolation/interpolation_test.go new file mode 100644 index 0000000000000..ebe3f68aefbb8 --- /dev/null +++ b/vendor/src/github.com/aanand/compose-file/interpolation/interpolation_test.go @@ -0,0 +1,59 @@ +package interpolation + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/aanand/compose-file/types" +) + +var defaults = map[string]string{ + "USER": "jenny", + "FOO": "bar", +} + +func defaultMapping(name string) (string, bool) { + val, ok := defaults[name] + return val, ok +} + +func TestInterpolate(t *testing.T) { + services := types.Dict{ + "servicea": types.Dict{ + "image": "example:${USER}", + "volumes": []interface{}{"$FOO:/target"}, + "logging": types.Dict{ + "driver": "${FOO}", + "options": types.Dict{ + "user": "$USER", + }, + }, + }, + } + expected := types.Dict{ + "servicea": types.Dict{ + "image": "example:jenny", + "volumes": []interface{}{"bar:/target"}, + "logging": types.Dict{ + "driver": "bar", + "options": types.Dict{ + "user": "jenny", + }, + }, + }, + } + result, err := Interpolate(services, "service", defaultMapping) + assert.NoError(t, err) + assert.Equal(t, expected, result) +} + +func TestInvalidInterpolation(t *testing.T) { + services := types.Dict{ + "servicea": types.Dict{ + "image": "${", + }, + } + _, err := Interpolate(services, "service", defaultMapping) + assert.EqualError(t, err, `Invalid interpolation format for "image" option in service "servicea": "${"`) +} diff --git a/vendor/src/github.com/aanand/compose-file/loader/loader.go b/vendor/src/github.com/aanand/compose-file/loader/loader.go index 4f438f6f8039b..f4a56f00f1637 100644 --- a/vendor/src/github.com/aanand/compose-file/loader/loader.go +++ b/vendor/src/github.com/aanand/compose-file/loader/loader.go @@ -8,12 +8,13 @@ import ( "regexp" "strings" + "github.com/aanand/compose-file/interpolation" + "github.com/aanand/compose-file/schema" + "github.com/aanand/compose-file/types" units "github.com/docker/go-units" shellwords "github.com/mattn/go-shellwords" + "github.com/mitchellh/mapstructure" yaml "gopkg.in/yaml.v2" - - "github.com/aanand/compose-file/schema" - "github.com/aanand/compose-file/types" ) var ( @@ -47,51 +48,109 @@ func Load(configDetails types.ConfigDetails) (*types.Config, error) { return nil, fmt.Errorf("Multiple files are not yet supported") } - cfg := types.Config{} + // TODO: support multiple files file := configDetails.ConfigFiles[0] if err := validateAgainstConfigSchema(file); err != nil { return nil, err } + cfg := types.Config{} version := file.Config["version"].(string) if version != "3" { return nil, fmt.Errorf("Unsupported version: %#v. The only supported version is 3", version) } if services, ok := file.Config["services"]; ok { - serviceMapping, err := loadServices(services.(types.Dict), configDetails.WorkingDir) + servicesConfig, err := interpolation.Interpolate(services.(types.Dict), "service", os.LookupEnv) if err != nil { return nil, err } - cfg.Services = serviceMapping + + servicesList, err := loadServices(servicesConfig, configDetails.WorkingDir) + if err != nil { + return nil, err + } + + cfg.Services = servicesList } if networks, ok := file.Config["networks"]; ok { - networkMapping, err := loadNetworks(networks.(types.Dict)) + networksConfig, err := interpolation.Interpolate(networks.(types.Dict), "network", os.LookupEnv) if err != nil { return nil, err } - cfg.Networks = networkMapping + + networksMapping, err := loadNetworks(networksConfig) + if err != nil { + return nil, err + } + + cfg.Networks = networksMapping } if volumes, ok := file.Config["volumes"]; ok { - volumeMapping, err := loadVolumes(volumes.(types.Dict)) + volumesConfig, err := interpolation.Interpolate(volumes.(types.Dict), "volume", os.LookupEnv) + if err != nil { + return nil, err + } + + volumesMapping, err := loadVolumes(volumesConfig) if err != nil { return nil, err } - cfg.Volumes = volumeMapping + + cfg.Volumes = volumesMapping } return &cfg, nil } +func transform(source map[string]interface{}, target interface{}) error { + data := mapstructure.Metadata{} + config := &mapstructure.DecoderConfig{ + DecodeHook: transformHook, + Result: target, + Metadata: &data, + } + decoder, err := mapstructure.NewDecoder(config) + if err != nil { + return err + } + err = decoder.Decode(source) + // TODO: use logging + if len(data.Unused) > 0 { + fmt.Printf("Unused keys: %s", data.Unused) + } + return err +} + +func transformHook( + source reflect.Type, + target reflect.Type, + data interface{}, +) (interface{}, error) { + switch target { + case reflect.TypeOf(types.External{}): + return transformExternal(source, target, data) + case reflect.TypeOf(make(map[string]string, 0)): + return transformMapStringString(source, target, data) + case reflect.TypeOf(types.UlimitsConfig{}): + return transformUlimits(source, target, data) + } + switch target.Kind() { + case reflect.Struct: + return transformStruct(source, target, data) + } + return data, nil +} + func validateAgainstConfigSchema(file types.ConfigFile) error { return schema.Validate(file.Config) } -// TODO: should this be renamed to validateStringKeys? Why do the keys need to -// be converted? +// keys needs to be converted to strings for jsonschema +// TODO: don't use types.Dict func convertToStringKeysRecursive(value interface{}, keyPrefix string) (interface{}, error) { if mapping, ok := value.(map[interface{}]interface{}); ok { dict := make(types.Dict) @@ -151,16 +210,11 @@ func loadServices(servicesDict types.Dict, workingDir string) ([]types.ServiceCo func loadService(name string, serviceDict types.Dict, workingDir string) (*types.ServiceConfig, error) { serviceConfig := &types.ServiceConfig{} - if err := loadStruct(serviceDict, serviceConfig); err != nil { + if err := transform(serviceDict, serviceConfig); err != nil { return nil, err } serviceConfig.Name = name - // Load ulimits manually - if ulimits, ok := serviceDict["ulimits"]; ok { - serviceConfig.Ulimits = loadUlimits(ulimits) - } - if err := resolveVolumePaths(serviceConfig.Volumes, workingDir); err != nil { return nil, err } @@ -168,7 +222,6 @@ func loadService(name string, serviceDict types.Dict, workingDir string) (*types return serviceConfig, nil } -// TODO: handle invalid mappings here? func resolveVolumePaths(volumes []string, workingDir string) error { for i, mapping := range volumes { parts := strings.SplitN(mapping, ":", 2) @@ -195,223 +248,171 @@ func expandUser(path string) string { return path } -// TODO: this should be part of the transform -func loadUlimits(value interface{}) map[string]*types.UlimitsConfig { - ulimitsMap := make(map[string]*types.UlimitsConfig) - - for name, item := range value.(types.Dict) { - config := &types.UlimitsConfig{} - if singleLimit, ok := item.(int); ok { - config.Single = singleLimit - } else { - limitDict := item.(types.Dict) - config.Soft = limitDict["soft"].(int) - config.Hard = limitDict["hard"].(int) - } - ulimitsMap[name] = config +func transformUlimits( + source reflect.Type, + target reflect.Type, + data interface{}, +) (interface{}, error) { + switch value := data.(type) { + case int: + return types.UlimitsConfig{Single: value}, nil + case types.Dict: + ulimit := types.UlimitsConfig{} + ulimit.Soft = value["soft"].(int) + ulimit.Hard = value["hard"].(int) + return ulimit, nil + default: + return data, fmt.Errorf("invalid type %T for ulimits", value) } - - return ulimitsMap } -func loadNetworks(networksDict types.Dict) (map[string]types.NetworkConfig, error) { +func loadNetworks(source types.Dict) (map[string]types.NetworkConfig, error) { networks := make(map[string]types.NetworkConfig) - - for name, networkDef := range networksDict { - if networkDef == nil { - networks[name] = types.NetworkConfig{} - } else { - networkConfig, err := loadNetwork(name, networkDef.(types.Dict)) - if err != nil { - return nil, err - } - networks[name] = *networkConfig + err := transform(source, &networks) + if err != nil { + return networks, err + } + for name, network := range networks { + if network.External.External && network.External.Name == "" { + network.External.Name = name + networks[name] = network } } - return networks, nil } -func loadNetwork(name string, networkDict types.Dict) (*types.NetworkConfig, error) { - network := &types.NetworkConfig{} - if err := loadStruct(networkDict, network); err != nil { - return nil, err - } - if external, ok := networkDict["external"]; ok { - network.ExternalName = loadExternalName(name, external) - } - return network, nil -} - -func loadVolumes(volumesDict types.Dict) (map[string]types.VolumeConfig, error) { +func loadVolumes(source types.Dict) (map[string]types.VolumeConfig, error) { volumes := make(map[string]types.VolumeConfig) - - for name, volumeDef := range volumesDict { - if volumeDef == nil { - volumes[name] = types.VolumeConfig{} - } else { - volumeConfig, err := loadVolume(name, volumeDef.(types.Dict)) - if err != nil { - return nil, err - } - volumes[name] = *volumeConfig + err := transform(source, &volumes) + if err != nil { + return volumes, err + } + for name, volume := range volumes { + if volume.External.External && volume.External.Name == "" { + volume.External.Name = name + volumes[name] = volume } } - return volumes, nil } -func loadVolume(name string, volumeDict types.Dict) (*types.VolumeConfig, error) { - volume := &types.VolumeConfig{} - if err := loadStruct(volumeDict, volume); err != nil { - return nil, err - } - if external, ok := volumeDict["external"]; ok { - volume.ExternalName = loadExternalName(name, external) - } - return volume, nil -} - -func loadExternalName(resourceName string, value interface{}) string { - if externalBool, ok := value.(bool); ok { - if externalBool { - return resourceName +func transformStruct( + source reflect.Type, + target reflect.Type, + data interface{}, +) (interface{}, error) { + structValue, ok := data.(map[string]interface{}) + if !ok { + // FIXME: this is necessary because of convertToStringKeysRecursive + structValue, ok = data.(types.Dict) + if !ok { + panic(fmt.Sprintf( + "transformStruct called with non-map type: %T, %s", data, data)) } - return "" } - return value.(types.Dict)["name"].(string) -} -func loadStruct(dict types.Dict, dest interface{}) error { - structValue := reflect.ValueOf(dest).Elem() - structType := structValue.Type() - - for i := 0; i < structType.NumField(); i++ { - field := structType.Field(i) - fieldValue := structValue.FieldByIndex([]int{i}) + var err error + for i := 0; i < target.NumField(); i++ { + field := target.Field(i) fieldTag := field.Tag.Get("compose") yamlName := toYAMLName(field.Name) - value, ok := dict[yamlName] + value, ok := structValue[yamlName] if !ok { continue } - if fieldTag == "list_or_dict_equals" { - fieldValue.Set(reflect.ValueOf(loadMappingOrList(value, "="))) - } else if fieldTag == "list_or_dict_colon" { - fieldValue.Set(reflect.ValueOf(loadMappingOrList(value, ":"))) - } else if fieldTag == "list_or_struct_map" { - if err := loadListOrStructMap(value, fieldValue); err != nil { - return err - } - } else if fieldTag == "string_or_list" { - fieldValue.Set(reflect.ValueOf(loadStringOrListOfStrings(value))) - } else if fieldTag == "list_of_strings_or_numbers" { - fieldValue.Set(reflect.ValueOf(loadListOfStringsOrNumbers(value))) - } else if fieldTag == "shell_command" { - command, err := loadShellCommand(value) - if err != nil { - return err - } - fieldValue.Set(reflect.ValueOf(command)) - } else if fieldTag == "size" { - size, err := loadSize(value) - if err != nil { - return err - } - fieldValue.SetInt(size) - } else if fieldTag == "-" { - // skip - } else if fieldTag != "" { - panic(fmt.Sprintf("Unrecognised field tag on %s: %s\n", field.Name, fieldTag)) - } else if field.Type.Kind() == reflect.String { - fieldValue.SetString(value.(string)) - } else if field.Type.Kind() == reflect.Bool { - fieldValue.SetBool(value.(bool)) - } else if field.Type.Kind() == reflect.Slice && field.Type.Elem().Kind() == reflect.String { - fieldValue.Set(reflect.ValueOf(loadListOfStrings(value))) - } else if field.Type.Kind() == reflect.Slice && field.Type.Elem().Kind() == reflect.Ptr && field.Type.Elem().Elem().Kind() == reflect.Struct { - if err := loadListOfStructs(value, fieldValue); err != nil { - return err - } - } else if field.Type.Kind() == reflect.Map && field.Type.Elem().Kind() == reflect.String { - fieldValue.Set(reflect.ValueOf(loadStringMapping(value))) - } else if field.Type.Kind() == reflect.Struct { - if err := loadStruct(value.(types.Dict), fieldValue.Addr().Interface()); err != nil { - return err - } - } else { - panic(fmt.Sprintf("Can't load %s (%s): don't know how to load %v", - field.Name, yamlName, field.Type)) + structValue[yamlName], err = convertField( + fieldTag, reflect.TypeOf(value), field.Type, value) + if err != nil { + return nil, fmt.Errorf("field %s: %s", yamlName, err.Error()) } } - - return nil + return structValue, nil } -func toYAMLName(name string) string { - nameParts := fieldNameRegexp.FindAllString(name, -1) - for i, p := range nameParts { - nameParts[i] = strings.ToLower(p) +func transformMapStringString( + source reflect.Type, + target reflect.Type, + data interface{}, +) (interface{}, error) { + switch value := data.(type) { + case map[string]interface{}: + return toMapStringString(value), nil + case types.Dict: + return toMapStringString(value), nil + case map[string]string: + return value, nil + default: + return data, fmt.Errorf("invalid type %T for map[string]string", value) } - return strings.Join(nameParts, "_") } -func loadStringMapping(value interface{}) map[string]string { - mapping := value.(types.Dict) - result := make(map[string]string) - for name, item := range mapping { - result[name] = toString(item) - } - return result +func convertField( + fieldTag string, + source reflect.Type, + target reflect.Type, + data interface{}, +) (interface{}, error) { + switch fieldTag { + case "": + return data, nil + case "list_or_dict_equals": + return loadMappingOrList(data, "="), nil + case "list_or_dict_colon": + return loadMappingOrList(data, ":"), nil + case "list_or_struct_map": + return loadListOrStructMap(data, target) + case "string_or_list": + return loadStringOrListOfStrings(data), nil + case "list_of_strings_or_numbers": + return loadListOfStringsOrNumbers(data), nil + case "shell_command": + return loadShellCommand(data) + case "size": + return loadSize(data) + case "-": + return nil, nil + } + return data, nil } -func loadListOfStrings(value interface{}) []string { - list := value.([]interface{}) - result := make([]string, len(list)) - for i, item := range list { - result[i] = item.(string) +func transformExternal( + source reflect.Type, + target reflect.Type, + data interface{}, +) (interface{}, error) { + switch value := data.(type) { + case bool: + return map[string]interface{}{"external": value}, nil + case types.Dict: + return map[string]interface{}{"external": true, "name": value["name"]}, nil + case map[string]interface{}: + return map[string]interface{}{"external": true, "name": value["name"]}, nil + default: + return data, fmt.Errorf("invalid type %T for external", value) } - return result } -func loadListOfStructs(value interface{}, dest reflect.Value) error { - result := dest - listOfDicts := value.([]interface{}) - for _, item := range listOfDicts { - itemStruct := reflect.New(dest.Type().Elem().Elem()) - if err := loadStruct(item.(types.Dict), itemStruct.Interface()); err != nil { - return err - } - result = reflect.Append(result, itemStruct) +func toYAMLName(name string) string { + nameParts := fieldNameRegexp.FindAllString(name, -1) + for i, p := range nameParts { + nameParts[i] = strings.ToLower(p) } - dest.Set(result) - return nil + return strings.Join(nameParts, "_") } -func loadListOrStructMap(value interface{}, dest reflect.Value) error { - mapValue := reflect.MakeMap(dest.Type()) +func loadListOrStructMap(value interface{}, target reflect.Type) (interface{}, error) { + mapValue := reflect.MakeMap(target) if list, ok := value.([]interface{}); ok { for _, name := range list { mapValue.SetMapIndex(reflect.ValueOf(name), reflect.ValueOf(nil)) } - } else { - for name, item := range value.(types.Dict) { - itemStruct := reflect.New(dest.Type().Elem().Elem()) - if item != nil { - if err := loadStruct(item.(types.Dict), itemStruct.Interface()); err != nil { - return err - } - } - mapValue.SetMapIndex(reflect.ValueOf(name), itemStruct) - } + return mapValue.Interface(), nil } - dest.Set(mapValue) - - return nil + return value, nil } func loadListOfStringsOrNumbers(value interface{}) []string { @@ -423,21 +424,19 @@ func loadListOfStringsOrNumbers(value interface{}) []string { return result } -func loadStringOrListOfStrings(value interface{}) []string { +func loadStringOrListOfStrings(value interface{}) interface{} { if _, ok := value.([]interface{}); ok { - return loadListOfStrings(value) + return value } return []string{value.(string)} } func loadMappingOrList(mappingOrList interface{}, sep string) map[string]string { - result := make(map[string]string) - if mapping, ok := mappingOrList.(types.Dict); ok { - for name, value := range mapping { - result[name] = toString(value) - } - } else if list, ok := mappingOrList.([]interface{}); ok { + return toMapStringString(mapping) + } + if list, ok := mappingOrList.([]interface{}); ok { + result := make(map[string]string) for _, value := range list { parts := strings.SplitN(value.(string), sep, 2) if len(parts) == 1 { @@ -446,25 +445,34 @@ func loadMappingOrList(mappingOrList interface{}, sep string) map[string]string result[parts[0]] = parts[1] } } - } else { - panic(fmt.Errorf("expected a map or a slice, got: %#v", mappingOrList)) + return result } - - return result + panic(fmt.Errorf("expected a map or a slice, got: %#v", mappingOrList)) } -func loadShellCommand(value interface{}) ([]string, error) { +func loadShellCommand(value interface{}) (interface{}, error) { if str, ok := value.(string); ok { return shellwords.Parse(str) } - return loadListOfStrings(value), nil + return value, nil } func loadSize(value interface{}) (int64, error) { - if size, ok := value.(int); ok { - return int64(size), nil + switch value := value.(type) { + case int: + return int64(value), nil + case string: + return units.RAMInBytes(value) + } + panic(fmt.Errorf("invalid type for size %T", value)) +} + +func toMapStringString(value map[string]interface{}) map[string]string { + output := make(map[string]string) + for key, value := range value { + output[key] = toString(value) } - return units.RAMInBytes(value.(string)) + return output } func toString(value interface{}) string { diff --git a/vendor/src/github.com/aanand/compose-file/loader/loader_test.go b/vendor/src/github.com/aanand/compose-file/loader/loader_test.go index e46827d4115c7..7a14f38d4f76e 100644 --- a/vendor/src/github.com/aanand/compose-file/loader/loader_test.go +++ b/vendor/src/github.com/aanand/compose-file/loader/loader_test.go @@ -135,13 +135,17 @@ var sampleConfig = types.Config{ func TestParseYAML(t *testing.T) { dict, err := ParseYAML([]byte(sampleYAML)) - assert.NoError(t, err) + if !assert.NoError(t, err) { + return + } assert.Equal(t, sampleDict, dict) } func TestLoad(t *testing.T) { actual, err := Load(buildConfigDetails(sampleDict)) - assert.NoError(t, err) + if !assert.NoError(t, err) { + return + } assert.Equal(t, serviceSort(sampleConfig.Services), serviceSort(actual.Services)) assert.Equal(t, sampleConfig.Networks, actual.Networks) assert.Equal(t, sampleConfig.Volumes, actual.Volumes) @@ -149,7 +153,9 @@ func TestLoad(t *testing.T) { func TestParseAndLoad(t *testing.T) { actual, err := loadYAML(sampleYAML) - assert.NoError(t, err) + if !assert.NoError(t, err) { + return + } assert.Equal(t, serviceSort(sampleConfig.Services), serviceSort(actual.Services)) assert.Equal(t, sampleConfig.Networks, actual.Networks) assert.Equal(t, sampleConfig.Volumes, actual.Volumes) @@ -379,12 +385,49 @@ services: assert.Contains(t, err.Error(), "services.dict-env.environment must be a mapping") } +func TestEnvironmentInterpolation(t *testing.T) { + config, err := loadYAML(` +version: "3" +services: + test: + image: busybox + labels: + - home1=$HOME + - home2=${HOME} + - nonexistent=$NONEXISTENT + - default=${NONEXISTENT-default} +networks: + test: + driver: $HOME +volumes: + test: + driver: $HOME +`) + + assert.NoError(t, err) + + home := os.Getenv("HOME") + + expectedLabels := map[string]string{ + "home1": home, + "home2": home, + "nonexistent": "", + "default": "default", + } + + assert.Equal(t, expectedLabels, config.Services[0].Labels) + assert.Equal(t, home, config.Networks["test"].Driver) + assert.Equal(t, home, config.Volumes["test"].Driver) +} + func TestFullExample(t *testing.T) { bytes, err := ioutil.ReadFile("full-example.yml") assert.NoError(t, err) config, err := loadYAML(string(bytes)) - assert.NoError(t, err) + if !assert.NoError(t, err) { + return + } workingDir, err := os.Getwd() assert.NoError(t, err) @@ -403,13 +446,15 @@ func TestFullExample(t *testing.T) { Devices: []string{"/dev/ttyUSB0:/dev/ttyUSB0"}, Dns: []string{"8.8.8.8", "9.9.9.9"}, DnsSearch: []string{"dc1.example.com", "dc2.example.com"}, + DomainName: "foo.com", Entrypoint: []string{"/code/entrypoint.sh", "-p", "3000"}, Environment: map[string]string{ "RACK_ENV": "development", "SHOW": "true", "SESSION_SECRET": "", }, - Expose: []string{"3000", "8000"}, + EnvFile: []string{"./common.env", "./apps/web.env", "/opt/secrets.env"}, + Expose: []string{"3000", "8000"}, ExternalLinks: []string{ "redis_1", "project_db_1:mysql", @@ -449,11 +494,10 @@ func TestFullExample(t *testing.T) { Ipv6Address: "", }, "other-network": { - Aliases: nil, Ipv4Address: "172.16.238.10", Ipv6Address: "2001:3984:3989::10", }, - "other-other-network": {}, + "other-other-network": nil, }, Pid: "host", Ports: []string{ @@ -520,11 +564,17 @@ func TestFullExample(t *testing.T) { }, "external-network": { - ExternalName: "external-network", + External: types.External{ + Name: "external-network", + External: true, + }, }, "other-external-network": { - ExternalName: "my-cool-network", + External: types.External{ + Name: "my-cool-network", + External: true, + }, }, } @@ -540,10 +590,16 @@ func TestFullExample(t *testing.T) { }, }, "external-volume": { - ExternalName: "external-volume", + External: types.External{ + Name: "external-volume", + External: true, + }, }, "other-external-volume": { - ExternalName: "my-cool-volume", + External: types.External{ + Name: "my-cool-volume", + External: true, + }, }, } diff --git a/vendor/src/github.com/aanand/compose-file/script/watch b/vendor/src/github.com/aanand/compose-file/script/watch index fa2a9b2f6cfa0..14b163bf132eb 100755 --- a/vendor/src/github.com/aanand/compose-file/script/watch +++ b/vendor/src/github.com/aanand/compose-file/script/watch @@ -8,4 +8,4 @@ exec filewatcher \ -x 'script' \ -x 'docs' \ -- \ - go test -v './${dir}' + bash -c 'go test -v ./${dir} || ( echo; echo; echo; echo; exit 1 )' diff --git a/vendor/src/github.com/aanand/compose-file/template/template.go b/vendor/src/github.com/aanand/compose-file/template/template.go new file mode 100644 index 0000000000000..5b25333881bc4 --- /dev/null +++ b/vendor/src/github.com/aanand/compose-file/template/template.go @@ -0,0 +1,108 @@ +package template + +import ( + "fmt" + "regexp" + "strings" +) + +var delimiter = "\\$" +var substitution = "[_a-z][_a-z0-9]*(?::?-[^}]+)?" + +var patternString = fmt.Sprintf( + "%s(?i:(?P%s)|(?P%s)|{(?P%s)}|(?P))", + delimiter, delimiter, substitution, substitution, +) + +var pattern = regexp.MustCompile(patternString) + +type InvalidTemplateError struct { + Template string +} + +func (e InvalidTemplateError) Error() string { + return fmt.Sprintf("Invalid template: %#v", e.Template) +} + +// A user-supplied function which maps from variable names to values. +// Returns the value as a string and a bool indicating whether +// the value is present, to distinguish between an empty string +// and the absence of a value. +type Mapping func(string) (string, bool) + +func Substitute(template string, mapping Mapping) (result string, err *InvalidTemplateError) { + defer func() { + if r := recover(); r != nil { + if e, ok := r.(*InvalidTemplateError); ok { + err = e + } else { + panic(r) + } + } + }() + + result = pattern.ReplaceAllStringFunc(template, func(substring string) string { + matches := pattern.FindStringSubmatch(substring) + groups := make(map[string]string) + for i, name := range pattern.SubexpNames() { + if i != 0 { + groups[name] = matches[i] + } + } + + substitution := groups["named"] + if substitution == "" { + substitution = groups["braced"] + } + if substitution != "" { + // Soft default (fall back if unset or empty) + if strings.Contains(substitution, ":-") { + name, defaultValue := partition(substitution, ":-") + value, ok := mapping(name) + if !ok || value == "" { + return defaultValue + } + return value + } + + // Hard default (fall back if-and-only-if empty) + if strings.Contains(substitution, "-") { + name, defaultValue := partition(substitution, "-") + value, ok := mapping(name) + if !ok { + return defaultValue + } + return value + } + + // No default (fall back to empty string) + value, ok := mapping(substitution) + if !ok { + return "" + } + return value + } + + if escaped := groups["escaped"]; escaped != "" { + return escaped + } + + panic(&InvalidTemplateError{Template: template}) + return "" + }) + + return +} + +// Split the string at the first occurrence of sep, and return the part before the separator, +// and the part after the separator. +// +// If the separator is not found, return the string itself, followed by an empty string. +func partition(s, sep string) (string, string) { + if strings.Contains(s, sep) { + parts := strings.SplitN(s, sep, 2) + return parts[0], parts[1] + } else { + return s, "" + } +} diff --git a/vendor/src/github.com/aanand/compose-file/template/template_test.go b/vendor/src/github.com/aanand/compose-file/template/template_test.go new file mode 100644 index 0000000000000..6b81bf0a39c82 --- /dev/null +++ b/vendor/src/github.com/aanand/compose-file/template/template_test.go @@ -0,0 +1,83 @@ +package template + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +var defaults = map[string]string{ + "FOO": "first", + "BAR": "", +} + +func defaultMapping(name string) (string, bool) { + val, ok := defaults[name] + return val, ok +} + +func TestEscaped(t *testing.T) { + result, err := Substitute("$${foo}", defaultMapping) + assert.NoError(t, err) + assert.Equal(t, "${foo}", result) +} + +func TestInvalid(t *testing.T) { + invalidTemplates := []string{ + "${", + "$}", + "${}", + "${ }", + "${ foo}", + "${foo }", + "${foo!}", + } + + for _, template := range invalidTemplates { + _, err := Substitute(template, defaultMapping) + assert.Error(t, err) + assert.IsType(t, &InvalidTemplateError{}, err) + } +} + +func TestNoValueNoDefault(t *testing.T) { + for _, template := range []string{"This ${missing} var", "This ${BAR} var"} { + result, err := Substitute(template, defaultMapping) + assert.NoError(t, err) + assert.Equal(t, "This var", result) + } +} + +func TestValueNoDefault(t *testing.T) { + for _, template := range []string{"This $FOO var", "This ${FOO} var"} { + result, err := Substitute(template, defaultMapping) + assert.NoError(t, err) + assert.Equal(t, "This first var", result) + } +} + +func TestNoValueWithDefault(t *testing.T) { + for _, template := range []string{"ok ${missing:-def}", "ok ${missing-def}"} { + result, err := Substitute(template, defaultMapping) + assert.NoError(t, err) + assert.Equal(t, "ok def", result) + } +} + +func TestEmptyValueWithSoftDefault(t *testing.T) { + result, err := Substitute("ok ${BAR:-def}", defaultMapping) + assert.NoError(t, err) + assert.Equal(t, "ok def", result) +} + +func TestEmptyValueWithHardDefault(t *testing.T) { + result, err := Substitute("ok ${BAR-def}", defaultMapping) + assert.NoError(t, err) + assert.Equal(t, "ok ", result) +} + +func TestNonAlphanumericDefault(t *testing.T) { + result, err := Substitute("ok ${BAR:-/non:-alphanumeric}", defaultMapping) + assert.NoError(t, err) + assert.Equal(t, "ok /non:-alphanumeric", result) +} diff --git a/vendor/src/github.com/aanand/compose-file/types/types.go b/vendor/src/github.com/aanand/compose-file/types/types.go index 22c0f349de62f..ecc9708d28c3d 100644 --- a/vendor/src/github.com/aanand/compose-file/types/types.go +++ b/vendor/src/github.com/aanand/compose-file/types/types.go @@ -22,50 +22,51 @@ type Config struct { type ServiceConfig struct { Name string - CapAdd []string - CapDrop []string - CgroupParent string + CapAdd []string `mapstructure:"cap_add"` + CapDrop []string `mapstructure:"cap_drop"` + CgroupParent string `mapstructure:"cgroup_parent"` Command []string `compose:"shell_command"` - ContainerName string - DependsOn []string + ContainerName string `mapstructure:"container_name"` + DependsOn []string `mapstructure:"depends_on"` Deploy DeployConfig Devices []string - Dns []string `compose:"string_or_list"` - DnsSearch []string `compose:"string_or_list"` - DomainName string + Dns []string `compose:"string_or_list"` + DnsSearch []string `mapstructure:"dns_search" compose:"string_or_list"` + DomainName string `mapstructure:"domainname"` Entrypoint []string `compose:"shell_command"` Environment map[string]string `compose:"list_or_dict_equals"` + EnvFile []string `mapstructure:"env_file"` Expose []string `compose:"list_of_strings_or_numbers"` - ExternalLinks []string - ExtraHosts map[string]string `compose:"list_or_dict_colon"` + ExternalLinks []string `mapstructure:"external_links"` + ExtraHosts map[string]string `mapstructure:"extra_hosts" compose:"list_or_dict_colon"` Hostname string Image string Ipc string Labels map[string]string `compose:"list_or_dict_equals"` Links []string Logging *LoggingConfig - MacAddress string - MemLimit int `compose:"size"` - MemswapLimit int `compose:"size"` - NetworkMode string + MacAddress string `mapstructure:"mac_address"` + MemLimit int64 `mapstructure:"mem_limit" compose:"size"` + MemswapLimit int64 `mapstructure:"memswap_limit" compose:"size"` + NetworkMode string `mapstructure:"network_mode"` Networks map[string]*ServiceNetworkConfig `compose:"list_or_struct_map"` Pid string Ports []string `compose:"list_of_strings_or_numbers"` Privileged bool - ReadOnly bool + ReadOnly bool `mapstructure:"read_only"` Restart string - SecurityOpt []string - ShmSize int `compose:"size"` - StdinOpen bool - StopGracePeriod *string - StopSignal string + SecurityOpt []string `mapstructure:"security_opt"` + ShmSize int64 `mapstructure:"shm_size" compose:"size"` + StdinOpen bool `mapstructure:"stdin_open"` + StopGracePeriod *string `mapstructure:"stop_grace_period"` + StopSignal string `mapstructure:"stop_signal"` Tmpfs []string `compose:"string_or_list"` Tty bool - Ulimits map[string]*UlimitsConfig `compose:"-"` + Ulimits map[string]*UlimitsConfig User string Volumes []string - VolumeDriver string - WorkingDir string + VolumeDriver string `mapstructure:"volume_driver"` + WorkingDir string `mapstructure:"working_dir"` } type LoggingConfig struct { @@ -86,8 +87,8 @@ type Placement struct { type ServiceNetworkConfig struct { Aliases []string - Ipv4Address string - Ipv6Address string + Ipv4Address string `mapstructure:"ipv4_address"` + Ipv6Address string `mapstructure:"ipv6_address"` } type UlimitsConfig struct { @@ -97,11 +98,11 @@ type UlimitsConfig struct { } type NetworkConfig struct { - Driver string - DriverOpts map[string]string - Ipam IPAMConfig - ExternalName string - Labels map[string]string `compose:"list_or_dict_equals"` + Driver string + DriverOpts map[string]string `mapstructure:"driver_opts"` + Ipam IPAMConfig + External External + Labels map[string]string `compose:"list_or_dict_equals"` } type IPAMConfig struct { @@ -114,8 +115,15 @@ type IPAMPool struct { } type VolumeConfig struct { - Driver string - DriverOpts map[string]string - ExternalName string - Labels map[string]string `compose:"list_or_dict_equals"` + Driver string + DriverOpts map[string]string `mapstructure:"driver_opts"` + External External + Labels map[string]string `compose:"list_or_dict_equals"` +} + +// External identifies a Volume or Network as a reference to a resource that is +// not managed, and should already exist. +type External struct { + Name string + External bool } diff --git a/vendor/src/github.com/docker/swarmkit/agent/agent.go b/vendor/src/github.com/docker/swarmkit/agent/agent.go index 22188132da06b..e7d29648045fb 100644 --- a/vendor/src/github.com/docker/swarmkit/agent/agent.go +++ b/vendor/src/github.com/docker/swarmkit/agent/agent.go @@ -48,9 +48,11 @@ func New(config *Config) (*Agent, error) { return nil, err } + worker := newWorker(config.DB, config.Executor) + a := &Agent{ config: config, - worker: newWorker(config.DB, config.Executor), + worker: worker, sessionq: make(chan sessionOperation), started: make(chan struct{}), stopped: make(chan struct{}), @@ -278,8 +280,8 @@ func (a *Agent) handleSessionMessage(ctx context.Context, message *api.SessionMe if message.Node != nil { if a.node == nil || !nodesEqual(a.node, message.Node) { - if a.config.NotifyRoleChange != nil { - a.config.NotifyRoleChange <- message.Node.Spec.Role + if a.config.NotifyNodeChange != nil { + a.config.NotifyNodeChange <- message.Node.Copy() } a.node = message.Node.Copy() if err := a.config.Executor.Configure(ctx, a.node); err != nil { diff --git a/vendor/src/github.com/docker/swarmkit/agent/config.go b/vendor/src/github.com/docker/swarmkit/agent/config.go index 0bad4b7fd53d9..d62e15c8d59e9 100644 --- a/vendor/src/github.com/docker/swarmkit/agent/config.go +++ b/vendor/src/github.com/docker/swarmkit/agent/config.go @@ -24,8 +24,8 @@ type Config struct { // DB used for task storage. Must be open for the lifetime of the agent. DB *bolt.DB - // NotifyRoleChange channel receives new roles from session messages. - NotifyRoleChange chan<- api.NodeRole + // NotifyNodeChange channel receives new node changes from session messages. + NotifyNodeChange chan<- *api.Node // Credentials is credentials for grpc connection to manager. Credentials credentials.TransportCredentials diff --git a/vendor/src/github.com/docker/swarmkit/agent/exec/controller.go b/vendor/src/github.com/docker/swarmkit/agent/exec/controller.go index e1ad502de8c16..9b1e4039db39b 100644 --- a/vendor/src/github.com/docker/swarmkit/agent/exec/controller.go +++ b/vendor/src/github.com/docker/swarmkit/agent/exec/controller.go @@ -54,6 +54,13 @@ type ContainerStatuser interface { ContainerStatus(ctx context.Context) (*api.ContainerStatus, error) } +// PortStatuser reports status of ports which are allocated by the executor +type PortStatuser interface { + // PortStatus returns the status on a list of PortConfigs + // which are managed at the host level by the controller. + PortStatus(ctx context.Context) (*api.PortStatus, error) +} + // Resolve attempts to get a controller from the executor and reports the // correct status depending on the tasks current state according to the result. // @@ -131,6 +138,7 @@ func Do(ctx context.Context, task *api.Task, ctlr Controller) (*api.TaskStatus, // this particular method. Eventually, we assemble this as part of a defer. var ( containerStatus *api.ContainerStatus + portStatus *api.PortStatus exitCode int ) @@ -230,6 +238,21 @@ func Do(ctx context.Context, task *api.Task, ctlr Controller) (*api.TaskStatus, status.RuntimeStatus = &api.TaskStatus_Container{ Container: containerStatus, } + + if portStatus == nil { + pctlr, ok := ctlr.(PortStatuser) + if !ok { + return + } + + var err error + portStatus, err = pctlr.PortStatus(ctx) + if err != nil && !contextDoneError(err) { + log.G(ctx).WithError(err).Error("container port status unavailable") + } + } + + status.PortStatus = portStatus }() if task.DesiredState == api.TaskStateShutdown { @@ -277,7 +300,7 @@ func Do(ctx context.Context, task *api.Task, ctlr Controller) (*api.TaskStatus, } switch status.State { - case api.TaskStateNew, api.TaskStateAllocated, api.TaskStateAssigned: + case api.TaskStateNew, api.TaskStatePending, api.TaskStateAssigned: return transition(api.TaskStateAccepted, "accepted") case api.TaskStateAccepted: return transition(api.TaskStatePreparing, "preparing") diff --git a/vendor/src/github.com/docker/swarmkit/agent/exec/controller_test.mock.go b/vendor/src/github.com/docker/swarmkit/agent/exec/controller_test.mock.go index 3b2a1a740fc92..8a20bc620b1c6 100644 --- a/vendor/src/github.com/docker/swarmkit/agent/exec/controller_test.mock.go +++ b/vendor/src/github.com/docker/swarmkit/agent/exec/controller_test.mock.go @@ -141,3 +141,35 @@ func (_m *MockContainerStatuser) ContainerStatus(ctx context.Context) (*api.Cont func (_mr *_MockContainerStatuserRecorder) ContainerStatus(arg0 interface{}) *gomock.Call { return _mr.mock.ctrl.RecordCall(_mr.mock, "ContainerStatus", arg0) } + +// Mock of PortStatuser interface +type MockPortStatuser struct { + ctrl *gomock.Controller + recorder *_MockPortStatuserRecorder +} + +// Recorder for MockPortStatuser (not exported) +type _MockPortStatuserRecorder struct { + mock *MockPortStatuser +} + +func NewMockPortStatuser(ctrl *gomock.Controller) *MockPortStatuser { + mock := &MockPortStatuser{ctrl: ctrl} + mock.recorder = &_MockPortStatuserRecorder{mock} + return mock +} + +func (_m *MockPortStatuser) EXPECT() *_MockPortStatuserRecorder { + return _m.recorder +} + +func (_m *MockPortStatuser) PortStatus(ctx context.Context) (*api.PortStatus, error) { + ret := _m.ctrl.Call(_m, "PortStatus", ctx) + ret0, _ := ret[0].(*api.PortStatus) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +func (_mr *_MockPortStatuserRecorder) PortStatus(arg0 interface{}) *gomock.Call { + return _mr.mock.ctrl.RecordCall(_mr.mock, "PortStatus", arg0) +} diff --git a/vendor/src/github.com/docker/swarmkit/agent/exec/executor.go b/vendor/src/github.com/docker/swarmkit/agent/exec/executor.go index 58c70018136e9..55754edbbbc37 100644 --- a/vendor/src/github.com/docker/swarmkit/agent/exec/executor.go +++ b/vendor/src/github.com/docker/swarmkit/agent/exec/executor.go @@ -21,3 +21,25 @@ type Executor interface { // manager to the executor. SetNetworkBootstrapKeys([]*api.EncryptionKey) error } + +// SecretsProvider is implemented by objects that can store secrets, typically +// an executor. +type SecretsProvider interface { + Secrets() SecretsManager +} + +// SecretGetter contains secret data necessary for the Controller. +type SecretGetter interface { + // Get returns the the secret with a specific secret ID, if available. + // When the secret is not available, the return will be nil. + Get(secretID string) *api.Secret +} + +// SecretsManager is the interface for secret storage and updates. +type SecretsManager interface { + SecretGetter + + Add(secrets ...api.Secret) // add one or more secrets + Remove(secrets []string) // remove the secrets by ID + Reset() // remove all secrets +} diff --git a/vendor/src/github.com/docker/swarmkit/agent/secrets.go b/vendor/src/github.com/docker/swarmkit/agent/secrets.go deleted file mode 100644 index a3faabfa18f1b..0000000000000 --- a/vendor/src/github.com/docker/swarmkit/agent/secrets.go +++ /dev/null @@ -1,53 +0,0 @@ -package agent - -import ( - "sync" - - "github.com/docker/swarmkit/api" -) - -// secrets is a map that keeps all the currenty available secrets to the agent -// mapped by secret ID -type secrets struct { - mu sync.RWMutex - m map[string]api.Secret -} - -func newSecrets() *secrets { - return &secrets{ - m: make(map[string]api.Secret), - } -} - -// Get returns a secret by ID. If the secret doesn't exist, returns nil. -func (s *secrets) Get(secretID string) api.Secret { - s.mu.RLock() - defer s.mu.RUnlock() - return s.m[secretID] -} - -// Add adds one or more secrets to the secret map -func (s *secrets) Add(secrets ...api.Secret) { - s.mu.Lock() - defer s.mu.Unlock() - for _, secret := range secrets { - s.m[secret.ID] = secret - } -} - -// Remove removes one or more secrets by ID from the secret map. Succeeds -// whether or not the given IDs are in the map. -func (s *secrets) Remove(secrets []string) { - s.mu.Lock() - defer s.mu.Unlock() - for _, secret := range secrets { - delete(s.m, secret) - } -} - -// Reset removes all the secrets -func (s *secrets) Reset() { - s.mu.Lock() - defer s.mu.Unlock() - s.m = make(map[string]api.Secret) -} diff --git a/vendor/src/github.com/docker/swarmkit/agent/worker.go b/vendor/src/github.com/docker/swarmkit/agent/worker.go index 2029f6c233c64..305a181691b75 100644 --- a/vendor/src/github.com/docker/swarmkit/agent/worker.go +++ b/vendor/src/github.com/docker/swarmkit/agent/worker.go @@ -42,7 +42,6 @@ type worker struct { db *bolt.DB executor exec.Executor listeners map[*statusReporterKey]struct{} - secrets *secrets taskManagers map[string]*taskManager mu sync.RWMutex @@ -54,7 +53,6 @@ func newWorker(db *bolt.DB, executor exec.Executor) *worker { executor: executor, listeners: make(map[*statusReporterKey]struct{}), taskManagers: make(map[string]*taskManager), - secrets: newSecrets(), } } @@ -255,6 +253,15 @@ func reconcileTaskState(ctx context.Context, w *worker, assignments []*api.Assig } func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.AssignmentChange, fullSnapshot bool) error { + var secrets exec.SecretsManager + provider, ok := w.executor.(exec.SecretsProvider) + if !ok { + log.G(ctx).Warn("secrets update ignored; executor does not support secrets") + return nil + } + + secrets = provider.Secrets() + var ( updatedSecrets []api.Secret removedSecrets []string @@ -278,11 +285,11 @@ func reconcileSecrets(ctx context.Context, w *worker, assignments []*api.Assignm // If this was a complete set of secrets, we're going to clear the secrets map and add all of them if fullSnapshot { - w.secrets.Reset() + secrets.Reset() } else { - w.secrets.Remove(removedSecrets) + secrets.Remove(removedSecrets) } - w.secrets.Add(updatedSecrets...) + secrets.Add(updatedSecrets...) return nil } diff --git a/vendor/src/github.com/docker/swarmkit/api/control.pb.go b/vendor/src/github.com/docker/swarmkit/api/control.pb.go index 6945199a7f2d3..0cff716d221cb 100644 --- a/vendor/src/github.com/docker/swarmkit/api/control.pb.go +++ b/vendor/src/github.com/docker/swarmkit/api/control.pb.go @@ -459,6 +459,28 @@ func (m *GetSecretResponse) Reset() { *m = GetSecretResponse{ func (*GetSecretResponse) ProtoMessage() {} func (*GetSecretResponse) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{40} } +type UpdateSecretRequest struct { + // SecretID is the secret ID to update. + SecretID string `protobuf:"bytes,1,opt,name=secret_id,json=secretId,proto3" json:"secret_id,omitempty"` + // SecretVersion is the version of the secret being updated. + SecretVersion *Version `protobuf:"bytes,2,opt,name=secret_version,json=secretVersion" json:"secret_version,omitempty"` + // Spec is the new spec to apply to the Secret + // Only some fields are allowed to be updated. + Spec *SecretSpec `protobuf:"bytes,3,opt,name=spec" json:"spec,omitempty"` +} + +func (m *UpdateSecretRequest) Reset() { *m = UpdateSecretRequest{} } +func (*UpdateSecretRequest) ProtoMessage() {} +func (*UpdateSecretRequest) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{41} } + +type UpdateSecretResponse struct { + Secret *Secret `protobuf:"bytes,1,opt,name=secret" json:"secret,omitempty"` +} + +func (m *UpdateSecretResponse) Reset() { *m = UpdateSecretResponse{} } +func (*UpdateSecretResponse) ProtoMessage() {} +func (*UpdateSecretResponse) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{42} } + // ListSecretRequest is the request to list all non-internal secrets in the secret store, // or all secrets filtered by (name or name prefix or id prefix) and labels. type ListSecretsRequest struct { @@ -467,7 +489,7 @@ type ListSecretsRequest struct { func (m *ListSecretsRequest) Reset() { *m = ListSecretsRequest{} } func (*ListSecretsRequest) ProtoMessage() {} -func (*ListSecretsRequest) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{41} } +func (*ListSecretsRequest) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{43} } type ListSecretsRequest_Filters struct { Names []string `protobuf:"bytes,1,rep,name=names" json:"names,omitempty"` @@ -479,7 +501,7 @@ type ListSecretsRequest_Filters struct { func (m *ListSecretsRequest_Filters) Reset() { *m = ListSecretsRequest_Filters{} } func (*ListSecretsRequest_Filters) ProtoMessage() {} func (*ListSecretsRequest_Filters) Descriptor() ([]byte, []int) { - return fileDescriptorControl, []int{41, 0} + return fileDescriptorControl, []int{43, 0} } // ListSecretResponse contains a list of all the secrets that match the name or @@ -492,7 +514,7 @@ type ListSecretsResponse struct { func (m *ListSecretsResponse) Reset() { *m = ListSecretsResponse{} } func (*ListSecretsResponse) ProtoMessage() {} -func (*ListSecretsResponse) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{42} } +func (*ListSecretsResponse) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{44} } // CreateSecretRequest specifies a new secret (it will not update an existing // secret) to create. @@ -502,7 +524,7 @@ type CreateSecretRequest struct { func (m *CreateSecretRequest) Reset() { *m = CreateSecretRequest{} } func (*CreateSecretRequest) ProtoMessage() {} -func (*CreateSecretRequest) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{43} } +func (*CreateSecretRequest) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{45} } // CreateSecretResponse contains the newly created `Secret`` corresponding to the // name in `CreateSecretRequest`. The `Secret.Spec.Data` field should be nil instead @@ -513,7 +535,7 @@ type CreateSecretResponse struct { func (m *CreateSecretResponse) Reset() { *m = CreateSecretResponse{} } func (*CreateSecretResponse) ProtoMessage() {} -func (*CreateSecretResponse) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{44} } +func (*CreateSecretResponse) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{46} } // RemoveSecretRequest contains the ID of the secret that should be removed. This // removes all versions of the secret. @@ -523,7 +545,7 @@ type RemoveSecretRequest struct { func (m *RemoveSecretRequest) Reset() { *m = RemoveSecretRequest{} } func (*RemoveSecretRequest) ProtoMessage() {} -func (*RemoveSecretRequest) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{45} } +func (*RemoveSecretRequest) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{47} } // RemoveSecretResponse is an empty object indicating the successful removal of // a secret. @@ -532,7 +554,7 @@ type RemoveSecretResponse struct { func (m *RemoveSecretResponse) Reset() { *m = RemoveSecretResponse{} } func (*RemoveSecretResponse) ProtoMessage() {} -func (*RemoveSecretResponse) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{46} } +func (*RemoveSecretResponse) Descriptor() ([]byte, []int) { return fileDescriptorControl, []int{48} } func init() { proto.RegisterType((*GetNodeRequest)(nil), "docker.swarmkit.v1.GetNodeRequest") @@ -581,6 +603,8 @@ func init() { proto.RegisterType((*UpdateClusterResponse)(nil), "docker.swarmkit.v1.UpdateClusterResponse") proto.RegisterType((*GetSecretRequest)(nil), "docker.swarmkit.v1.GetSecretRequest") proto.RegisterType((*GetSecretResponse)(nil), "docker.swarmkit.v1.GetSecretResponse") + proto.RegisterType((*UpdateSecretRequest)(nil), "docker.swarmkit.v1.UpdateSecretRequest") + proto.RegisterType((*UpdateSecretResponse)(nil), "docker.swarmkit.v1.UpdateSecretResponse") proto.RegisterType((*ListSecretsRequest)(nil), "docker.swarmkit.v1.ListSecretsRequest") proto.RegisterType((*ListSecretsRequest_Filters)(nil), "docker.swarmkit.v1.ListSecretsRequest.Filters") proto.RegisterType((*ListSecretsResponse)(nil), "docker.swarmkit.v1.ListSecretsResponse") @@ -762,6 +786,14 @@ func (p *authenticatedWrapperControlServer) GetSecret(ctx context.Context, r *Ge return p.local.GetSecret(ctx, r) } +func (p *authenticatedWrapperControlServer) UpdateSecret(ctx context.Context, r *UpdateSecretRequest) (*UpdateSecretResponse, error) { + + if err := p.authorize(ctx, []string{"swarm-manager"}); err != nil { + return nil, err + } + return p.local.UpdateSecret(ctx, r) +} + func (p *authenticatedWrapperControlServer) ListSecrets(ctx context.Context, r *ListSecretsRequest) (*ListSecretsResponse, error) { if err := p.authorize(ctx, []string{"swarm-manager"}); err != nil { @@ -1491,6 +1523,32 @@ func (m *GetSecretResponse) Copy() *GetSecretResponse { return o } +func (m *UpdateSecretRequest) Copy() *UpdateSecretRequest { + if m == nil { + return nil + } + + o := &UpdateSecretRequest{ + SecretID: m.SecretID, + SecretVersion: m.SecretVersion.Copy(), + Spec: m.Spec.Copy(), + } + + return o +} + +func (m *UpdateSecretResponse) Copy() *UpdateSecretResponse { + if m == nil { + return nil + } + + o := &UpdateSecretResponse{ + Secret: m.Secret.Copy(), + } + + return o +} + func (m *ListSecretsRequest) Copy() *ListSecretsRequest { if m == nil { return nil @@ -2203,6 +2261,34 @@ func (this *GetSecretResponse) GoString() string { s = append(s, "}") return strings.Join(s, "") } +func (this *UpdateSecretRequest) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 7) + s = append(s, "&api.UpdateSecretRequest{") + s = append(s, "SecretID: "+fmt.Sprintf("%#v", this.SecretID)+",\n") + if this.SecretVersion != nil { + s = append(s, "SecretVersion: "+fmt.Sprintf("%#v", this.SecretVersion)+",\n") + } + if this.Spec != nil { + s = append(s, "Spec: "+fmt.Sprintf("%#v", this.Spec)+",\n") + } + s = append(s, "}") + return strings.Join(s, "") +} +func (this *UpdateSecretResponse) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 5) + s = append(s, "&api.UpdateSecretResponse{") + if this.Secret != nil { + s = append(s, "Secret: "+fmt.Sprintf("%#v", this.Secret)+",\n") + } + s = append(s, "}") + return strings.Join(s, "") +} func (this *ListSecretsRequest) GoString() string { if this == nil { return "nil" @@ -2358,6 +2444,12 @@ type ControlClient interface { // - Returns `InvalidArgument` if the `GetSecretRequest.SecretID` is empty. // - Returns an error if getting fails. GetSecret(ctx context.Context, in *GetSecretRequest, opts ...grpc.CallOption) (*GetSecretResponse, error) + // UpdateSecret returns a `UpdateSecretResponse` with a `Secret` with the same + // id as `GetSecretRequest.SecretID` + // - Returns `NotFound` if the Secret with the given id is not found. + // - Returns `InvalidArgument` if the `GetSecretRequest.SecretID` is empty. + // - Returns an error if updating fails. + UpdateSecret(ctx context.Context, in *UpdateSecretRequest, opts ...grpc.CallOption) (*UpdateSecretResponse, error) // ListSecrets returns a `ListSecretResponse` with a list all non-internal `Secret`s being // managed, or all secrets matching any name in `ListSecretsRequest.Names`, any // name prefix in `ListSecretsRequest.NamePrefixes`, any id in @@ -2565,6 +2657,15 @@ func (c *controlClient) GetSecret(ctx context.Context, in *GetSecretRequest, opt return out, nil } +func (c *controlClient) UpdateSecret(ctx context.Context, in *UpdateSecretRequest, opts ...grpc.CallOption) (*UpdateSecretResponse, error) { + out := new(UpdateSecretResponse) + err := grpc.Invoke(ctx, "/docker.swarmkit.v1.Control/UpdateSecret", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *controlClient) ListSecrets(ctx context.Context, in *ListSecretsRequest, opts ...grpc.CallOption) (*ListSecretsResponse, error) { out := new(ListSecretsResponse) err := grpc.Invoke(ctx, "/docker.swarmkit.v1.Control/ListSecrets", in, out, c.cc, opts...) @@ -2620,6 +2721,12 @@ type ControlServer interface { // - Returns `InvalidArgument` if the `GetSecretRequest.SecretID` is empty. // - Returns an error if getting fails. GetSecret(context.Context, *GetSecretRequest) (*GetSecretResponse, error) + // UpdateSecret returns a `UpdateSecretResponse` with a `Secret` with the same + // id as `GetSecretRequest.SecretID` + // - Returns `NotFound` if the Secret with the given id is not found. + // - Returns `InvalidArgument` if the `GetSecretRequest.SecretID` is empty. + // - Returns an error if updating fails. + UpdateSecret(context.Context, *UpdateSecretRequest) (*UpdateSecretResponse, error) // ListSecrets returns a `ListSecretResponse` with a list all non-internal `Secret`s being // managed, or all secrets matching any name in `ListSecretsRequest.Names`, any // name prefix in `ListSecretsRequest.NamePrefixes`, any id in @@ -3003,6 +3110,24 @@ func _Control_GetSecret_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } +func _Control_UpdateSecret_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSecretRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).UpdateSecret(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/docker.swarmkit.v1.Control/UpdateSecret", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).UpdateSecret(ctx, req.(*UpdateSecretRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Control_ListSecrets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ListSecretsRequest) if err := dec(in); err != nil { @@ -3141,6 +3266,10 @@ var _Control_serviceDesc = grpc.ServiceDesc{ MethodName: "GetSecret", Handler: _Control_GetSecret_Handler, }, + { + MethodName: "UpdateSecret", + Handler: _Control_UpdateSecret_Handler, + }, { MethodName: "ListSecrets", Handler: _Control_ListSecrets_Handler, @@ -4775,6 +4904,78 @@ func (m *GetSecretResponse) MarshalTo(data []byte) (int, error) { return i, nil } +func (m *UpdateSecretRequest) Marshal() (data []byte, err error) { + size := m.Size() + data = make([]byte, size) + n, err := m.MarshalTo(data) + if err != nil { + return nil, err + } + return data[:n], nil +} + +func (m *UpdateSecretRequest) MarshalTo(data []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.SecretID) > 0 { + data[i] = 0xa + i++ + i = encodeVarintControl(data, i, uint64(len(m.SecretID))) + i += copy(data[i:], m.SecretID) + } + if m.SecretVersion != nil { + data[i] = 0x12 + i++ + i = encodeVarintControl(data, i, uint64(m.SecretVersion.Size())) + n26, err := m.SecretVersion.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n26 + } + if m.Spec != nil { + data[i] = 0x1a + i++ + i = encodeVarintControl(data, i, uint64(m.Spec.Size())) + n27, err := m.Spec.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n27 + } + return i, nil +} + +func (m *UpdateSecretResponse) Marshal() (data []byte, err error) { + size := m.Size() + data = make([]byte, size) + n, err := m.MarshalTo(data) + if err != nil { + return nil, err + } + return data[:n], nil +} + +func (m *UpdateSecretResponse) MarshalTo(data []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Secret != nil { + data[i] = 0xa + i++ + i = encodeVarintControl(data, i, uint64(m.Secret.Size())) + n28, err := m.Secret.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n28 + } + return i, nil +} + func (m *ListSecretsRequest) Marshal() (data []byte, err error) { size := m.Size() data = make([]byte, size) @@ -4794,11 +4995,11 @@ func (m *ListSecretsRequest) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintControl(data, i, uint64(m.Filters.Size())) - n26, err := m.Filters.MarshalTo(data[i:]) + n29, err := m.Filters.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n26 + i += n29 } return i, nil } @@ -4932,11 +5133,11 @@ func (m *CreateSecretRequest) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintControl(data, i, uint64(m.Spec.Size())) - n27, err := m.Spec.MarshalTo(data[i:]) + n30, err := m.Spec.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n27 + i += n30 } return i, nil } @@ -4960,11 +5161,11 @@ func (m *CreateSecretResponse) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintControl(data, i, uint64(m.Secret.Size())) - n28, err := m.Secret.MarshalTo(data[i:]) + n31, err := m.Secret.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n28 + i += n31 } return i, nil } @@ -5725,6 +5926,37 @@ func (p *raftProxyControlServer) GetSecret(ctx context.Context, r *GetSecretRequ return resp, err } +func (p *raftProxyControlServer) UpdateSecret(ctx context.Context, r *UpdateSecretRequest) (*UpdateSecretResponse, error) { + + conn, err := p.connSelector.LeaderConn(ctx) + if err != nil { + if err == raftselector.ErrIsLeader { + return p.local.UpdateSecret(ctx, r) + } + return nil, err + } + modCtx, err := p.runCtxMods(ctx) + if err != nil { + return nil, err + } + + resp, err := NewControlClient(conn).UpdateSecret(modCtx, r) + if err != nil { + if !strings.Contains(err.Error(), "is closing") && !strings.Contains(err.Error(), "the connection is unavailable") && !strings.Contains(err.Error(), "connection error") { + return resp, err + } + conn, err := p.pollNewLeaderConn(ctx) + if err != nil { + if err == raftselector.ErrIsLeader { + return p.local.UpdateSecret(ctx, r) + } + return nil, err + } + return NewControlClient(conn).UpdateSecret(modCtx, r) + } + return resp, err +} + func (p *raftProxyControlServer) ListSecrets(ctx context.Context, r *ListSecretsRequest) (*ListSecretsResponse, error) { conn, err := p.connSelector.LeaderConn(ctx) @@ -6448,6 +6680,34 @@ func (m *GetSecretResponse) Size() (n int) { return n } +func (m *UpdateSecretRequest) Size() (n int) { + var l int + _ = l + l = len(m.SecretID) + if l > 0 { + n += 1 + l + sovControl(uint64(l)) + } + if m.SecretVersion != nil { + l = m.SecretVersion.Size() + n += 1 + l + sovControl(uint64(l)) + } + if m.Spec != nil { + l = m.Spec.Size() + n += 1 + l + sovControl(uint64(l)) + } + return n +} + +func (m *UpdateSecretResponse) Size() (n int) { + var l int + _ = l + if m.Secret != nil { + l = m.Secret.Size() + n += 1 + l + sovControl(uint64(l)) + } + return n +} + func (m *ListSecretsRequest) Size() (n int) { var l int _ = l @@ -7088,6 +7348,28 @@ func (this *GetSecretResponse) String() string { }, "") return s } +func (this *UpdateSecretRequest) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&UpdateSecretRequest{`, + `SecretID:` + fmt.Sprintf("%v", this.SecretID) + `,`, + `SecretVersion:` + strings.Replace(fmt.Sprintf("%v", this.SecretVersion), "Version", "Version", 1) + `,`, + `Spec:` + strings.Replace(fmt.Sprintf("%v", this.Spec), "SecretSpec", "SecretSpec", 1) + `,`, + `}`, + }, "") + return s +} +func (this *UpdateSecretResponse) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&UpdateSecretResponse{`, + `Secret:` + strings.Replace(fmt.Sprintf("%v", this.Secret), "Secret", "Secret", 1) + `,`, + `}`, + }, "") + return s +} func (this *ListSecretsRequest) String() string { if this == nil { return "nil" @@ -12083,6 +12365,234 @@ func (m *GetSecretResponse) Unmarshal(data []byte) error { } return nil } +func (m *UpdateSecretRequest) Unmarshal(data []byte) error { + l := len(data) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowControl + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UpdateSecretRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpdateSecretRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SecretID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowControl + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthControl + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SecretID = string(data[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SecretVersion", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowControl + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthControl + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.SecretVersion == nil { + m.SecretVersion = &Version{} + } + if err := m.SecretVersion.Unmarshal(data[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Spec", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowControl + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthControl + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Spec == nil { + m.Spec = &SecretSpec{} + } + if err := m.Spec.Unmarshal(data[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipControl(data[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthControl + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UpdateSecretResponse) Unmarshal(data []byte) error { + l := len(data) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowControl + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UpdateSecretResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpdateSecretResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Secret", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowControl + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthControl + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Secret == nil { + m.Secret = &Secret{} + } + if err := m.Secret.Unmarshal(data[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipControl(data[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthControl + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ListSecretsRequest) Unmarshal(data []byte) error { l := len(data) iNdEx := 0 @@ -12903,114 +13413,117 @@ var ( func init() { proto.RegisterFile("control.proto", fileDescriptorControl) } var fileDescriptorControl = []byte{ - // 1731 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x5a, 0x5f, 0x6f, 0x1b, 0xc5, - 0x16, 0xaf, 0xed, 0x24, 0x4e, 0x8e, 0x93, 0xb4, 0x99, 0x38, 0xf7, 0x5a, 0xdb, 0x5e, 0xa7, 0xda, - 0xde, 0xa6, 0x8e, 0xd4, 0xeb, 0xf4, 0xba, 0x54, 0x94, 0x22, 0xfe, 0x25, 0xa6, 0xc1, 0xfd, 0x13, - 0xaa, 0x4d, 0x0b, 0xbc, 0x45, 0x8e, 0x3d, 0x0d, 0x8b, 0x1d, 0xaf, 0xd9, 0xdd, 0xa4, 0xad, 0x78, - 0x01, 0x09, 0x24, 0x3e, 0x02, 0xaf, 0xbc, 0xf2, 0x80, 0xc4, 0x27, 0xe0, 0xb5, 0xe2, 0x89, 0x47, - 0x9e, 0x2c, 0x6a, 0x09, 0x89, 0x27, 0xc4, 0x27, 0x40, 0x68, 0x66, 0xce, 0xec, 0xae, 0xd7, 0xb3, - 0xbb, 0x76, 0x12, 0x94, 0x3e, 0x65, 0x77, 0xf6, 0x77, 0xe6, 0x9c, 0x99, 0xf3, 0x9b, 0x9f, 0xcf, - 0x1c, 0x05, 0xe6, 0x1a, 0x56, 0xc7, 0xb5, 0xad, 0x76, 0xb9, 0x6b, 0x5b, 0xae, 0x45, 0x48, 0xd3, - 0x6a, 0xb4, 0xa8, 0x5d, 0x76, 0x9e, 0xd4, 0xed, 0xfd, 0x96, 0xe9, 0x96, 0x0f, 0xff, 0xaf, 0xe5, - 0x9c, 0x2e, 0x6d, 0x38, 0x02, 0xa0, 0xcd, 0x59, 0xbb, 0x9f, 0xd0, 0x86, 0x2b, 0x5f, 0x73, 0xee, - 0xb3, 0x2e, 0x95, 0x2f, 0xf9, 0x3d, 0x6b, 0xcf, 0xe2, 0x8f, 0x6b, 0xec, 0x09, 0x47, 0x17, 0xbb, - 0xed, 0x83, 0x3d, 0xb3, 0xb3, 0x26, 0xfe, 0x88, 0x41, 0xfd, 0x06, 0xcc, 0x6f, 0x52, 0x77, 0xcb, - 0x6a, 0x52, 0x83, 0x7e, 0x7a, 0x40, 0x1d, 0x97, 0x5c, 0x82, 0x6c, 0xc7, 0x6a, 0xd2, 0x1d, 0xb3, - 0x59, 0x48, 0x5d, 0x4c, 0x95, 0x66, 0xd6, 0xa1, 0xdf, 0x5b, 0x9e, 0x62, 0x88, 0x5a, 0xd5, 0x98, - 0x62, 0x9f, 0x6a, 0x4d, 0xfd, 0x2d, 0x38, 0xeb, 0x99, 0x39, 0x5d, 0xab, 0xe3, 0x50, 0x72, 0x15, - 0x26, 0xd8, 0x47, 0x6e, 0x94, 0xab, 0x14, 0xca, 0xc3, 0x0b, 0x28, 0x73, 0x3c, 0x47, 0xe9, 0xbd, - 0x0c, 0x9c, 0xbb, 0x67, 0x3a, 0x7c, 0x0a, 0x47, 0xba, 0xbe, 0x0d, 0xd9, 0xc7, 0x66, 0xdb, 0xa5, - 0xb6, 0x83, 0xb3, 0x5c, 0x55, 0xcd, 0x12, 0x36, 0x2b, 0xdf, 0x16, 0x36, 0x86, 0x34, 0xd6, 0xbe, - 0xc8, 0x40, 0x16, 0x07, 0x49, 0x1e, 0x26, 0x3b, 0xf5, 0x7d, 0xca, 0x66, 0xcc, 0x94, 0x66, 0x0c, - 0xf1, 0x42, 0xd6, 0x20, 0x67, 0x36, 0x77, 0xba, 0x36, 0x7d, 0x6c, 0x3e, 0xa5, 0x4e, 0x21, 0xcd, - 0xbe, 0xad, 0xcf, 0xf7, 0x7b, 0xcb, 0x50, 0xab, 0x3e, 0xc0, 0x51, 0x03, 0xcc, 0xa6, 0x7c, 0x26, - 0x0f, 0x60, 0xaa, 0x5d, 0xdf, 0xa5, 0x6d, 0xa7, 0x90, 0xb9, 0x98, 0x29, 0xe5, 0x2a, 0x37, 0xc7, - 0x89, 0xac, 0x7c, 0x8f, 0x9b, 0xbe, 0xdb, 0x71, 0xed, 0x67, 0x06, 0xce, 0x43, 0x6a, 0x90, 0xdb, - 0xa7, 0xfb, 0xbb, 0xd4, 0x76, 0x3e, 0x36, 0xbb, 0x4e, 0x61, 0xe2, 0x62, 0xa6, 0x34, 0x5f, 0xb9, - 0x12, 0xb5, 0x6d, 0xdb, 0x5d, 0xda, 0x28, 0xdf, 0xf7, 0xf0, 0x46, 0xd0, 0x96, 0x54, 0x60, 0xd2, - 0xb6, 0xda, 0xd4, 0x29, 0x4c, 0xf2, 0x49, 0x2e, 0x44, 0xee, 0xbd, 0xd5, 0xa6, 0x86, 0x80, 0x92, - 0x4b, 0x30, 0xc7, 0xb6, 0xc2, 0xdf, 0x83, 0x29, 0xbe, 0x3f, 0xb3, 0x6c, 0x50, 0xae, 0x5a, 0x7b, - 0x0d, 0x72, 0x81, 0xd0, 0xc9, 0x39, 0xc8, 0xb4, 0xe8, 0x33, 0x41, 0x0b, 0x83, 0x3d, 0xb2, 0xdd, - 0x3d, 0xac, 0xb7, 0x0f, 0x68, 0x21, 0xcd, 0xc7, 0xc4, 0xcb, 0xad, 0xf4, 0xcd, 0x94, 0xbe, 0x01, - 0x0b, 0x81, 0xed, 0x40, 0x8e, 0x94, 0x61, 0x92, 0x65, 0x5f, 0x24, 0x23, 0x8e, 0x24, 0x02, 0xa6, - 0x7f, 0x97, 0x82, 0x85, 0x47, 0xdd, 0x66, 0xdd, 0xa5, 0xe3, 0x32, 0x94, 0xbc, 0x09, 0xb3, 0x1c, - 0x74, 0x48, 0x6d, 0xc7, 0xb4, 0x3a, 0x3c, 0xc0, 0x5c, 0xe5, 0xbc, 0xca, 0xe3, 0x07, 0x02, 0x62, - 0xe4, 0x98, 0x01, 0xbe, 0x90, 0x6b, 0x30, 0xc1, 0x8e, 0x5b, 0x21, 0xc3, 0xed, 0x2e, 0xc4, 0xe5, - 0xc5, 0xe0, 0x48, 0x7d, 0x1d, 0x48, 0x30, 0xd6, 0x23, 0x1d, 0x8b, 0x2d, 0x58, 0x30, 0xe8, 0xbe, - 0x75, 0x38, 0xfe, 0x7a, 0xf3, 0x30, 0xf9, 0xd8, 0xb2, 0x1b, 0x22, 0x13, 0xd3, 0x86, 0x78, 0xd1, - 0xf3, 0x40, 0x82, 0xf3, 0x89, 0x98, 0xf0, 0xd0, 0x3f, 0xac, 0x3b, 0xad, 0x80, 0x0b, 0xb7, 0xee, - 0xb4, 0x42, 0x2e, 0x18, 0x82, 0xb9, 0x60, 0x9f, 0xbc, 0x43, 0x2f, 0xcc, 0xfc, 0xd5, 0xb1, 0x8f, - 0x71, 0xab, 0xe3, 0x78, 0x8e, 0xd2, 0x6f, 0xca, 0xd5, 0x8d, 0xed, 0xda, 0x5b, 0x47, 0xd0, 0xbb, - 0xfe, 0x17, 0x8a, 0x08, 0x1b, 0x3c, 0x82, 0x88, 0x04, 0xcd, 0x86, 0x45, 0xe4, 0xdb, 0x53, 0x14, - 0x11, 0x55, 0x64, 0x4a, 0x11, 0x59, 0x83, 0x9c, 0x43, 0xed, 0x43, 0xb3, 0xc1, 0xd8, 0x21, 0x44, - 0x04, 0x43, 0xd8, 0x16, 0xc3, 0xb5, 0xaa, 0x63, 0x00, 0x42, 0x6a, 0x4d, 0x87, 0xac, 0xc0, 0x34, - 0x72, 0x49, 0xa8, 0xc5, 0xcc, 0x7a, 0xae, 0xdf, 0x5b, 0xce, 0x0a, 0x32, 0x39, 0x46, 0x56, 0xb0, - 0xc9, 0x21, 0x55, 0x98, 0x6f, 0x52, 0xc7, 0xb4, 0x69, 0x73, 0xc7, 0x71, 0xeb, 0x2e, 0xea, 0xc3, - 0x7c, 0xe5, 0x3f, 0x51, 0x29, 0xde, 0x66, 0x28, 0x63, 0x0e, 0x8d, 0xf8, 0x9b, 0x42, 0x64, 0xb2, + // 1777 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x5a, 0xcf, 0x6f, 0xdb, 0xc6, + 0x12, 0x8e, 0x24, 0xdb, 0xb2, 0x47, 0x96, 0x13, 0xaf, 0x95, 0x3c, 0x81, 0xc9, 0x93, 0x03, 0xe6, + 0xc5, 0x91, 0x81, 0x3c, 0x39, 0x4f, 0x79, 0x41, 0xd3, 0x14, 0xfd, 0x65, 0xbb, 0x71, 0x95, 0x1f, + 0x6e, 0x40, 0x27, 0x6d, 0x6f, 0x86, 0x2c, 0x6d, 0x5c, 0x56, 0xb2, 0xa8, 0x92, 0xb4, 0x93, 0xa0, + 0x97, 0x16, 0x68, 0x81, 0xfe, 0x09, 0xbd, 0xf6, 0xda, 0x02, 0x3d, 0xf7, 0xd6, 0x6b, 0xd0, 0x53, + 0x8f, 0x3d, 0x19, 0x8d, 0x80, 0x02, 0x3d, 0x15, 0xfd, 0x0b, 0x8a, 0x62, 0x77, 0x67, 0x49, 0x8a, + 0x5a, 0x92, 0x92, 0xe5, 0xc2, 0x39, 0x99, 0x5c, 0x7e, 0xb3, 0x33, 0xbb, 0xf3, 0xed, 0xa7, 0xd9, + 0x81, 0x21, 0xdf, 0xb0, 0x3a, 0xae, 0x6d, 0xb5, 0x2b, 0x5d, 0xdb, 0x72, 0x2d, 0x42, 0x9a, 0x56, + 0xa3, 0x45, 0xed, 0x8a, 0xf3, 0xa4, 0x6e, 0xef, 0xb5, 0x4c, 0xb7, 0x72, 0xf0, 0x3f, 0x2d, 0xe7, + 0x74, 0x69, 0xc3, 0x11, 0x00, 0x2d, 0x6f, 0xed, 0x7c, 0x4c, 0x1b, 0xae, 0x7c, 0xcd, 0xb9, 0xcf, + 0xba, 0x54, 0xbe, 0x14, 0x76, 0xad, 0x5d, 0x8b, 0x3f, 0xae, 0xb0, 0x27, 0x1c, 0x5d, 0xe8, 0xb6, + 0xf7, 0x77, 0xcd, 0xce, 0x8a, 0xf8, 0x23, 0x06, 0xf5, 0x1b, 0x30, 0xb7, 0x41, 0xdd, 0x4d, 0xab, + 0x49, 0x0d, 0xfa, 0xc9, 0x3e, 0x75, 0x5c, 0x72, 0x09, 0xb2, 0x1d, 0xab, 0x49, 0xb7, 0xcd, 0x66, + 0x31, 0x75, 0x31, 0x55, 0x9e, 0x59, 0x85, 0xde, 0xe1, 0xe2, 0x14, 0x43, 0xd4, 0xd6, 0x8d, 0x29, + 0xf6, 0xa9, 0xd6, 0xd4, 0xdf, 0x84, 0xd3, 0x9e, 0x99, 0xd3, 0xb5, 0x3a, 0x0e, 0x25, 0x57, 0x61, + 0x82, 0x7d, 0xe4, 0x46, 0xb9, 0x6a, 0xb1, 0x32, 0xb8, 0x80, 0x0a, 0xc7, 0x73, 0x94, 0x7e, 0x98, + 0x81, 0x33, 0xf7, 0x4c, 0x87, 0x4f, 0xe1, 0x48, 0xd7, 0xb7, 0x21, 0xfb, 0xd8, 0x6c, 0xbb, 0xd4, + 0x76, 0x70, 0x96, 0xab, 0xaa, 0x59, 0xc2, 0x66, 0x95, 0xdb, 0xc2, 0xc6, 0x90, 0xc6, 0xda, 0xe7, + 0x19, 0xc8, 0xe2, 0x20, 0x29, 0xc0, 0x64, 0xa7, 0xbe, 0x47, 0xd9, 0x8c, 0x99, 0xf2, 0x8c, 0x21, + 0x5e, 0xc8, 0x0a, 0xe4, 0xcc, 0xe6, 0x76, 0xd7, 0xa6, 0x8f, 0xcd, 0xa7, 0xd4, 0x29, 0xa6, 0xd9, + 0xb7, 0xd5, 0xb9, 0xde, 0xe1, 0x22, 0xd4, 0xd6, 0x1f, 0xe0, 0xa8, 0x01, 0x66, 0x53, 0x3e, 0x93, + 0x07, 0x30, 0xd5, 0xae, 0xef, 0xd0, 0xb6, 0x53, 0xcc, 0x5c, 0xcc, 0x94, 0x73, 0xd5, 0x9b, 0xa3, + 0x44, 0x56, 0xb9, 0xc7, 0x4d, 0xdf, 0xe9, 0xb8, 0xf6, 0x33, 0x03, 0xe7, 0x21, 0x35, 0xc8, 0xed, + 0xd1, 0xbd, 0x1d, 0x6a, 0x3b, 0x1f, 0x99, 0x5d, 0xa7, 0x38, 0x71, 0x31, 0x53, 0x9e, 0xab, 0x5e, + 0x89, 0xda, 0xb6, 0xad, 0x2e, 0x6d, 0x54, 0xee, 0x7b, 0x78, 0x23, 0x68, 0x4b, 0xaa, 0x30, 0x69, + 0x5b, 0x6d, 0xea, 0x14, 0x27, 0xf9, 0x24, 0x17, 0x22, 0xf7, 0xde, 0x6a, 0x53, 0x43, 0x40, 0xc9, + 0x25, 0xc8, 0xb3, 0xad, 0xf0, 0xf7, 0x60, 0x8a, 0xef, 0xcf, 0x2c, 0x1b, 0x94, 0xab, 0xd6, 0x5e, + 0x85, 0x5c, 0x20, 0x74, 0x72, 0x06, 0x32, 0x2d, 0xfa, 0x4c, 0xd0, 0xc2, 0x60, 0x8f, 0x6c, 0x77, + 0x0f, 0xea, 0xed, 0x7d, 0x5a, 0x4c, 0xf3, 0x31, 0xf1, 0x72, 0x2b, 0x7d, 0x33, 0xa5, 0xaf, 0xc1, + 0x7c, 0x60, 0x3b, 0x90, 0x23, 0x15, 0x98, 0x64, 0xd9, 0x17, 0xc9, 0x88, 0x23, 0x89, 0x80, 0xe9, + 0xdf, 0xa6, 0x60, 0xfe, 0x51, 0xb7, 0x59, 0x77, 0xe9, 0xa8, 0x0c, 0x25, 0x6f, 0xc0, 0x2c, 0x07, + 0x1d, 0x50, 0xdb, 0x31, 0xad, 0x0e, 0x0f, 0x30, 0x57, 0x3d, 0xaf, 0xf2, 0xf8, 0xbe, 0x80, 0x18, + 0x39, 0x66, 0x80, 0x2f, 0xe4, 0x1a, 0x4c, 0xb0, 0xe3, 0x56, 0xcc, 0x70, 0xbb, 0x0b, 0x71, 0x79, + 0x31, 0x38, 0x52, 0x5f, 0x05, 0x12, 0x8c, 0xf5, 0x48, 0xc7, 0x62, 0x13, 0xe6, 0x0d, 0xba, 0x67, + 0x1d, 0x8c, 0xbe, 0xde, 0x02, 0x4c, 0x3e, 0xb6, 0xec, 0x86, 0xc8, 0xc4, 0xb4, 0x21, 0x5e, 0xf4, + 0x02, 0x90, 0xe0, 0x7c, 0x22, 0x26, 0x3c, 0xf4, 0x0f, 0xeb, 0x4e, 0x2b, 0xe0, 0xc2, 0xad, 0x3b, + 0xad, 0x90, 0x0b, 0x86, 0x60, 0x2e, 0xd8, 0x27, 0xef, 0xd0, 0x0b, 0x33, 0x7f, 0x75, 0xec, 0x63, + 0xdc, 0xea, 0x38, 0x9e, 0xa3, 0xf4, 0x9b, 0x72, 0x75, 0x23, 0xbb, 0xf6, 0xd6, 0x11, 0xf4, 0xae, + 0xff, 0x85, 0x22, 0xc2, 0x06, 0x8f, 0x20, 0x22, 0x41, 0xb3, 0x41, 0x11, 0xf9, 0xe6, 0x04, 0x45, + 0x44, 0x15, 0x99, 0x52, 0x44, 0x56, 0x20, 0xe7, 0x50, 0xfb, 0xc0, 0x6c, 0x30, 0x76, 0x08, 0x11, + 0xc1, 0x10, 0xb6, 0xc4, 0x70, 0x6d, 0xdd, 0x31, 0x00, 0x21, 0xb5, 0xa6, 0x43, 0x96, 0x60, 0x1a, + 0xb9, 0x24, 0xd4, 0x62, 0x66, 0x35, 0xd7, 0x3b, 0x5c, 0xcc, 0x0a, 0x32, 0x39, 0x46, 0x56, 0xb0, + 0xc9, 0x21, 0xeb, 0x30, 0xd7, 0xa4, 0x8e, 0x69, 0xd3, 0xe6, 0xb6, 0xe3, 0xd6, 0x5d, 0xd4, 0x87, + 0xb9, 0xea, 0xbf, 0xa3, 0x52, 0xbc, 0xc5, 0x50, 0x46, 0x1e, 0x8d, 0xf8, 0x9b, 0x42, 0x64, 0xb2, 0xff, 0x88, 0xc8, 0xe0, 0x76, 0xf9, 0x22, 0xc3, 0x58, 0x13, 0x2b, 0x32, 0x9c, 0x46, 0x02, 0xa6, - 0xdf, 0x85, 0xfc, 0x86, 0x4d, 0xeb, 0x2e, 0xc5, 0x2d, 0x93, 0x44, 0xba, 0x8e, 0x0a, 0x20, 0x58, - 0xb4, 0xac, 0x9a, 0x06, 0x2d, 0x02, 0x22, 0xb0, 0x05, 0x4b, 0xa1, 0xc9, 0x30, 0xaa, 0x1b, 0x90, - 0xc5, 0x34, 0xe0, 0x84, 0xe7, 0x63, 0x26, 0x34, 0x24, 0x56, 0x7f, 0x07, 0x16, 0x36, 0xa9, 0x1b, - 0x8a, 0xec, 0x2a, 0x80, 0x9f, 0x75, 0x3c, 0x35, 0x73, 0xfd, 0xde, 0xf2, 0x8c, 0x97, 0x74, 0x63, - 0xc6, 0xcb, 0xb9, 0x7e, 0x17, 0x48, 0x70, 0x8a, 0xe3, 0xc5, 0xf3, 0x63, 0x0a, 0xf2, 0x42, 0xe5, - 0x8e, 0x13, 0x13, 0xa9, 0xc2, 0x59, 0x89, 0x1e, 0x43, 0xa0, 0xe7, 0xd1, 0x46, 0x6a, 0xf4, 0xf5, - 0x01, 0x8d, 0x1e, 0x3d, 0x43, 0xa1, 0x05, 0x1c, 0x6f, 0x47, 0xaa, 0x90, 0x17, 0xd2, 0x74, 0xac, - 0x24, 0xfd, 0x1b, 0x96, 0x42, 0xb3, 0xa0, 0xc6, 0xfd, 0x9e, 0x86, 0x45, 0xc6, 0x71, 0x1c, 0xf7, - 0x64, 0xae, 0x16, 0x96, 0xb9, 0xb5, 0x28, 0x31, 0x09, 0x59, 0x0e, 0x2b, 0xdd, 0x57, 0xe9, 0x13, - 0x57, 0xba, 0xed, 0x90, 0xd2, 0xbd, 0x3e, 0x66, 0x70, 0x4a, 0xb1, 0x1b, 0x52, 0x93, 0x89, 0x93, - 0x55, 0x93, 0xf7, 0x21, 0x3f, 0x18, 0x12, 0x12, 0xe3, 0x55, 0x98, 0xc6, 0x44, 0x49, 0x4d, 0x89, - 0x65, 0x86, 0x07, 0xf6, 0x95, 0x65, 0x8b, 0xba, 0x4f, 0x2c, 0xbb, 0x35, 0x86, 0xb2, 0xa0, 0x85, + 0xdf, 0x85, 0xc2, 0x9a, 0x4d, 0xeb, 0x2e, 0xc5, 0x2d, 0x93, 0x44, 0xba, 0x8e, 0x0a, 0x20, 0x58, + 0xb4, 0xa8, 0x9a, 0x06, 0x2d, 0x02, 0x22, 0xb0, 0x09, 0x67, 0x43, 0x93, 0x61, 0x54, 0x37, 0x20, + 0x8b, 0x69, 0xc0, 0x09, 0xcf, 0xc7, 0x4c, 0x68, 0x48, 0xac, 0xfe, 0x36, 0xcc, 0x6f, 0x50, 0x37, + 0x14, 0xd9, 0x55, 0x00, 0x3f, 0xeb, 0x78, 0x6a, 0xf2, 0xbd, 0xc3, 0xc5, 0x19, 0x2f, 0xe9, 0xc6, + 0x8c, 0x97, 0x73, 0xfd, 0x2e, 0x90, 0xe0, 0x14, 0xe3, 0xc5, 0xf3, 0x63, 0x0a, 0x0a, 0x42, 0xe5, + 0xc6, 0x89, 0x89, 0xac, 0xc3, 0x69, 0x89, 0x1e, 0x41, 0xa0, 0xe7, 0xd0, 0x46, 0x6a, 0xf4, 0xf5, + 0x3e, 0x8d, 0x1e, 0x3e, 0x43, 0xa1, 0x05, 0x8c, 0xb7, 0x23, 0xeb, 0x50, 0x10, 0xd2, 0x34, 0x56, + 0x92, 0xfe, 0x05, 0x67, 0x43, 0xb3, 0xa0, 0xc6, 0xfd, 0x9e, 0x86, 0x05, 0xc6, 0x71, 0x1c, 0xf7, + 0x64, 0xae, 0x16, 0x96, 0xb9, 0x95, 0x28, 0x31, 0x09, 0x59, 0x0e, 0x2a, 0xdd, 0x97, 0xe9, 0x63, + 0x57, 0xba, 0xad, 0x90, 0xd2, 0xbd, 0x36, 0x62, 0x70, 0x4a, 0xb1, 0x1b, 0x50, 0x93, 0x89, 0xe3, + 0x55, 0x93, 0xf7, 0xa0, 0xd0, 0x1f, 0x12, 0x12, 0xe3, 0x15, 0x98, 0xc6, 0x44, 0x49, 0x4d, 0x89, + 0x65, 0x86, 0x07, 0xf6, 0x95, 0x65, 0x93, 0xba, 0x4f, 0x2c, 0xbb, 0x35, 0x82, 0xb2, 0xa0, 0x85, 0x4a, 0x59, 0xbc, 0xc9, 0x7c, 0xde, 0x76, 0xc4, 0x50, 0x1c, 0x6f, 0xa5, 0x95, 0xc4, 0xea, 0x8f, 0xb8, 0xb2, 0x84, 0x22, 0x23, 0x30, 0xc1, 0x76, 0x13, 0xf7, 0x8b, 0x3f, 0x33, 0x22, 0xa3, 0x0d, - 0x23, 0x72, 0xda, 0x27, 0x32, 0xda, 0x32, 0x22, 0x23, 0xc0, 0x53, 0x9b, 0x13, 0x8a, 0xf1, 0x23, - 0x79, 0xb6, 0x4e, 0x3c, 0x4c, 0xef, 0xbc, 0x85, 0x22, 0xf5, 0xce, 0x1b, 0x8e, 0x1f, 0xe1, 0xbc, - 0x85, 0x2c, 0x5f, 0xae, 0xf3, 0x16, 0x11, 0xdc, 0x69, 0x9e, 0x37, 0x3f, 0x24, 0xff, 0xbc, 0x61, - 0xa2, 0x62, 0xcf, 0x9b, 0xcc, 0x9c, 0x07, 0xc6, 0x1f, 0xcb, 0x8d, 0xf6, 0x81, 0xe3, 0x52, 0x3b, + 0x23, 0x72, 0xda, 0x27, 0x32, 0xda, 0x32, 0x22, 0x23, 0xc0, 0x53, 0x9b, 0x63, 0x8a, 0xf1, 0x43, + 0x79, 0xb6, 0x8e, 0x3d, 0x4c, 0xef, 0xbc, 0x85, 0x22, 0xf5, 0xce, 0x1b, 0x8e, 0x1f, 0xe1, 0xbc, + 0x85, 0x2c, 0x5f, 0xae, 0xf3, 0x16, 0x11, 0xdc, 0x49, 0x9e, 0x37, 0x3f, 0x24, 0xff, 0xbc, 0x61, + 0xa2, 0x62, 0xcf, 0x9b, 0xcc, 0x9c, 0x07, 0xc6, 0x1f, 0xcb, 0xb5, 0xf6, 0xbe, 0xe3, 0x52, 0x3b, 0xa0, 0xc3, 0x0d, 0x31, 0x12, 0xd2, 0x61, 0xc4, 0x31, 0x5e, 0x20, 0xc0, 0xa3, 0xaf, 0x37, 0x85, 0x4f, 0x5f, 0x84, 0xc4, 0xd1, 0x57, 0x5a, 0x49, 0xac, 0xc7, 0x25, 0xfc, 0x70, 0x04, 0x2e, 0x85, - 0x2c, 0x5f, 0x2e, 0x2e, 0x45, 0x04, 0x77, 0x9a, 0x5c, 0xf2, 0x43, 0xf2, 0xb9, 0x84, 0xd9, 0x88, - 0xe5, 0x92, 0x4c, 0x9d, 0x07, 0xd6, 0x0f, 0x60, 0xe1, 0x8e, 0x65, 0x76, 0x1e, 0x5a, 0x2d, 0xda, - 0x31, 0x2c, 0xb7, 0xee, 0xb2, 0x82, 0xa3, 0x0c, 0x8b, 0x36, 0x7b, 0xa6, 0x3b, 0x8c, 0x70, 0xd4, - 0xde, 0x71, 0xd9, 0x67, 0x1e, 0xe1, 0xb4, 0xb1, 0x20, 0x3e, 0x7d, 0xc8, 0xbf, 0x70, 0x3b, 0x72, - 0x0d, 0xf2, 0x88, 0xdf, 0xaf, 0x77, 0xea, 0x7b, 0x9e, 0x81, 0xb8, 0xa3, 0x11, 0xf1, 0xed, 0xbe, - 0xf8, 0xc4, 0x2d, 0xf4, 0xaf, 0xd3, 0xb2, 0xbe, 0x3a, 0x0e, 0x8d, 0x59, 0x7d, 0x25, 0xd1, 0xe3, - 0xd4, 0x57, 0x68, 0x33, 0x46, 0x7d, 0x85, 0xde, 0xfd, 0xdf, 0x29, 0xb2, 0x09, 0xd3, 0x36, 0xee, - 0x57, 0x61, 0x82, 0x1b, 0x5e, 0x56, 0x19, 0x0e, 0x6d, 0xee, 0xfa, 0xc4, 0xf3, 0xde, 0xf2, 0x19, - 0xc3, 0x33, 0xf6, 0x0b, 0xb5, 0x13, 0x3a, 0x8d, 0x6f, 0xc0, 0x39, 0x5e, 0x07, 0x37, 0x6c, 0xea, - 0xca, 0x5d, 0x5d, 0x85, 0x19, 0x87, 0x0f, 0xf8, 0x9b, 0x3a, 0xdb, 0xef, 0x2d, 0x4f, 0x0b, 0x54, - 0xad, 0xca, 0x7e, 0xcc, 0xf9, 0x53, 0x53, 0xdf, 0xc4, 0x4a, 0x5c, 0x98, 0x63, 0x28, 0x15, 0x98, - 0x12, 0x00, 0x8c, 0x44, 0x53, 0x17, 0x06, 0xdc, 0x06, 0x91, 0xfa, 0x6f, 0x69, 0x20, 0xa2, 0xce, - 0x60, 0xaf, 0x9e, 0x28, 0xbc, 0x17, 0x16, 0x85, 0x72, 0x74, 0xcd, 0x14, 0x34, 0x1c, 0xd6, 0x84, - 0x2f, 0x4f, 0x5e, 0x13, 0x8c, 0x90, 0x26, 0xdc, 0x1a, 0x2f, 0xb6, 0x53, 0x91, 0x84, 0xbb, 0xb2, - 0x70, 0xc6, 0x88, 0x30, 0x65, 0xaf, 0xb0, 0x32, 0x9f, 0x0f, 0xa1, 0x20, 0xc4, 0xe5, 0x4c, 0x42, - 0xf5, 0x1a, 0x2c, 0xca, 0x7b, 0x5d, 0x90, 0x3f, 0x95, 0x81, 0x4a, 0xae, 0x18, 0x3d, 0x53, 0xa0, - 0x90, 0xbb, 0xe3, 0xdf, 0x37, 0x8f, 0xcd, 0xa5, 0xb7, 0x61, 0x51, 0x5e, 0x1b, 0x8e, 0x48, 0xeb, - 0x7f, 0xf9, 0xd7, 0x97, 0x60, 0x34, 0x95, 0x1f, 0x96, 0x20, 0xbb, 0x21, 0x5a, 0xd2, 0xc4, 0x84, - 0x2c, 0x76, 0x7b, 0x89, 0xae, 0x0a, 0x6a, 0xb0, 0x83, 0xac, 0x5d, 0x8a, 0xc5, 0x60, 0x9d, 0xb5, - 0xf4, 0xd3, 0xf7, 0x7f, 0x7c, 0x93, 0x3e, 0x0b, 0x73, 0x1c, 0xf4, 0x3f, 0xd4, 0x47, 0x62, 0xc1, - 0x8c, 0xd7, 0x36, 0x24, 0xff, 0x1d, 0xa5, 0xc9, 0xaa, 0x5d, 0x4e, 0x40, 0xc5, 0x3b, 0xb4, 0x01, - 0xfc, 0xae, 0x1d, 0x51, 0xce, 0x35, 0xd4, 0x81, 0xd4, 0x56, 0x92, 0x60, 0x89, 0x3e, 0xfd, 0xae, - 0x9c, 0xda, 0xe7, 0x50, 0x17, 0x50, 0xed, 0x53, 0xd1, 0xdc, 0x8b, 0xf0, 0x29, 0x72, 0xf8, 0xb0, - 0xee, 0xb4, 0x22, 0x73, 0x18, 0xe8, 0xca, 0x45, 0xe6, 0x70, 0xa0, 0xff, 0x16, 0x9f, 0x43, 0xde, - 0x95, 0x89, 0xce, 0x61, 0xb0, 0xc7, 0x15, 0x9d, 0xc3, 0x81, 0xd6, 0x4e, 0xe2, 0x7e, 0xf2, 0xe5, - 0xc5, 0xec, 0x67, 0x70, 0x85, 0x2b, 0x49, 0xb0, 0x44, 0x9f, 0x7e, 0x57, 0x45, 0xed, 0x73, 0xa8, - 0x71, 0xa3, 0xf6, 0x39, 0xdc, 0x9c, 0x89, 0xf2, 0xf9, 0x14, 0x66, 0x83, 0x17, 0x54, 0x72, 0x65, - 0xc4, 0x5b, 0xb5, 0x56, 0x4a, 0x06, 0xc6, 0x7b, 0xfe, 0x0c, 0xe6, 0x06, 0xda, 0x5a, 0x44, 0x39, - 0xa3, 0xaa, 0x8d, 0xa6, 0xad, 0x8e, 0x80, 0x4c, 0x74, 0x3e, 0xd0, 0xb1, 0x51, 0x3b, 0x57, 0x75, - 0xa5, 0xd4, 0xce, 0x95, 0xed, 0x9f, 0x18, 0xe7, 0x03, 0x8d, 0x19, 0xb5, 0x73, 0x55, 0x07, 0x48, - 0xed, 0x5c, 0xdd, 0xe5, 0x89, 0x25, 0x19, 0x5e, 0x74, 0x22, 0x49, 0x36, 0x78, 0x39, 0x8e, 0x24, - 0x59, 0xf8, 0xa6, 0x1b, 0x4f, 0x32, 0x79, 0x2b, 0x8b, 0x26, 0x59, 0xe8, 0x2a, 0x19, 0x4d, 0xb2, - 0xf0, 0x05, 0x2f, 0x91, 0x64, 0x72, 0xc1, 0x31, 0x24, 0x0b, 0xad, 0x79, 0x75, 0x04, 0xe4, 0x88, - 0x79, 0x8e, 0x75, 0xae, 0xea, 0x46, 0xc4, 0xe5, 0x79, 0x44, 0xe7, 0x22, 0xcf, 0x58, 0xb1, 0x46, - 0xe6, 0x79, 0xf0, 0x46, 0x10, 0x99, 0xe7, 0x50, 0xb9, 0x9c, 0x90, 0x67, 0x79, 0x63, 0x8a, 0xce, - 0x73, 0xe8, 0x9a, 0x17, 0x9d, 0xe7, 0xf0, 0xe5, 0x2b, 0xf1, 0x3c, 0xcb, 0x05, 0xc7, 0x9c, 0xe7, - 0xd0, 0x9a, 0x57, 0x47, 0x40, 0x26, 0xfe, 0x38, 0x79, 0x65, 0xbc, 0xfa, 0xc7, 0x29, 0x7c, 0x49, - 0xd0, 0x2e, 0x27, 0xa0, 0xe2, 0x1d, 0x1e, 0x40, 0x2e, 0x50, 0x86, 0x92, 0x95, 0xd1, 0x2a, 0x67, - 0xed, 0x4a, 0x22, 0x2e, 0x31, 0xbd, 0xc1, 0x2a, 0x53, 0x9d, 0x5e, 0x45, 0x49, 0xab, 0x95, 0x92, - 0x81, 0x89, 0x9e, 0x83, 0x15, 0xa5, 0xda, 0xb3, 0xa2, 0x6a, 0xd5, 0x4a, 0xc9, 0xc0, 0x58, 0xcf, - 0xeb, 0x17, 0x9e, 0xbf, 0x28, 0x9e, 0xf9, 0xe5, 0x45, 0xf1, 0xcc, 0x9f, 0x2f, 0x8a, 0xa9, 0xcf, - 0xfb, 0xc5, 0xd4, 0xf3, 0x7e, 0x31, 0xf5, 0x73, 0xbf, 0x98, 0xfa, 0xb5, 0x5f, 0x4c, 0xed, 0x4e, - 0xf1, 0xff, 0x78, 0xb8, 0xfe, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xde, 0x36, 0x11, 0xa9, 0x6a, - 0x21, 0x00, 0x00, + 0x2c, 0x5f, 0x2e, 0x2e, 0x45, 0x04, 0x77, 0x92, 0x5c, 0xf2, 0x43, 0xf2, 0xb9, 0x84, 0xd9, 0x88, + 0xe5, 0x92, 0x4c, 0x9d, 0x07, 0xd6, 0xf7, 0x61, 0xfe, 0x8e, 0x65, 0x76, 0x1e, 0x5a, 0x2d, 0xda, + 0x31, 0x2c, 0xb7, 0xee, 0xb2, 0x82, 0xa3, 0x02, 0x0b, 0x36, 0x7b, 0xa6, 0xdb, 0x8c, 0x70, 0xd4, + 0xde, 0x76, 0xd9, 0x67, 0x1e, 0xe1, 0xb4, 0x31, 0x2f, 0x3e, 0x7d, 0xc0, 0xbf, 0x70, 0x3b, 0x72, + 0x0d, 0x0a, 0x88, 0xdf, 0xab, 0x77, 0xea, 0xbb, 0x9e, 0x81, 0xb8, 0xa3, 0x11, 0xf1, 0xed, 0xbe, + 0xf8, 0xc4, 0x2d, 0xf4, 0xaf, 0xd2, 0xb2, 0xbe, 0x1a, 0x87, 0xc6, 0xac, 0xbe, 0x92, 0xe8, 0x51, + 0xea, 0x2b, 0xb4, 0x19, 0xa1, 0xbe, 0x42, 0xef, 0xfe, 0xef, 0x14, 0xd9, 0x80, 0x69, 0x1b, 0xf7, + 0xab, 0x38, 0xc1, 0x0d, 0x2f, 0xab, 0x0c, 0x07, 0x36, 0x77, 0x75, 0xe2, 0xf9, 0xe1, 0xe2, 0x29, + 0xc3, 0x33, 0xf6, 0x0b, 0xb5, 0x63, 0x3a, 0x8d, 0xaf, 0xc3, 0x19, 0x5e, 0x07, 0x37, 0x6c, 0xea, + 0xca, 0x5d, 0x5d, 0x86, 0x19, 0x87, 0x0f, 0xf8, 0x9b, 0x3a, 0xdb, 0x3b, 0x5c, 0x9c, 0x16, 0xa8, + 0xda, 0x3a, 0xfb, 0x31, 0xe7, 0x4f, 0x4d, 0x7d, 0x03, 0x2b, 0x71, 0x61, 0x8e, 0xa1, 0x54, 0x61, + 0x4a, 0x00, 0x30, 0x12, 0x4d, 0x5d, 0x18, 0x70, 0x1b, 0x44, 0xea, 0x3f, 0xa4, 0x60, 0x41, 0x56, + 0xa0, 0x47, 0x8b, 0x85, 0xac, 0xc2, 0x1c, 0x42, 0x47, 0xc8, 0x6e, 0x5e, 0x98, 0xc8, 0xe4, 0x56, + 0xfb, 0x92, 0x5b, 0x8a, 0x0e, 0x3c, 0x50, 0x83, 0xdc, 0xf1, 0x8b, 0xff, 0xb1, 0xb7, 0xe1, 0xb7, + 0x34, 0x10, 0x51, 0x6e, 0xb1, 0x57, 0x4f, 0x1b, 0xdf, 0x0d, 0x6b, 0x63, 0x25, 0xba, 0x74, 0x0c, + 0x1a, 0x0e, 0x4a, 0xe3, 0x17, 0xc7, 0x2f, 0x8d, 0x46, 0x48, 0x1a, 0x6f, 0x8d, 0x16, 0xdb, 0x89, + 0x28, 0xe3, 0x5d, 0x79, 0x7f, 0xc0, 0x88, 0x30, 0x65, 0xff, 0x67, 0xb7, 0x1d, 0x3e, 0x84, 0xba, + 0x18, 0x97, 0x33, 0x09, 0xd5, 0x6b, 0xb0, 0x20, 0xaf, 0xb7, 0x41, 0xea, 0x56, 0xfb, 0x0a, 0xda, + 0xa1, 0xb9, 0xd4, 0x3f, 0xd5, 0x18, 0x5c, 0x7a, 0x0b, 0x16, 0xe4, 0xed, 0xe9, 0x88, 0xa7, 0xfb, + 0x9c, 0x7f, 0x8b, 0x0b, 0x46, 0x53, 0xfd, 0xee, 0x1c, 0x64, 0xd7, 0x44, 0x67, 0x9e, 0x98, 0x90, + 0xc5, 0xa6, 0x37, 0xd1, 0x55, 0x41, 0xf5, 0x37, 0xd2, 0xb5, 0x4b, 0xb1, 0x18, 0x2c, 0x37, 0xcf, + 0xfe, 0xf4, 0xfd, 0x1f, 0x5f, 0xa7, 0x4f, 0x43, 0x9e, 0x83, 0xfe, 0x8b, 0x3f, 0x13, 0xc4, 0x82, + 0x19, 0xaf, 0x7b, 0x4a, 0xfe, 0x33, 0x4c, 0xaf, 0x59, 0xbb, 0x9c, 0x80, 0x8a, 0x77, 0x68, 0x03, + 0xf8, 0xcd, 0x4b, 0xa2, 0x9c, 0x6b, 0xa0, 0x11, 0xab, 0x2d, 0x25, 0xc1, 0x12, 0x7d, 0xfa, 0xcd, + 0x49, 0xb5, 0xcf, 0x81, 0x66, 0xa8, 0xda, 0xa7, 0xa2, 0xc7, 0x19, 0xe1, 0x53, 0xe4, 0xf0, 0x61, + 0xdd, 0x69, 0x45, 0xe6, 0x30, 0xd0, 0x9c, 0x8c, 0xcc, 0x61, 0x5f, 0x1b, 0x32, 0x3e, 0x87, 0xbc, + 0x39, 0x15, 0x9d, 0xc3, 0x60, 0xab, 0x2f, 0x3a, 0x87, 0x7d, 0x1d, 0xae, 0xc4, 0xfd, 0xe4, 0xcb, + 0x8b, 0xd9, 0xcf, 0xe0, 0x0a, 0x97, 0x92, 0x60, 0x89, 0x3e, 0xfd, 0xe6, 0x92, 0xda, 0xe7, 0x40, + 0xff, 0x4a, 0xed, 0x73, 0xb0, 0x47, 0x15, 0xe5, 0xf3, 0x29, 0xcc, 0x06, 0xef, 0xe9, 0xe4, 0xca, + 0x90, 0xcd, 0x05, 0xad, 0x9c, 0x0c, 0x8c, 0xf7, 0xfc, 0x29, 0xe4, 0xfb, 0xba, 0x7b, 0x44, 0x39, + 0xa3, 0xaa, 0x9b, 0xa8, 0x2d, 0x0f, 0x81, 0x4c, 0x74, 0xde, 0xd7, 0xb8, 0x52, 0x3b, 0x57, 0x35, + 0xe7, 0xd4, 0xce, 0x95, 0x5d, 0xb0, 0x18, 0xe7, 0x7d, 0xfd, 0x29, 0xb5, 0x73, 0x55, 0x23, 0x4c, + 0xed, 0x5c, 0xdd, 0xec, 0x8a, 0x25, 0x19, 0xde, 0xf7, 0x22, 0x49, 0xd6, 0xdf, 0x23, 0x88, 0x24, + 0x59, 0xf8, 0xc2, 0x1f, 0x4f, 0x32, 0x79, 0x39, 0x8d, 0x26, 0x59, 0xe8, 0x46, 0x1d, 0x4d, 0xb2, + 0xf0, 0x3d, 0x37, 0x91, 0x64, 0x72, 0xc1, 0x31, 0x24, 0x0b, 0xad, 0x79, 0x79, 0x08, 0xe4, 0x90, + 0x79, 0x8e, 0x75, 0xae, 0x6a, 0xca, 0xc4, 0xe5, 0x79, 0x48, 0xe7, 0x22, 0xcf, 0x58, 0xb8, 0x47, + 0xe6, 0xb9, 0xff, 0x62, 0x14, 0x99, 0xe7, 0xd0, 0xad, 0x21, 0x21, 0xcf, 0xf2, 0xe2, 0x18, 0x9d, + 0xe7, 0xd0, 0x6d, 0x37, 0x3a, 0xcf, 0xe1, 0x3b, 0x68, 0xe2, 0x79, 0x96, 0x0b, 0x8e, 0x39, 0xcf, + 0xa1, 0x35, 0x2f, 0x0f, 0x81, 0x4c, 0xfc, 0x71, 0xf2, 0x6e, 0x33, 0xea, 0x1f, 0xa7, 0xf0, 0x5d, + 0x49, 0xbb, 0x9c, 0x80, 0x4a, 0xdc, 0xe7, 0xe0, 0xd5, 0x41, 0xbd, 0xcf, 0x8a, 0x6b, 0x91, 0x56, + 0x4e, 0x06, 0xc6, 0x7b, 0xde, 0x87, 0x5c, 0xa0, 0x00, 0x26, 0x4b, 0xc3, 0xd5, 0xec, 0xda, 0x95, + 0x44, 0x5c, 0xe2, 0x82, 0x83, 0xf5, 0xad, 0x7a, 0xc1, 0x8a, 0x62, 0x5a, 0x2b, 0x27, 0x03, 0x13, + 0x3d, 0x07, 0x6b, 0x59, 0xb5, 0x67, 0x45, 0xbd, 0xac, 0x95, 0x93, 0x81, 0xb1, 0x9e, 0x57, 0x2f, + 0x3c, 0x7f, 0x51, 0x3a, 0xf5, 0xcb, 0x8b, 0xd2, 0xa9, 0x3f, 0x5f, 0x94, 0x52, 0x9f, 0xf5, 0x4a, + 0xa9, 0xe7, 0xbd, 0x52, 0xea, 0xe7, 0x5e, 0x29, 0xf5, 0x6b, 0xaf, 0x94, 0xda, 0x99, 0xe2, 0xff, + 0x72, 0x72, 0xfd, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2a, 0x7c, 0x4c, 0x3e, 0xeb, 0x22, 0x00, + 0x00, } diff --git a/vendor/src/github.com/docker/swarmkit/api/control.proto b/vendor/src/github.com/docker/swarmkit/api/control.proto index 3be83d5600fcc..a05c55b4add40 100644 --- a/vendor/src/github.com/docker/swarmkit/api/control.proto +++ b/vendor/src/github.com/docker/swarmkit/api/control.proto @@ -83,6 +83,15 @@ service Control { option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" }; } + // UpdateSecret returns a `UpdateSecretResponse` with a `Secret` with the same + // id as `GetSecretRequest.SecretID` + // - Returns `NotFound` if the Secret with the given id is not found. + // - Returns `InvalidArgument` if the `GetSecretRequest.SecretID` is empty. + // - Returns an error if updating fails. + rpc UpdateSecret(UpdateSecretRequest) returns (UpdateSecretResponse) { + option (docker.protobuf.plugin.tls_authorization) = { roles: "swarm-manager" }; + }; + // ListSecrets returns a `ListSecretResponse` with a list all non-internal `Secret`s being // managed, or all secrets matching any name in `ListSecretsRequest.Names`, any // name prefix in `ListSecretsRequest.NamePrefixes`, any id in @@ -342,6 +351,23 @@ message GetSecretResponse { Secret secret = 1; } +message UpdateSecretRequest { + // SecretID is the secret ID to update. + string secret_id = 1 [(gogoproto.customname) = "SecretID"]; + + // SecretVersion is the version of the secret being updated. + Version secret_version = 2; + + // Spec is the new spec to apply to the Secret + // Only some fields are allowed to be updated. + SecretSpec spec = 3; +} + +message UpdateSecretResponse { + Secret secret = 1; +} + + // ListSecretRequest is the request to list all non-internal secrets in the secret store, // or all secrets filtered by (name or name prefix or id prefix) and labels. message ListSecretsRequest { diff --git a/vendor/src/github.com/docker/swarmkit/api/gen.go b/vendor/src/github.com/docker/swarmkit/api/gen.go index d0fb1ede1d9c1..9f90c7e7b517a 100644 --- a/vendor/src/github.com/docker/swarmkit/api/gen.go +++ b/vendor/src/github.com/docker/swarmkit/api/gen.go @@ -1,3 +1,3 @@ package api -//go:generate protoc -I.:../protobuf:../vendor:../vendor/github.com/gogo/protobuf --gogoswarm_out=plugins=grpc+deepcopy+raftproxy+authenticatedwrapper,import_path=github.com/docker/swarmkit/api,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto,Mtimestamp/timestamp.proto=github.com/docker/swarmkit/api/timestamp,Mduration/duration.proto=github.com/docker/swarmkit/api/duration,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor,Mplugin/plugin.proto=github.com/docker/swarmkit/protobuf/plugin:. types.proto specs.proto objects.proto control.proto dispatcher.proto ca.proto snapshot.proto raft.proto health.proto resource.proto +//go:generate protoc -I.:../protobuf:../vendor:../vendor/github.com/gogo/protobuf:../vendor/github.com/gogo/protobuf/protobuf --gogoswarm_out=plugins=grpc+deepcopy+raftproxy+authenticatedwrapper,import_path=github.com/docker/swarmkit/api,Mgogoproto/gogo.proto=github.com/gogo/protobuf/gogoproto,Mtimestamp/timestamp.proto=github.com/docker/swarmkit/api/timestamp,Mduration/duration.proto=github.com/docker/swarmkit/api/duration,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor,Mplugin/plugin.proto=github.com/docker/swarmkit/protobuf/plugin:. types.proto specs.proto objects.proto control.proto dispatcher.proto ca.proto snapshot.proto raft.proto health.proto resource.proto diff --git a/vendor/src/github.com/docker/swarmkit/api/naming/naming.go b/vendor/src/github.com/docker/swarmkit/api/naming/naming.go new file mode 100644 index 0000000000000..76515fc90f1e2 --- /dev/null +++ b/vendor/src/github.com/docker/swarmkit/api/naming/naming.go @@ -0,0 +1,29 @@ +// Package naming centralizes the naming of SwarmKit objects. +package naming + +import ( + "fmt" + + "github.com/docker/swarmkit/api" +) + +// Task returns the task name from Annotations.Name, +// and, in case Annotations.Name is missing, fallback +// to construct the name from othere information. +func Task(t *api.Task) string { + if t.Annotations.Name != "" { + // if set, use the container Annotations.Name field, set in the orchestrator. + return t.Annotations.Name + } + + slot := fmt.Sprint(t.Slot) + if slot == "" || t.Slot == 0 { + // when no slot id is assigned, we assume that this is node-bound task. + slot = t.NodeID + } + + // fallback to service.instance.id. + return fmt.Sprintf("%s.%s.%s", t.ServiceAnnotations.Name, slot, t.ID) +} + +// TODO(stevvooe): Consolidate "Hostname" style validation here. diff --git a/vendor/src/github.com/docker/swarmkit/api/objects.pb.go b/vendor/src/github.com/docker/swarmkit/api/objects.pb.go index 70d87b43ce590..fc54f1b74b75a 100644 --- a/vendor/src/github.com/docker/swarmkit/api/objects.pb.go +++ b/vendor/src/github.com/docker/swarmkit/api/objects.pb.go @@ -15,6 +15,7 @@ import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" import sort "sort" import strconv "strconv" import reflect "reflect" +import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" import io "io" @@ -227,9 +228,10 @@ type Cluster struct { // and agents to unambiguously identify the older key to be deleted when // a new key is allocated on key rotation. EncryptionKeyLamportClock uint64 `protobuf:"varint,6,opt,name=encryption_key_lamport_clock,json=encryptionKeyLamportClock,proto3" json:"encryption_key_lamport_clock,omitempty"` - // RemovedNodes is the list of nodes that have been removed from the + // BlacklistedCertificates tracks certificates that should no longer + // be honored. It's a mapping from CN -> BlacklistedCertificate. // swarm. Their certificates should effectively be blacklisted. - RemovedNodes []*RemovedNode `protobuf:"bytes,7,rep,name=removed_nodes,json=removedNodes" json:"removed_nodes,omitempty"` + BlacklistedCertificates map[string]*BlacklistedCertificate `protobuf:"bytes,8,rep,name=blacklisted_certificates,json=blacklistedCertificates" json:"blacklisted_certificates,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value"` } func (m *Cluster) Reset() { *m = Cluster{} } @@ -451,10 +453,10 @@ func (m *Cluster) Copy() *Cluster { } } - if m.RemovedNodes != nil { - o.RemovedNodes = make([]*RemovedNode, 0, len(m.RemovedNodes)) - for _, v := range m.RemovedNodes { - o.RemovedNodes = append(o.RemovedNodes, v.Copy()) + if m.BlacklistedCertificates != nil { + o.BlacklistedCertificates = make(map[string]*BlacklistedCertificate) + for k, v := range m.BlacklistedCertificates { + o.BlacklistedCertificates[k] = v.Copy() } } @@ -641,8 +643,18 @@ func (this *Cluster) GoString() string { s = append(s, "NetworkBootstrapKeys: "+fmt.Sprintf("%#v", this.NetworkBootstrapKeys)+",\n") } s = append(s, "EncryptionKeyLamportClock: "+fmt.Sprintf("%#v", this.EncryptionKeyLamportClock)+",\n") - if this.RemovedNodes != nil { - s = append(s, "RemovedNodes: "+fmt.Sprintf("%#v", this.RemovedNodes)+",\n") + keysForBlacklistedCertificates := make([]string, 0, len(this.BlacklistedCertificates)) + for k, _ := range this.BlacklistedCertificates { + keysForBlacklistedCertificates = append(keysForBlacklistedCertificates, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForBlacklistedCertificates) + mapStringForBlacklistedCertificates := "map[string]*BlacklistedCertificate{" + for _, k := range keysForBlacklistedCertificates { + mapStringForBlacklistedCertificates += fmt.Sprintf("%#v: %#v,", k, this.BlacklistedCertificates[k]) + } + mapStringForBlacklistedCertificates += "}" + if this.BlacklistedCertificates != nil { + s = append(s, "BlacklistedCertificates: "+mapStringForBlacklistedCertificates+",\n") } s = append(s, "}") return strings.Join(s, "") @@ -1270,16 +1282,32 @@ func (m *Cluster) MarshalTo(data []byte) (int, error) { i++ i = encodeVarintObjects(data, i, uint64(m.EncryptionKeyLamportClock)) } - if len(m.RemovedNodes) > 0 { - for _, msg := range m.RemovedNodes { - data[i] = 0x3a + if len(m.BlacklistedCertificates) > 0 { + for k, _ := range m.BlacklistedCertificates { + data[i] = 0x42 i++ - i = encodeVarintObjects(data, i, uint64(msg.Size())) - n, err := msg.MarshalTo(data[i:]) - if err != nil { - return 0, err + v := m.BlacklistedCertificates[k] + msgSize := 0 + if v != nil { + msgSize = v.Size() + msgSize += 1 + sovObjects(uint64(msgSize)) + } + mapSize := 1 + len(k) + sovObjects(uint64(len(k))) + msgSize + i = encodeVarintObjects(data, i, uint64(mapSize)) + data[i] = 0xa + i++ + i = encodeVarintObjects(data, i, uint64(len(k))) + i += copy(data[i:], k) + if v != nil { + data[i] = 0x12 + i++ + i = encodeVarintObjects(data, i, uint64(v.Size())) + n32, err := v.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n32 } - i += n } } return i, nil @@ -1309,19 +1337,19 @@ func (m *Secret) MarshalTo(data []byte) (int, error) { data[i] = 0x12 i++ i = encodeVarintObjects(data, i, uint64(m.Meta.Size())) - n32, err := m.Meta.MarshalTo(data[i:]) + n33, err := m.Meta.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n32 + i += n33 data[i] = 0x1a i++ i = encodeVarintObjects(data, i, uint64(m.Spec.Size())) - n33, err := m.Spec.MarshalTo(data[i:]) + n34, err := m.Spec.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n33 + i += n34 if len(m.Digest) > 0 { data[i] = 0x22 i++ @@ -1596,10 +1624,17 @@ func (m *Cluster) Size() (n int) { if m.EncryptionKeyLamportClock != 0 { n += 1 + sovObjects(uint64(m.EncryptionKeyLamportClock)) } - if len(m.RemovedNodes) > 0 { - for _, e := range m.RemovedNodes { - l = e.Size() - n += 1 + l + sovObjects(uint64(l)) + if len(m.BlacklistedCertificates) > 0 { + for k, v := range m.BlacklistedCertificates { + _ = k + _ = v + l = 0 + if v != nil { + l = v.Size() + l += 1 + sovObjects(uint64(l)) + } + mapEntrySize := 1 + len(k) + sovObjects(uint64(len(k))) + l + n += mapEntrySize + 1 + sovObjects(uint64(mapEntrySize)) } } return n @@ -1761,6 +1796,16 @@ func (this *Cluster) String() string { if this == nil { return "nil" } + keysForBlacklistedCertificates := make([]string, 0, len(this.BlacklistedCertificates)) + for k, _ := range this.BlacklistedCertificates { + keysForBlacklistedCertificates = append(keysForBlacklistedCertificates, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForBlacklistedCertificates) + mapStringForBlacklistedCertificates := "map[string]*BlacklistedCertificate{" + for _, k := range keysForBlacklistedCertificates { + mapStringForBlacklistedCertificates += fmt.Sprintf("%v: %v,", k, this.BlacklistedCertificates[k]) + } + mapStringForBlacklistedCertificates += "}" s := strings.Join([]string{`&Cluster{`, `ID:` + fmt.Sprintf("%v", this.ID) + `,`, `Meta:` + strings.Replace(strings.Replace(this.Meta.String(), "Meta", "Meta", 1), `&`, ``, 1) + `,`, @@ -1768,7 +1813,7 @@ func (this *Cluster) String() string { `RootCA:` + strings.Replace(strings.Replace(this.RootCA.String(), "RootCA", "RootCA", 1), `&`, ``, 1) + `,`, `NetworkBootstrapKeys:` + strings.Replace(fmt.Sprintf("%v", this.NetworkBootstrapKeys), "EncryptionKey", "EncryptionKey", 1) + `,`, `EncryptionKeyLamportClock:` + fmt.Sprintf("%v", this.EncryptionKeyLamportClock) + `,`, - `RemovedNodes:` + strings.Replace(fmt.Sprintf("%v", this.RemovedNodes), "RemovedNode", "RemovedNode", 1) + `,`, + `BlacklistedCertificates:` + mapStringForBlacklistedCertificates + `,`, `}`, }, "") return s @@ -3697,9 +3742,9 @@ func (m *Cluster) Unmarshal(data []byte) error { break } } - case 7: + case 8: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RemovedNodes", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field BlacklistedCertificates", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -3723,9 +3768,99 @@ func (m *Cluster) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RemovedNodes = append(m.RemovedNodes, &RemovedNode{}) - if err := m.RemovedNodes[len(m.RemovedNodes)-1].Unmarshal(data[iNdEx:postIndex]); err != nil { - return err + var keykey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowObjects + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + keykey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowObjects + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLenmapkey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthObjects + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey := string(data[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + if m.BlacklistedCertificates == nil { + m.BlacklistedCertificates = make(map[string]*BlacklistedCertificate) + } + if iNdEx < postIndex { + var valuekey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowObjects + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + valuekey |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + var mapmsglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowObjects + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + mapmsglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if mapmsglen < 0 { + return ErrInvalidLengthObjects + } + postmsgIndex := iNdEx + mapmsglen + if mapmsglen < 0 { + return ErrInvalidLengthObjects + } + if postmsgIndex > l { + return io.ErrUnexpectedEOF + } + mapvalue := &BlacklistedCertificate{} + if err := mapvalue.Unmarshal(data[iNdEx:postmsgIndex]); err != nil { + return err + } + iNdEx = postmsgIndex + m.BlacklistedCertificates[mapkey] = mapvalue + } else { + var mapvalue *BlacklistedCertificate + m.BlacklistedCertificates[mapkey] = mapvalue } iNdEx = postIndex default: @@ -4064,76 +4199,79 @@ var ( func init() { proto.RegisterFile("objects.proto", fileDescriptorObjects) } var fileDescriptorObjects = []byte{ - // 1126 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x57, 0x4d, 0x6f, 0x1b, 0xc5, - 0x1b, 0xef, 0xda, 0x5b, 0xbf, 0x3c, 0xb6, 0x23, 0xfd, 0xe7, 0x5f, 0x45, 0xdb, 0x10, 0xec, 0xe0, - 0x0a, 0xd4, 0x43, 0xe5, 0x8a, 0x52, 0x50, 0x2b, 0x5a, 0x21, 0xbf, 0x44, 0x60, 0x95, 0x40, 0x34, - 0x29, 0xe9, 0x71, 0x35, 0xd9, 0x9d, 0x9a, 0xc5, 0xf6, 0xce, 0x6a, 0x66, 0xec, 0x2a, 0x3d, 0x21, - 0x3e, 0x00, 0x1f, 0x81, 0x6f, 0xc1, 0x99, 0x6b, 0x0e, 0x1c, 0xb8, 0xc1, 0xc9, 0x22, 0x3e, 0x20, - 0x71, 0xe3, 0x23, 0xa0, 0x79, 0x59, 0xdb, 0x91, 0xd7, 0x21, 0x95, 0xaa, 0xdc, 0xe6, 0xf1, 0xfc, - 0x7e, 0xbf, 0x79, 0xde, 0xe6, 0x99, 0x35, 0xd4, 0xd8, 0xc9, 0x77, 0x34, 0x90, 0xa2, 0x95, 0x70, - 0x26, 0x19, 0x42, 0x21, 0x0b, 0x86, 0x94, 0xb7, 0xc4, 0x2b, 0xc2, 0xc7, 0xc3, 0x48, 0xb6, 0xa6, - 0x1f, 0xee, 0x54, 0xe4, 0x69, 0x42, 0x2d, 0x60, 0xa7, 0x22, 0x12, 0x1a, 0xa4, 0xc6, 0x6d, 0x19, - 0x8d, 0xa9, 0x90, 0x64, 0x9c, 0xdc, 0x5f, 0xac, 0xec, 0xd6, 0xad, 0x01, 0x1b, 0x30, 0xbd, 0xbc, - 0xaf, 0x56, 0xe6, 0xd7, 0xe6, 0x2f, 0x0e, 0xb8, 0x07, 0x54, 0x12, 0xf4, 0x29, 0x14, 0xa7, 0x94, - 0x8b, 0x88, 0xc5, 0x9e, 0xb3, 0xe7, 0xdc, 0xad, 0x3c, 0x78, 0xa7, 0xb5, 0x7e, 0x72, 0xeb, 0xd8, - 0x40, 0x3a, 0xee, 0xd9, 0xac, 0x71, 0x03, 0xa7, 0x0c, 0xf4, 0x04, 0x20, 0xe0, 0x94, 0x48, 0x1a, - 0xfa, 0x44, 0x7a, 0x39, 0xcd, 0x7f, 0x37, 0x8b, 0xff, 0x3c, 0x75, 0x0a, 0x97, 0x2d, 0xa1, 0x2d, - 0x15, 0x7b, 0x92, 0x84, 0x29, 0x3b, 0x7f, 0x25, 0xb6, 0x25, 0xb4, 0x65, 0xf3, 0xef, 0x3c, 0xb8, - 0x5f, 0xb1, 0x90, 0xa2, 0x6d, 0xc8, 0x45, 0xa1, 0x76, 0xbe, 0xdc, 0x29, 0xcc, 0x67, 0x8d, 0x5c, - 0xbf, 0x87, 0x73, 0x51, 0x88, 0x1e, 0x80, 0x3b, 0xa6, 0x92, 0x58, 0xb7, 0xbc, 0x2c, 0x61, 0x95, - 0x01, 0x1b, 0x93, 0xc6, 0xa2, 0x4f, 0xc0, 0x55, 0x69, 0xb5, 0xce, 0xec, 0x66, 0x71, 0xd4, 0x99, - 0x47, 0x09, 0x0d, 0x52, 0x9e, 0xc2, 0xa3, 0x7d, 0xa8, 0x84, 0x54, 0x04, 0x3c, 0x4a, 0xa4, 0xca, - 0xa4, 0xab, 0xe9, 0x77, 0x36, 0xd1, 0x7b, 0x4b, 0x28, 0x5e, 0xe5, 0xa1, 0x27, 0x50, 0x10, 0x92, - 0xc8, 0x89, 0xf0, 0x6e, 0x6a, 0x85, 0xfa, 0x46, 0x07, 0x34, 0xca, 0xba, 0x60, 0x39, 0xe8, 0x0b, - 0xd8, 0x1a, 0x93, 0x98, 0x0c, 0x28, 0xf7, 0xad, 0x4a, 0x41, 0xab, 0xbc, 0x97, 0x19, 0xba, 0x41, - 0x1a, 0x21, 0x5c, 0x1b, 0xaf, 0x9a, 0x68, 0x1f, 0x80, 0x48, 0x49, 0x82, 0x6f, 0xc7, 0x34, 0x96, - 0x5e, 0x51, 0xab, 0xbc, 0x9f, 0xe9, 0x0b, 0x95, 0xaf, 0x18, 0x1f, 0xb6, 0x17, 0x60, 0xbc, 0x42, - 0x44, 0x9f, 0x43, 0x25, 0xa0, 0x5c, 0x46, 0x2f, 0xa3, 0x80, 0x48, 0xea, 0x95, 0xb4, 0x4e, 0x23, - 0x4b, 0xa7, 0xbb, 0x84, 0xd9, 0xa0, 0x56, 0x99, 0xcd, 0xdf, 0x73, 0x50, 0x3c, 0xa2, 0x7c, 0x1a, - 0x05, 0x6f, 0xb7, 0xdc, 0x8f, 0x2f, 0x94, 0x3b, 0xd3, 0x33, 0x7b, 0xec, 0x5a, 0xc5, 0x1f, 0x41, - 0x89, 0xc6, 0x61, 0xc2, 0xa2, 0x58, 0xda, 0x72, 0x67, 0x76, 0xcb, 0xbe, 0xc5, 0xe0, 0x05, 0x1a, - 0xed, 0x43, 0xcd, 0x74, 0xb1, 0x7f, 0xa1, 0xd6, 0x7b, 0x59, 0xf4, 0x6f, 0x34, 0xd0, 0x16, 0xa9, - 0x3a, 0x59, 0xb1, 0x50, 0x0f, 0x6a, 0x09, 0xa7, 0xd3, 0x88, 0x4d, 0x84, 0xaf, 0x83, 0x28, 0x5c, - 0x29, 0x08, 0x5c, 0x4d, 0x59, 0xca, 0x6a, 0xfe, 0x94, 0x83, 0x52, 0xea, 0x23, 0x7a, 0x68, 0xd3, - 0xe1, 0x6c, 0x76, 0x28, 0xc5, 0x6a, 0x29, 0x93, 0x89, 0x87, 0x70, 0x33, 0x61, 0x5c, 0x0a, 0x2f, - 0xb7, 0x97, 0xdf, 0xd4, 0xb3, 0x87, 0x8c, 0xcb, 0x2e, 0x8b, 0x5f, 0x46, 0x03, 0x6c, 0xc0, 0xe8, - 0x05, 0x54, 0xa6, 0x11, 0x97, 0x13, 0x32, 0xf2, 0xa3, 0x44, 0x78, 0x79, 0xcd, 0xfd, 0xe0, 0xb2, - 0x23, 0x5b, 0xc7, 0x06, 0xdf, 0x3f, 0xec, 0x6c, 0xcd, 0x67, 0x0d, 0x58, 0x98, 0x02, 0x83, 0x95, - 0xea, 0x27, 0x62, 0xe7, 0x00, 0xca, 0x8b, 0x1d, 0x74, 0x0f, 0x20, 0x36, 0x2d, 0xea, 0x2f, 0x9a, - 0xa6, 0x36, 0x9f, 0x35, 0xca, 0xb6, 0x71, 0xfb, 0x3d, 0x5c, 0xb6, 0x80, 0x7e, 0x88, 0x10, 0xb8, - 0x24, 0x0c, 0xb9, 0x6e, 0xa1, 0x32, 0xd6, 0xeb, 0xe6, 0xaf, 0x37, 0xc1, 0x7d, 0x4e, 0xc4, 0xf0, - 0xba, 0xc7, 0x8c, 0x3a, 0x73, 0xad, 0xe9, 0xee, 0x01, 0x08, 0x53, 0x4a, 0x15, 0x8e, 0xbb, 0x0c, - 0xc7, 0x16, 0x58, 0x85, 0x63, 0x01, 0x26, 0x1c, 0x31, 0x62, 0x52, 0xf7, 0x97, 0x8b, 0xf5, 0x1a, - 0xdd, 0x81, 0x62, 0xcc, 0x42, 0x4d, 0x2f, 0x68, 0x3a, 0xcc, 0x67, 0x8d, 0x82, 0x1a, 0x29, 0xfd, - 0x1e, 0x2e, 0xa8, 0xad, 0x7e, 0xa8, 0xee, 0x2d, 0x89, 0x63, 0x26, 0x89, 0x1a, 0x4a, 0xc2, 0xde, - 0xff, 0xcc, 0xc6, 0x6a, 0x2f, 0x61, 0xe9, 0xbd, 0x5d, 0x61, 0xa2, 0x63, 0xf8, 0x7f, 0xea, 0xef, - 0xaa, 0x60, 0xe9, 0x4d, 0x04, 0x91, 0x55, 0x58, 0xd9, 0x59, 0x99, 0x93, 0xe5, 0xcd, 0x73, 0x52, - 0x67, 0x30, 0x6b, 0x4e, 0x76, 0xa0, 0x16, 0x52, 0x11, 0x71, 0x1a, 0xea, 0x1b, 0x48, 0x3d, 0xd8, - 0x73, 0xee, 0x6e, 0x6d, 0x78, 0x7a, 0xac, 0x08, 0xc5, 0x55, 0xcb, 0xd1, 0x16, 0x6a, 0x43, 0xc9, - 0xf6, 0x8d, 0xf0, 0x2a, 0xba, 0x77, 0xaf, 0x38, 0x1f, 0x17, 0xb4, 0x0b, 0x13, 0xa4, 0xfa, 0x46, - 0x13, 0xe4, 0x31, 0xc0, 0x88, 0x0d, 0xfc, 0x90, 0x47, 0x53, 0xca, 0xbd, 0x9a, 0xe6, 0xee, 0x64, - 0x71, 0x7b, 0x1a, 0x81, 0xcb, 0x23, 0x36, 0x30, 0xcb, 0xe6, 0x0f, 0x0e, 0xfc, 0x6f, 0xcd, 0x29, - 0xf4, 0x31, 0x14, 0xad, 0x5b, 0x97, 0x7d, 0x04, 0x58, 0x1e, 0x4e, 0xb1, 0x68, 0x17, 0xca, 0xea, - 0x8e, 0x50, 0x21, 0xa8, 0xb9, 0xfd, 0x65, 0xbc, 0xfc, 0x01, 0x79, 0x50, 0x24, 0xa3, 0x88, 0xa8, - 0xbd, 0xbc, 0xde, 0x4b, 0xcd, 0xe6, 0x8f, 0x39, 0x28, 0x5a, 0xb1, 0xeb, 0x1e, 0xe7, 0xf6, 0xd8, - 0xb5, 0x9b, 0xf5, 0x14, 0xaa, 0x26, 0x9d, 0xb6, 0x25, 0xdc, 0xff, 0x4c, 0x6a, 0xc5, 0xe0, 0x4d, - 0x3b, 0x3c, 0x05, 0x37, 0x4a, 0xc8, 0xd8, 0x8e, 0xf2, 0xcc, 0x93, 0xfb, 0x87, 0xed, 0x83, 0xaf, - 0x13, 0xd3, 0xd9, 0xa5, 0xf9, 0xac, 0xe1, 0xaa, 0x1f, 0xb0, 0xa6, 0x35, 0x7f, 0xce, 0x43, 0xb1, - 0x3b, 0x9a, 0x08, 0x49, 0xf9, 0x75, 0x27, 0xc4, 0x1e, 0xbb, 0x96, 0x90, 0x2e, 0x14, 0x39, 0x63, - 0xd2, 0x0f, 0xc8, 0x65, 0xb9, 0xc0, 0x8c, 0xc9, 0x6e, 0xbb, 0xb3, 0xa5, 0x88, 0x6a, 0x90, 0x18, - 0x1b, 0x17, 0x14, 0xb5, 0x4b, 0xd0, 0x0b, 0xd8, 0x4e, 0xc7, 0xef, 0x09, 0x63, 0x52, 0x48, 0x4e, - 0x12, 0x7f, 0x48, 0x4f, 0xd5, 0x9b, 0x97, 0xdf, 0xf4, 0x65, 0xb2, 0x1f, 0x07, 0xfc, 0x54, 0x27, - 0xea, 0x19, 0x3d, 0xc5, 0xb7, 0xac, 0x40, 0x27, 0xe5, 0x3f, 0xa3, 0xa7, 0x02, 0x7d, 0x06, 0xbb, - 0x74, 0x01, 0x53, 0x8a, 0xfe, 0x88, 0x8c, 0xd5, 0xc3, 0xe2, 0x07, 0x23, 0x16, 0x0c, 0xf5, 0x6c, - 0x73, 0xf1, 0x6d, 0xba, 0x2a, 0xf5, 0xa5, 0x41, 0x74, 0x15, 0x40, 0xbd, 0x9e, 0x9c, 0x8e, 0xd9, - 0x94, 0x86, 0xbe, 0x1a, 0x7a, 0x6a, 0xc8, 0xe5, 0x37, 0xa5, 0x08, 0x1b, 0xa0, 0x1a, 0x92, 0xb8, - 0xca, 0x97, 0x86, 0x68, 0xfe, 0xe5, 0x40, 0xe1, 0x88, 0x06, 0x9c, 0xca, 0xb7, 0x5a, 0xb6, 0x47, - 0x17, 0xca, 0x56, 0xcf, 0x7e, 0xd1, 0xd5, 0xa9, 0x6b, 0x55, 0xdb, 0x86, 0x42, 0x18, 0x0d, 0xa8, - 0x30, 0xdf, 0x24, 0x65, 0x6c, 0x2d, 0xd4, 0x04, 0x57, 0x44, 0xaf, 0xa9, 0xee, 0xcf, 0xbc, 0x79, - 0x3e, 0xad, 0x42, 0xf4, 0x9a, 0x62, 0xbd, 0x87, 0x76, 0xa0, 0x14, 0xc5, 0x92, 0xf2, 0x98, 0x8c, - 0x74, 0xfe, 0x4a, 0x78, 0x61, 0x77, 0x76, 0xcf, 0xce, 0xeb, 0x37, 0xfe, 0x38, 0xaf, 0xdf, 0xf8, - 0xe7, 0xbc, 0xee, 0x7c, 0x3f, 0xaf, 0x3b, 0x67, 0xf3, 0xba, 0xf3, 0xdb, 0xbc, 0xee, 0xfc, 0x39, - 0xaf, 0x3b, 0x27, 0x05, 0xfd, 0x9f, 0xe2, 0xa3, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xf7, 0x71, - 0xe0, 0xa4, 0xc3, 0x0c, 0x00, 0x00, + // 1174 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x57, 0x4d, 0x8f, 0x1b, 0x35, + 0x18, 0xee, 0x24, 0xb3, 0xf9, 0x78, 0xb3, 0x59, 0x81, 0xa9, 0xca, 0x34, 0x2c, 0xc9, 0x92, 0x0a, + 0x54, 0xa1, 0x2a, 0x15, 0xa5, 0xa0, 0x2d, 0xb4, 0x82, 0x7c, 0x09, 0xa2, 0x52, 0xa8, 0xdc, 0xd2, + 0x1e, 0x23, 0xef, 0x8c, 0x1b, 0x86, 0x4c, 0xc6, 0x23, 0xdb, 0x49, 0x95, 0x9e, 0x10, 0x3f, 0x80, + 0x9f, 0xc0, 0x5f, 0xe1, 0xba, 0x07, 0x0e, 0xdc, 0xe0, 0x80, 0x22, 0x36, 0x07, 0x24, 0x6e, 0xfc, + 0x04, 0x64, 0x8f, 0x27, 0x99, 0x55, 0x26, 0xcb, 0x56, 0xaa, 0xf6, 0xe6, 0x37, 0x7e, 0x9e, 0xc7, + 0xef, 0x97, 0xdf, 0x71, 0xa0, 0xca, 0x8e, 0xbe, 0xa7, 0xae, 0x14, 0xad, 0x88, 0x33, 0xc9, 0x10, + 0xf2, 0x98, 0x3b, 0xa6, 0xbc, 0x25, 0x9e, 0x13, 0x3e, 0x19, 0xfb, 0xb2, 0x35, 0xfb, 0xa0, 0x56, + 0x91, 0xf3, 0x88, 0x1a, 0x40, 0xad, 0x22, 0x22, 0xea, 0x26, 0xc6, 0x55, 0xe9, 0x4f, 0xa8, 0x90, + 0x64, 0x12, 0xdd, 0x5c, 0xad, 0xcc, 0xd6, 0xe5, 0x11, 0x1b, 0x31, 0xbd, 0xbc, 0xa9, 0x56, 0xf1, + 0xaf, 0xcd, 0x5f, 0x2c, 0xb0, 0x1f, 0x50, 0x49, 0xd0, 0xa7, 0x50, 0x9c, 0x51, 0x2e, 0x7c, 0x16, + 0x3a, 0xd6, 0x81, 0x75, 0xbd, 0x72, 0xeb, 0xad, 0xd6, 0xe6, 0xc9, 0xad, 0x27, 0x31, 0xa4, 0x63, + 0x1f, 0x2f, 0x1a, 0x97, 0x70, 0xc2, 0x40, 0x77, 0x01, 0x5c, 0x4e, 0x89, 0xa4, 0xde, 0x90, 0x48, + 0x27, 0xa7, 0xf9, 0x6f, 0x67, 0xf1, 0x1f, 0x27, 0x4e, 0xe1, 0xb2, 0x21, 0xb4, 0xa5, 0x62, 0x4f, + 0x23, 0x2f, 0x61, 0xe7, 0xcf, 0xc5, 0x36, 0x84, 0xb6, 0x6c, 0xfe, 0x93, 0x07, 0xfb, 0x6b, 0xe6, + 0x51, 0x74, 0x05, 0x72, 0xbe, 0xa7, 0x9d, 0x2f, 0x77, 0x0a, 0xcb, 0x45, 0x23, 0x37, 0xe8, 0xe1, + 0x9c, 0xef, 0xa1, 0x5b, 0x60, 0x4f, 0xa8, 0x24, 0xc6, 0x2d, 0x27, 0x4b, 0x58, 0x65, 0xc0, 0xc4, + 0xa4, 0xb1, 0xe8, 0x63, 0xb0, 0x55, 0x5a, 0x8d, 0x33, 0xfb, 0x59, 0x1c, 0x75, 0xe6, 0xa3, 0x88, + 0xba, 0x09, 0x4f, 0xe1, 0x51, 0x1f, 0x2a, 0x1e, 0x15, 0x2e, 0xf7, 0x23, 0xa9, 0x32, 0x69, 0x6b, + 0xfa, 0xb5, 0x6d, 0xf4, 0xde, 0x1a, 0x8a, 0xd3, 0x3c, 0x74, 0x17, 0x0a, 0x42, 0x12, 0x39, 0x15, + 0xce, 0x8e, 0x56, 0xa8, 0x6f, 0x75, 0x40, 0xa3, 0x8c, 0x0b, 0x86, 0x83, 0xbe, 0x84, 0xbd, 0x09, + 0x09, 0xc9, 0x88, 0xf2, 0xa1, 0x51, 0x29, 0x68, 0x95, 0x77, 0x32, 0x43, 0x8f, 0x91, 0xb1, 0x10, + 0xae, 0x4e, 0xd2, 0x26, 0xea, 0x03, 0x10, 0x29, 0x89, 0xfb, 0xdd, 0x84, 0x86, 0xd2, 0x29, 0x6a, + 0x95, 0x77, 0x33, 0x7d, 0xa1, 0xf2, 0x39, 0xe3, 0xe3, 0xf6, 0x0a, 0x8c, 0x53, 0x44, 0xf4, 0x05, + 0x54, 0x5c, 0xca, 0xa5, 0xff, 0xcc, 0x77, 0x89, 0xa4, 0x4e, 0x49, 0xeb, 0x34, 0xb2, 0x74, 0xba, + 0x6b, 0x98, 0x09, 0x2a, 0xcd, 0x6c, 0xfe, 0x9e, 0x83, 0xe2, 0x23, 0xca, 0x67, 0xbe, 0xfb, 0x6a, + 0xcb, 0x7d, 0xe7, 0x54, 0xb9, 0x33, 0x3d, 0x33, 0xc7, 0x6e, 0x54, 0xfc, 0x10, 0x4a, 0x34, 0xf4, + 0x22, 0xe6, 0x87, 0xd2, 0x94, 0x3b, 0xb3, 0x5b, 0xfa, 0x06, 0x83, 0x57, 0x68, 0xd4, 0x87, 0x6a, + 0xdc, 0xc5, 0xc3, 0x53, 0xb5, 0x3e, 0xc8, 0xa2, 0x7f, 0xab, 0x81, 0xa6, 0x48, 0xbb, 0xd3, 0x94, + 0x85, 0x7a, 0x50, 0x8d, 0x38, 0x9d, 0xf9, 0x6c, 0x2a, 0x86, 0x3a, 0x88, 0xc2, 0xb9, 0x82, 0xc0, + 0xbb, 0x09, 0x4b, 0x59, 0xcd, 0x9f, 0x73, 0x50, 0x4a, 0x7c, 0x44, 0xb7, 0x4d, 0x3a, 0xac, 0xed, + 0x0e, 0x25, 0x58, 0x2d, 0x15, 0x67, 0xe2, 0x36, 0xec, 0x44, 0x8c, 0x4b, 0xe1, 0xe4, 0x0e, 0xf2, + 0xdb, 0x7a, 0xf6, 0x21, 0xe3, 0xb2, 0xcb, 0xc2, 0x67, 0xfe, 0x08, 0xc7, 0x60, 0xf4, 0x14, 0x2a, + 0x33, 0x9f, 0xcb, 0x29, 0x09, 0x86, 0x7e, 0x24, 0x9c, 0xbc, 0xe6, 0xbe, 0x77, 0xd6, 0x91, 0xad, + 0x27, 0x31, 0x7e, 0xf0, 0xb0, 0xb3, 0xb7, 0x5c, 0x34, 0x60, 0x65, 0x0a, 0x0c, 0x46, 0x6a, 0x10, + 0x89, 0xda, 0x03, 0x28, 0xaf, 0x76, 0xd0, 0x0d, 0x80, 0x30, 0x6e, 0xd1, 0xe1, 0xaa, 0x69, 0xaa, + 0xcb, 0x45, 0xa3, 0x6c, 0x1a, 0x77, 0xd0, 0xc3, 0x65, 0x03, 0x18, 0x78, 0x08, 0x81, 0x4d, 0x3c, + 0x8f, 0xeb, 0x16, 0x2a, 0x63, 0xbd, 0x6e, 0xfe, 0xba, 0x03, 0xf6, 0x63, 0x22, 0xc6, 0x17, 0x3d, + 0x66, 0xd4, 0x99, 0x1b, 0x4d, 0x77, 0x03, 0x40, 0xc4, 0xa5, 0x54, 0xe1, 0xd8, 0xeb, 0x70, 0x4c, + 0x81, 0x55, 0x38, 0x06, 0x10, 0x87, 0x23, 0x02, 0x26, 0x75, 0x7f, 0xd9, 0x58, 0xaf, 0xd1, 0x35, + 0x28, 0x86, 0xcc, 0xd3, 0xf4, 0x82, 0xa6, 0xc3, 0x72, 0xd1, 0x28, 0xa8, 0x91, 0x32, 0xe8, 0xe1, + 0x82, 0xda, 0x1a, 0x78, 0xea, 0xde, 0x92, 0x30, 0x64, 0x92, 0xa8, 0xa1, 0x24, 0xcc, 0xfd, 0xcf, + 0x6c, 0xac, 0xf6, 0x1a, 0x96, 0xdc, 0xdb, 0x14, 0x13, 0x3d, 0x81, 0x37, 0x12, 0x7f, 0xd3, 0x82, + 0xa5, 0x97, 0x11, 0x44, 0x46, 0x21, 0xb5, 0x93, 0x9a, 0x93, 0xe5, 0xed, 0x73, 0x52, 0x67, 0x30, + 0x6b, 0x4e, 0x76, 0xa0, 0xea, 0x51, 0xe1, 0x73, 0xea, 0xe9, 0x1b, 0x48, 0x1d, 0x38, 0xb0, 0xae, + 0xef, 0x6d, 0xf9, 0xf4, 0x18, 0x11, 0x8a, 0x77, 0x0d, 0x47, 0x5b, 0xa8, 0x0d, 0x25, 0xd3, 0x37, + 0xc2, 0xa9, 0xe8, 0xde, 0x3d, 0xe7, 0x7c, 0x5c, 0xd1, 0x4e, 0x4d, 0x90, 0xdd, 0x97, 0x9a, 0x20, + 0x77, 0x00, 0x02, 0x36, 0x1a, 0x7a, 0xdc, 0x9f, 0x51, 0xee, 0x54, 0x35, 0xb7, 0x96, 0xc5, 0xed, + 0x69, 0x04, 0x2e, 0x07, 0x6c, 0x14, 0x2f, 0x9b, 0x3f, 0x5a, 0xf0, 0xfa, 0x86, 0x53, 0xe8, 0x23, + 0x28, 0x1a, 0xb7, 0xce, 0x7a, 0x04, 0x18, 0x1e, 0x4e, 0xb0, 0x68, 0x1f, 0xca, 0xea, 0x8e, 0x50, + 0x21, 0x68, 0x7c, 0xfb, 0xcb, 0x78, 0xfd, 0x03, 0x72, 0xa0, 0x48, 0x02, 0x9f, 0xa8, 0xbd, 0xbc, + 0xde, 0x4b, 0xcc, 0xe6, 0x4f, 0x39, 0x28, 0x1a, 0xb1, 0x8b, 0x1e, 0xe7, 0xe6, 0xd8, 0x8d, 0x9b, + 0x75, 0x0f, 0x76, 0xe3, 0x74, 0x9a, 0x96, 0xb0, 0xff, 0x37, 0xa9, 0x95, 0x18, 0x1f, 0xb7, 0xc3, + 0x3d, 0xb0, 0xfd, 0x88, 0x4c, 0xcc, 0x28, 0xcf, 0x3c, 0x79, 0xf0, 0xb0, 0xfd, 0xe0, 0x9b, 0x28, + 0xee, 0xec, 0xd2, 0x72, 0xd1, 0xb0, 0xd5, 0x0f, 0x58, 0xd3, 0x9a, 0x7f, 0xda, 0x50, 0xec, 0x06, + 0x53, 0x21, 0x29, 0xbf, 0xe8, 0x84, 0x98, 0x63, 0x37, 0x12, 0xd2, 0x85, 0x22, 0x67, 0x4c, 0x0e, + 0x5d, 0x72, 0x56, 0x2e, 0x30, 0x63, 0xb2, 0xdb, 0xee, 0xec, 0x29, 0xa2, 0x1a, 0x24, 0xb1, 0x8d, + 0x0b, 0x8a, 0xda, 0x25, 0xe8, 0x29, 0x5c, 0x49, 0xc6, 0xef, 0x11, 0x63, 0x52, 0x48, 0x4e, 0xa2, + 0xe1, 0x98, 0xce, 0xd5, 0x37, 0x2f, 0xbf, 0xed, 0x65, 0xd2, 0x0f, 0x5d, 0x3e, 0xd7, 0x89, 0xba, + 0x4f, 0xe7, 0xf8, 0xb2, 0x11, 0xe8, 0x24, 0xfc, 0xfb, 0x74, 0x2e, 0xd0, 0x67, 0xb0, 0x4f, 0x57, + 0x30, 0xa5, 0x38, 0x0c, 0xc8, 0x44, 0x7d, 0x58, 0x86, 0x6e, 0xc0, 0xdc, 0xb1, 0x9e, 0x6d, 0x36, + 0xbe, 0x4a, 0xd3, 0x52, 0x5f, 0xc5, 0x88, 0xae, 0x02, 0x20, 0x01, 0xce, 0x51, 0x40, 0xdc, 0x71, + 0xe0, 0x0b, 0xf5, 0xfe, 0x4c, 0x3d, 0x36, 0xd4, 0x78, 0x52, 0xbe, 0x1d, 0x9e, 0x91, 0xad, 0x56, + 0x67, 0xcd, 0x4d, 0x3d, 0x5d, 0x44, 0x3f, 0x94, 0x7c, 0x8e, 0xdf, 0x3c, 0xca, 0xde, 0xad, 0xcd, + 0x60, 0xff, 0x2c, 0x22, 0x7a, 0x0d, 0xf2, 0x63, 0x3a, 0x8f, 0x6b, 0x8f, 0xd5, 0x12, 0x7d, 0x0e, + 0x3b, 0x33, 0x12, 0x4c, 0xa9, 0xa9, 0xfa, 0xfb, 0x59, 0x3e, 0x65, 0x4b, 0xe2, 0x98, 0xf8, 0x49, + 0xee, 0xd0, 0x6a, 0xfe, 0x6d, 0x41, 0xe1, 0x11, 0x75, 0x39, 0x95, 0xaf, 0xb4, 0xbb, 0x0e, 0x4f, + 0x75, 0x57, 0x3d, 0xfb, 0xe1, 0xa1, 0x4e, 0xdd, 0x68, 0xae, 0x2b, 0x50, 0xf0, 0xfc, 0x11, 0x15, + 0xf1, 0xd3, 0xa9, 0x8c, 0x8d, 0x85, 0x9a, 0x60, 0x0b, 0xff, 0x05, 0xd5, 0xd7, 0x28, 0x1f, 0x7f, + 0xe5, 0x8d, 0x82, 0xff, 0x82, 0x62, 0xbd, 0x87, 0x6a, 0x50, 0xf2, 0x43, 0x49, 0x79, 0x48, 0x02, + 0x5d, 0xe6, 0x12, 0x5e, 0xd9, 0x9d, 0xfd, 0xe3, 0x93, 0xfa, 0xa5, 0x3f, 0x4e, 0xea, 0x97, 0xfe, + 0x3d, 0xa9, 0x5b, 0x3f, 0x2c, 0xeb, 0xd6, 0xf1, 0xb2, 0x6e, 0xfd, 0xb6, 0xac, 0x5b, 0x7f, 0x2d, + 0xeb, 0xd6, 0x51, 0x41, 0xff, 0xf5, 0xf9, 0xf0, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x40, 0xcf, + 0x57, 0x63, 0x6a, 0x0d, 0x00, 0x00, } diff --git a/vendor/src/github.com/docker/swarmkit/api/objects.proto b/vendor/src/github.com/docker/swarmkit/api/objects.proto index 894926f3d1f26..86421c0851d7e 100644 --- a/vendor/src/github.com/docker/swarmkit/api/objects.proto +++ b/vendor/src/github.com/docker/swarmkit/api/objects.proto @@ -226,9 +226,10 @@ message Cluster { // a new key is allocated on key rotation. uint64 encryption_key_lamport_clock = 6; - // RemovedNodes is the list of nodes that have been removed from the + // BlacklistedCertificates tracks certificates that should no longer + // be honored. It's a mapping from CN -> BlacklistedCertificate. // swarm. Their certificates should effectively be blacklisted. - repeated RemovedNode removed_nodes = 7; + map blacklisted_certificates = 8; } // Secret represents a secret that should be passed to a container or a node, diff --git a/vendor/src/github.com/docker/swarmkit/api/specs.pb.go b/vendor/src/github.com/docker/swarmkit/api/specs.pb.go index 7dbaa0c41cdc0..3e4f0185d4a84 100644 --- a/vendor/src/github.com/docker/swarmkit/api/specs.pb.go +++ b/vendor/src/github.com/docker/swarmkit/api/specs.pb.go @@ -458,6 +458,9 @@ type ContainerSpec struct { // // If Command and Args are provided, Args will be appended to Command. Args []string `protobuf:"bytes,4,rep,name=args" json:"args,omitempty"` + // Hostname specifies the hostname that will be set on containers created by docker swarm. + // All containers for a given service will have the same hostname + Hostname string `protobuf:"bytes,14,opt,name=hostname,proto3" json:"hostname,omitempty"` // Env specifies the environment variables for the container in NAME=VALUE // format. These must be compliant with [IEEE Std // 1003.1-2001](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html). @@ -472,7 +475,10 @@ type ContainerSpec struct { User string `protobuf:"bytes,7,opt,name=user,proto3" json:"user,omitempty"` // Groups specifies supplementary groups available to the user. Groups []string `protobuf:"bytes,11,rep,name=groups" json:"groups,omitempty"` - Mounts []Mount `protobuf:"bytes,8,rep,name=mounts" json:"mounts"` + // TTY declares that a TTY should be attached to the standard streams, + // including stdin if it is still open. + TTY bool `protobuf:"varint,13,opt,name=tty,proto3" json:"tty,omitempty"` + Mounts []Mount `protobuf:"bytes,8,rep,name=mounts" json:"mounts"` // StopGracePeriod the grace period for stopping the container before // forcefully killing the container. StopGracePeriod *docker_swarmkit_v11.Duration `protobuf:"bytes,9,opt,name=stop_grace_period,json=stopGracePeriod" json:"stop_grace_period,omitempty"` @@ -481,6 +487,13 @@ type ContainerSpec struct { // SecretReference contains references to zero or more secrets that // will be exposed to the container. Secrets []*SecretReference `protobuf:"bytes,12,rep,name=secrets" json:"secrets,omitempty"` + // DNSConfig allows one to specify DNS related configuration in resolv.conf + DNSConfig *ContainerSpec_DNSConfig `protobuf:"bytes,15,opt,name=dns_config,json=dnsConfig" json:"dns_config,omitempty"` + // Healthcheck describes how to check the container is healthy. If the + // container is considered unhealthy, it will be destroyed, its creating + // task will exit and a new task will be rescheduled elsewhere. A container + // is considered unhealthy after `Retries` number of consecutive failures. + Healthcheck *HealthConfig `protobuf:"bytes,16,opt,name=healthcheck" json:"healthcheck,omitempty"` } func (m *ContainerSpec) Reset() { *m = ContainerSpec{} } @@ -502,6 +515,23 @@ func (*ContainerSpec_PullOptions) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{6, 1} } +// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) +// Detailed documentation is available in: +// http://man7.org/linux/man-pages/man5/resolv.conf.5.html +// TODO: domain is not supported yet +type ContainerSpec_DNSConfig struct { + // Nameservers specifies the IP addresses of the name servers + Nameservers []string `protobuf:"bytes,1,rep,name=nameservers" json:"nameservers,omitempty"` + // Search specifies the search list for host-name lookup + Search []string `protobuf:"bytes,2,rep,name=search" json:"search,omitempty"` + // Options allows certain internal resolver variables to be modified + Options []string `protobuf:"bytes,3,rep,name=options" json:"options,omitempty"` +} + +func (m *ContainerSpec_DNSConfig) Reset() { *m = ContainerSpec_DNSConfig{} } +func (*ContainerSpec_DNSConfig) ProtoMessage() {} +func (*ContainerSpec_DNSConfig) Descriptor() ([]byte, []int) { return fileDescriptorSpecs, []int{6, 2} } + // EndpointSpec defines the properties that can be configured to // access and loadbalance the service. type EndpointSpec struct { @@ -583,6 +613,7 @@ func init() { proto.RegisterType((*NetworkAttachmentSpec)(nil), "docker.swarmkit.v1.NetworkAttachmentSpec") proto.RegisterType((*ContainerSpec)(nil), "docker.swarmkit.v1.ContainerSpec") proto.RegisterType((*ContainerSpec_PullOptions)(nil), "docker.swarmkit.v1.ContainerSpec.PullOptions") + proto.RegisterType((*ContainerSpec_DNSConfig)(nil), "docker.swarmkit.v1.ContainerSpec.DNSConfig") proto.RegisterType((*EndpointSpec)(nil), "docker.swarmkit.v1.EndpointSpec") proto.RegisterType((*NetworkSpec)(nil), "docker.swarmkit.v1.NetworkSpec") proto.RegisterType((*ClusterSpec)(nil), "docker.swarmkit.v1.ClusterSpec") @@ -723,10 +754,14 @@ func (m *ContainerSpec) Copy() *ContainerSpec { o := &ContainerSpec{ Image: m.Image, + Hostname: m.Hostname, Dir: m.Dir, User: m.User, + TTY: m.TTY, StopGracePeriod: m.StopGracePeriod.Copy(), PullOptions: m.PullOptions.Copy(), + DNSConfig: m.DNSConfig.Copy(), + Healthcheck: m.Healthcheck.Copy(), } if m.Labels != nil { @@ -785,6 +820,31 @@ func (m *ContainerSpec_PullOptions) Copy() *ContainerSpec_PullOptions { return o } +func (m *ContainerSpec_DNSConfig) Copy() *ContainerSpec_DNSConfig { + if m == nil { + return nil + } + + o := &ContainerSpec_DNSConfig{} + + if m.Nameservers != nil { + o.Nameservers = make([]string, 0, len(m.Nameservers)) + o.Nameservers = append(o.Nameservers, m.Nameservers...) + } + + if m.Search != nil { + o.Search = make([]string, 0, len(m.Search)) + o.Search = append(o.Search, m.Search...) + } + + if m.Options != nil { + o.Options = make([]string, 0, len(m.Options)) + o.Options = append(o.Options, m.Options...) + } + + return o +} + func (m *EndpointSpec) Copy() *EndpointSpec { if m == nil { return nil @@ -981,7 +1041,7 @@ func (this *ContainerSpec) GoString() string { if this == nil { return "nil" } - s := make([]string, 0, 16) + s := make([]string, 0, 20) s = append(s, "&api.ContainerSpec{") s = append(s, "Image: "+fmt.Sprintf("%#v", this.Image)+",\n") keysForLabels := make([]string, 0, len(this.Labels)) @@ -999,10 +1059,12 @@ func (this *ContainerSpec) GoString() string { } s = append(s, "Command: "+fmt.Sprintf("%#v", this.Command)+",\n") s = append(s, "Args: "+fmt.Sprintf("%#v", this.Args)+",\n") + s = append(s, "Hostname: "+fmt.Sprintf("%#v", this.Hostname)+",\n") s = append(s, "Env: "+fmt.Sprintf("%#v", this.Env)+",\n") s = append(s, "Dir: "+fmt.Sprintf("%#v", this.Dir)+",\n") s = append(s, "User: "+fmt.Sprintf("%#v", this.User)+",\n") s = append(s, "Groups: "+fmt.Sprintf("%#v", this.Groups)+",\n") + s = append(s, "TTY: "+fmt.Sprintf("%#v", this.TTY)+",\n") if this.Mounts != nil { s = append(s, "Mounts: "+fmt.Sprintf("%#v", this.Mounts)+",\n") } @@ -1015,6 +1077,12 @@ func (this *ContainerSpec) GoString() string { if this.Secrets != nil { s = append(s, "Secrets: "+fmt.Sprintf("%#v", this.Secrets)+",\n") } + if this.DNSConfig != nil { + s = append(s, "DNSConfig: "+fmt.Sprintf("%#v", this.DNSConfig)+",\n") + } + if this.Healthcheck != nil { + s = append(s, "Healthcheck: "+fmt.Sprintf("%#v", this.Healthcheck)+",\n") + } s = append(s, "}") return strings.Join(s, "") } @@ -1028,6 +1096,18 @@ func (this *ContainerSpec_PullOptions) GoString() string { s = append(s, "}") return strings.Join(s, "") } +func (this *ContainerSpec_DNSConfig) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 7) + s = append(s, "&api.ContainerSpec_DNSConfig{") + s = append(s, "Nameservers: "+fmt.Sprintf("%#v", this.Nameservers)+",\n") + s = append(s, "Search: "+fmt.Sprintf("%#v", this.Search)+",\n") + s = append(s, "Options: "+fmt.Sprintf("%#v", this.Options)+",\n") + s = append(s, "}") + return strings.Join(s, "") +} func (this *EndpointSpec) GoString() string { if this == nil { return "nil" @@ -1584,6 +1664,44 @@ func (m *ContainerSpec) MarshalTo(data []byte) (int, error) { i += n } } + if m.TTY { + data[i] = 0x68 + i++ + if m.TTY { + data[i] = 1 + } else { + data[i] = 0 + } + i++ + } + if len(m.Hostname) > 0 { + data[i] = 0x72 + i++ + i = encodeVarintSpecs(data, i, uint64(len(m.Hostname))) + i += copy(data[i:], m.Hostname) + } + if m.DNSConfig != nil { + data[i] = 0x7a + i++ + i = encodeVarintSpecs(data, i, uint64(m.DNSConfig.Size())) + n18, err := m.DNSConfig.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n18 + } + if m.Healthcheck != nil { + data[i] = 0x82 + i++ + data[i] = 0x1 + i++ + i = encodeVarintSpecs(data, i, uint64(m.Healthcheck.Size())) + n19, err := m.Healthcheck.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n19 + } return i, nil } @@ -1613,6 +1731,69 @@ func (m *ContainerSpec_PullOptions) MarshalTo(data []byte) (int, error) { return i, nil } +func (m *ContainerSpec_DNSConfig) Marshal() (data []byte, err error) { + size := m.Size() + data = make([]byte, size) + n, err := m.MarshalTo(data) + if err != nil { + return nil, err + } + return data[:n], nil +} + +func (m *ContainerSpec_DNSConfig) MarshalTo(data []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Nameservers) > 0 { + for _, s := range m.Nameservers { + data[i] = 0xa + i++ + l = len(s) + for l >= 1<<7 { + data[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + data[i] = uint8(l) + i++ + i += copy(data[i:], s) + } + } + if len(m.Search) > 0 { + for _, s := range m.Search { + data[i] = 0x12 + i++ + l = len(s) + for l >= 1<<7 { + data[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + data[i] = uint8(l) + i++ + i += copy(data[i:], s) + } + } + if len(m.Options) > 0 { + for _, s := range m.Options { + data[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + data[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + data[i] = uint8(l) + i++ + i += copy(data[i:], s) + } + } + return i, nil +} + func (m *EndpointSpec) Marshal() (data []byte, err error) { size := m.Size() data = make([]byte, size) @@ -1666,20 +1847,20 @@ func (m *NetworkSpec) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintSpecs(data, i, uint64(m.Annotations.Size())) - n18, err := m.Annotations.MarshalTo(data[i:]) + n20, err := m.Annotations.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n18 + i += n20 if m.DriverConfig != nil { data[i] = 0x12 i++ i = encodeVarintSpecs(data, i, uint64(m.DriverConfig.Size())) - n19, err := m.DriverConfig.MarshalTo(data[i:]) + n21, err := m.DriverConfig.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n19 + i += n21 } if m.Ipv6Enabled { data[i] = 0x18 @@ -1705,11 +1886,11 @@ func (m *NetworkSpec) MarshalTo(data []byte) (int, error) { data[i] = 0x2a i++ i = encodeVarintSpecs(data, i, uint64(m.IPAM.Size())) - n20, err := m.IPAM.MarshalTo(data[i:]) + n22, err := m.IPAM.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n20 + i += n22 } if m.Attachable { data[i] = 0x30 @@ -1742,59 +1923,59 @@ func (m *ClusterSpec) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintSpecs(data, i, uint64(m.Annotations.Size())) - n21, err := m.Annotations.MarshalTo(data[i:]) + n23, err := m.Annotations.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n21 + i += n23 data[i] = 0x12 i++ i = encodeVarintSpecs(data, i, uint64(m.AcceptancePolicy.Size())) - n22, err := m.AcceptancePolicy.MarshalTo(data[i:]) + n24, err := m.AcceptancePolicy.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n22 + i += n24 data[i] = 0x1a i++ i = encodeVarintSpecs(data, i, uint64(m.Orchestration.Size())) - n23, err := m.Orchestration.MarshalTo(data[i:]) + n25, err := m.Orchestration.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n23 + i += n25 data[i] = 0x22 i++ i = encodeVarintSpecs(data, i, uint64(m.Raft.Size())) - n24, err := m.Raft.MarshalTo(data[i:]) + n26, err := m.Raft.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n24 + i += n26 data[i] = 0x2a i++ i = encodeVarintSpecs(data, i, uint64(m.Dispatcher.Size())) - n25, err := m.Dispatcher.MarshalTo(data[i:]) + n27, err := m.Dispatcher.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n25 + i += n27 data[i] = 0x32 i++ i = encodeVarintSpecs(data, i, uint64(m.CAConfig.Size())) - n26, err := m.CAConfig.MarshalTo(data[i:]) + n28, err := m.CAConfig.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n26 + i += n28 data[i] = 0x3a i++ i = encodeVarintSpecs(data, i, uint64(m.TaskDefaults.Size())) - n27, err := m.TaskDefaults.MarshalTo(data[i:]) + n29, err := m.TaskDefaults.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n27 + i += n29 return i, nil } @@ -1816,11 +1997,11 @@ func (m *SecretSpec) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintSpecs(data, i, uint64(m.Annotations.Size())) - n28, err := m.Annotations.MarshalTo(data[i:]) + n30, err := m.Annotations.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n28 + i += n30 if len(m.Data) > 0 { data[i] = 0x12 i++ @@ -2064,6 +2245,21 @@ func (m *ContainerSpec) Size() (n int) { n += 1 + l + sovSpecs(uint64(l)) } } + if m.TTY { + n += 2 + } + l = len(m.Hostname) + if l > 0 { + n += 1 + l + sovSpecs(uint64(l)) + } + if m.DNSConfig != nil { + l = m.DNSConfig.Size() + n += 1 + l + sovSpecs(uint64(l)) + } + if m.Healthcheck != nil { + l = m.Healthcheck.Size() + n += 2 + l + sovSpecs(uint64(l)) + } return n } @@ -2077,6 +2273,30 @@ func (m *ContainerSpec_PullOptions) Size() (n int) { return n } +func (m *ContainerSpec_DNSConfig) Size() (n int) { + var l int + _ = l + if len(m.Nameservers) > 0 { + for _, s := range m.Nameservers { + l = len(s) + n += 1 + l + sovSpecs(uint64(l)) + } + } + if len(m.Search) > 0 { + for _, s := range m.Search { + l = len(s) + n += 1 + l + sovSpecs(uint64(l)) + } + } + if len(m.Options) > 0 { + for _, s := range m.Options { + l = len(s) + n += 1 + l + sovSpecs(uint64(l)) + } + } + return n +} + func (m *EndpointSpec) Size() (n int) { var l int _ = l @@ -2302,6 +2522,10 @@ func (this *ContainerSpec) String() string { `PullOptions:` + strings.Replace(fmt.Sprintf("%v", this.PullOptions), "ContainerSpec_PullOptions", "ContainerSpec_PullOptions", 1) + `,`, `Groups:` + fmt.Sprintf("%v", this.Groups) + `,`, `Secrets:` + strings.Replace(fmt.Sprintf("%v", this.Secrets), "SecretReference", "SecretReference", 1) + `,`, + `TTY:` + fmt.Sprintf("%v", this.TTY) + `,`, + `Hostname:` + fmt.Sprintf("%v", this.Hostname) + `,`, + `DNSConfig:` + strings.Replace(fmt.Sprintf("%v", this.DNSConfig), "ContainerSpec_DNSConfig", "ContainerSpec_DNSConfig", 1) + `,`, + `Healthcheck:` + strings.Replace(fmt.Sprintf("%v", this.Healthcheck), "HealthConfig", "HealthConfig", 1) + `,`, `}`, }, "") return s @@ -2316,6 +2540,18 @@ func (this *ContainerSpec_PullOptions) String() string { }, "") return s } +func (this *ContainerSpec_DNSConfig) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ContainerSpec_DNSConfig{`, + `Nameservers:` + fmt.Sprintf("%v", this.Nameservers) + `,`, + `Search:` + fmt.Sprintf("%v", this.Search) + `,`, + `Options:` + fmt.Sprintf("%v", this.Options) + `,`, + `}`, + }, "") + return s +} func (this *EndpointSpec) String() string { if this == nil { return "nil" @@ -3755,6 +3991,121 @@ func (m *ContainerSpec) Unmarshal(data []byte) error { return err } iNdEx = postIndex + case 13: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TTY", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSpecs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.TTY = bool(v != 0) + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hostname", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSpecs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSpecs + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hostname = string(data[iNdEx:postIndex]) + iNdEx = postIndex + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DNSConfig", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSpecs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSpecs + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.DNSConfig == nil { + m.DNSConfig = &ContainerSpec_DNSConfig{} + } + if err := m.DNSConfig.Unmarshal(data[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Healthcheck", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSpecs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSpecs + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Healthcheck == nil { + m.Healthcheck = &HealthConfig{} + } + if err := m.Healthcheck.Unmarshal(data[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipSpecs(data[iNdEx:]) @@ -3855,6 +4206,143 @@ func (m *ContainerSpec_PullOptions) Unmarshal(data []byte) error { } return nil } +func (m *ContainerSpec_DNSConfig) Unmarshal(data []byte) error { + l := len(data) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSpecs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DNSConfig: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DNSConfig: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Nameservers", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSpecs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSpecs + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Nameservers = append(m.Nameservers, string(data[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Search", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSpecs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSpecs + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Search = append(m.Search, string(data[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Options", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSpecs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSpecs + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Options = append(m.Options, string(data[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSpecs(data[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthSpecs + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *EndpointSpec) Unmarshal(data []byte) error { l := len(data) iNdEx := 0 @@ -4640,97 +5128,105 @@ var ( func init() { proto.RegisterFile("specs.proto", fileDescriptorSpecs) } var fileDescriptorSpecs = []byte{ - // 1457 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x57, 0x4d, 0x6f, 0x1b, 0xb9, - 0x19, 0xd6, 0xd8, 0x63, 0x59, 0x7a, 0x47, 0x4e, 0x14, 0x22, 0x1f, 0x13, 0x25, 0x95, 0x15, 0x25, - 0x4d, 0x9d, 0x16, 0xb5, 0x5b, 0xb5, 0x48, 0x93, 0xa6, 0x41, 0xab, 0xaf, 0x3a, 0xaa, 0x6b, 0x47, - 0xa0, 0x93, 0x00, 0x3d, 0x09, 0xf4, 0x0c, 0x2d, 0x0f, 0x3c, 0x1a, 0x4e, 0x39, 0x1c, 0x05, 0xbe, - 0xed, 0x31, 0xf0, 0x61, 0xff, 0x81, 0x4f, 0x0b, 0xec, 0x3f, 0xd8, 0xff, 0x90, 0xe3, 0x1e, 0xf7, - 0x64, 0xac, 0x7d, 0x5f, 0x60, 0x81, 0xfd, 0x03, 0x0b, 0x72, 0x28, 0x69, 0xb4, 0x19, 0x27, 0x01, - 0xd6, 0x37, 0xf2, 0xe5, 0xf3, 0xbc, 0xa4, 0xde, 0xf7, 0x99, 0x87, 0x14, 0x58, 0x51, 0x48, 0x9d, - 0x68, 0x3d, 0xe4, 0x4c, 0x30, 0x84, 0x5c, 0xe6, 0x1c, 0x52, 0xbe, 0x1e, 0xbd, 0x25, 0x7c, 0x74, - 0xe8, 0x89, 0xf5, 0xf1, 0x9f, 0x2b, 0x96, 0x38, 0x0a, 0xa9, 0x06, 0x54, 0xae, 0x0f, 0xd9, 0x90, - 0xa9, 0xe1, 0x86, 0x1c, 0xe9, 0xe8, 0x2d, 0x37, 0xe6, 0x44, 0x78, 0x2c, 0xd8, 0x98, 0x0c, 0x92, - 0x85, 0xfa, 0x97, 0x26, 0x14, 0x76, 0x98, 0x4b, 0x77, 0x43, 0xea, 0xa0, 0x4d, 0xb0, 0x48, 0x10, - 0x30, 0xa1, 0x00, 0x91, 0x6d, 0xd4, 0x8c, 0x35, 0xab, 0xb1, 0xba, 0xfe, 0xe1, 0x96, 0xeb, 0xcd, - 0x19, 0xac, 0x65, 0xbe, 0x3f, 0x5d, 0xcd, 0xe1, 0x34, 0x13, 0xfd, 0x09, 0x4c, 0xce, 0x7c, 0x6a, - 0x2f, 0xd4, 0x8c, 0xb5, 0x2b, 0x8d, 0xbb, 0x59, 0x19, 0xe4, 0xa6, 0x98, 0xf9, 0x14, 0x2b, 0x24, - 0xda, 0x04, 0x18, 0xd1, 0xd1, 0x1e, 0xe5, 0xd1, 0x81, 0x17, 0xda, 0x8b, 0x8a, 0xf7, 0xbb, 0x8b, - 0x78, 0xf2, 0xb0, 0xeb, 0xdb, 0x53, 0x38, 0x4e, 0x51, 0xd1, 0x36, 0x94, 0xc8, 0x98, 0x78, 0x3e, - 0xd9, 0xf3, 0x7c, 0x4f, 0x1c, 0xd9, 0xa6, 0x4a, 0xf5, 0xe8, 0xa3, 0xa9, 0x9a, 0x29, 0x02, 0x9e, - 0xa3, 0xd7, 0x5d, 0x80, 0xd9, 0x46, 0xe8, 0x21, 0x2c, 0xf7, 0xbb, 0x3b, 0x9d, 0xde, 0xce, 0x66, - 0x39, 0x57, 0xb9, 0x7d, 0x7c, 0x52, 0xbb, 0x21, 0x73, 0xcc, 0x00, 0x7d, 0x1a, 0xb8, 0x5e, 0x30, - 0x44, 0x6b, 0x50, 0x68, 0xb6, 0xdb, 0xdd, 0xfe, 0xab, 0x6e, 0xa7, 0x6c, 0x54, 0x2a, 0xc7, 0x27, - 0xb5, 0x9b, 0xf3, 0xc0, 0xa6, 0xe3, 0xd0, 0x50, 0x50, 0xb7, 0x62, 0xbe, 0xfb, 0xaa, 0x9a, 0xab, - 0xbf, 0x33, 0xa0, 0x94, 0x3e, 0x04, 0x7a, 0x08, 0xf9, 0x66, 0xfb, 0x55, 0xef, 0x4d, 0xb7, 0x9c, - 0x9b, 0xd1, 0xd3, 0x88, 0xa6, 0x23, 0xbc, 0x31, 0x45, 0x0f, 0x60, 0xa9, 0xdf, 0x7c, 0xbd, 0xdb, - 0x2d, 0x1b, 0xb3, 0xe3, 0xa4, 0x61, 0x7d, 0x12, 0x47, 0x0a, 0xd5, 0xc1, 0xcd, 0xde, 0x4e, 0x79, - 0x21, 0x1b, 0xd5, 0xe1, 0xc4, 0x0b, 0xf4, 0x51, 0xce, 0x16, 0xc1, 0xda, 0xa5, 0x7c, 0xec, 0x39, - 0x97, 0xac, 0x89, 0xc7, 0x60, 0x0a, 0x12, 0x1d, 0x2a, 0x4d, 0x58, 0xd9, 0x9a, 0x78, 0x45, 0xa2, - 0x43, 0xb9, 0xa9, 0xa6, 0x2b, 0xbc, 0x54, 0x06, 0xa7, 0xa1, 0xef, 0x39, 0x44, 0x50, 0x57, 0x29, - 0xc3, 0x6a, 0xfc, 0x36, 0x8b, 0x8d, 0xa7, 0x28, 0x7d, 0xfe, 0x17, 0x39, 0x9c, 0xa2, 0xa2, 0x67, - 0x90, 0x1f, 0xfa, 0x6c, 0x8f, 0xf8, 0x4a, 0x13, 0x56, 0xe3, 0x5e, 0x56, 0x92, 0x4d, 0x85, 0x98, - 0x25, 0xd0, 0x14, 0xf4, 0x04, 0xf2, 0x71, 0xe8, 0x12, 0x41, 0xed, 0xbc, 0x22, 0xd7, 0xb2, 0xc8, - 0xaf, 0x15, 0xa2, 0xcd, 0x82, 0x7d, 0x6f, 0x88, 0x35, 0x1e, 0x6d, 0x41, 0x21, 0xa0, 0xe2, 0x2d, - 0xe3, 0x87, 0x91, 0xbd, 0x5c, 0x5b, 0x5c, 0xb3, 0x1a, 0x7f, 0xc8, 0x14, 0x63, 0x82, 0x69, 0x0a, - 0x41, 0x9c, 0x83, 0x11, 0x0d, 0x44, 0x92, 0xa6, 0xb5, 0x60, 0x1b, 0x78, 0x9a, 0x00, 0xfd, 0x03, - 0x0a, 0x34, 0x70, 0x43, 0xe6, 0x05, 0xc2, 0x2e, 0x5c, 0x7c, 0x90, 0xae, 0xc6, 0xc8, 0x62, 0xe2, - 0x29, 0xa3, 0x95, 0x07, 0x73, 0xc4, 0x5c, 0x5a, 0xdf, 0x80, 0x6b, 0x1f, 0x14, 0x0b, 0x55, 0xa0, - 0xa0, 0x8b, 0x95, 0x74, 0xd9, 0xc4, 0xd3, 0x79, 0xfd, 0x2a, 0xac, 0xcc, 0x15, 0x46, 0xd9, 0xc6, - 0xa4, 0x5b, 0xa8, 0x09, 0x45, 0x87, 0x05, 0x82, 0x78, 0x01, 0xe5, 0x5a, 0x20, 0x99, 0xb5, 0x6d, - 0x4f, 0x40, 0x92, 0xf5, 0x22, 0x87, 0x67, 0x2c, 0xf4, 0x6f, 0x28, 0x72, 0x1a, 0xb1, 0x98, 0x3b, - 0x34, 0xd2, 0x0a, 0x59, 0xcb, 0xee, 0x71, 0x02, 0xc2, 0xf4, 0xff, 0xb1, 0xc7, 0xa9, 0xac, 0x53, - 0x84, 0x67, 0x54, 0xf4, 0x0c, 0x96, 0x39, 0x8d, 0x04, 0xe1, 0xe2, 0x63, 0x4d, 0xc6, 0x09, 0xa4, - 0xcf, 0x7c, 0xcf, 0x39, 0xc2, 0x13, 0x06, 0x7a, 0x06, 0xc5, 0xd0, 0x27, 0x8e, 0xca, 0x6a, 0x2f, - 0x29, 0xfa, 0x6f, 0xb2, 0xe8, 0xfd, 0x09, 0x08, 0xcf, 0xf0, 0xe8, 0x29, 0x80, 0xcf, 0x86, 0x03, - 0x97, 0x7b, 0x63, 0xca, 0xb5, 0x48, 0x2a, 0x59, 0xec, 0x8e, 0x42, 0xe0, 0xa2, 0xcf, 0x86, 0xc9, - 0x10, 0x6d, 0xfe, 0x2a, 0x85, 0xa4, 0xd4, 0xb1, 0x05, 0x40, 0xa6, 0xab, 0x5a, 0x1f, 0x8f, 0x3e, - 0x2b, 0x95, 0xee, 0x48, 0x8a, 0x8e, 0xee, 0x41, 0x69, 0x9f, 0x71, 0x87, 0x0e, 0xb4, 0xee, 0x8b, - 0x4a, 0x13, 0x96, 0x8a, 0x25, 0x42, 0x6f, 0x15, 0x61, 0x99, 0xc7, 0x81, 0xf0, 0x46, 0xb4, 0xbe, - 0x05, 0x37, 0x32, 0x93, 0xa2, 0x06, 0x94, 0xa6, 0x6d, 0x1e, 0x78, 0xae, 0xd2, 0x47, 0xb1, 0x75, - 0xf5, 0xfc, 0x74, 0xd5, 0x9a, 0xea, 0xa1, 0xd7, 0xc1, 0xd6, 0x14, 0xd4, 0x73, 0xeb, 0x3f, 0x98, - 0xb0, 0x32, 0x27, 0x16, 0x74, 0x1d, 0x96, 0xbc, 0x11, 0x19, 0xd2, 0x84, 0x8e, 0x93, 0x09, 0xea, - 0x42, 0xde, 0x27, 0x7b, 0xd4, 0x97, 0x92, 0x91, 0x65, 0xfb, 0xe3, 0x27, 0x55, 0xb7, 0xfe, 0x5f, - 0x85, 0xef, 0x06, 0x82, 0x1f, 0x61, 0x4d, 0x46, 0x36, 0x2c, 0x3b, 0x6c, 0x34, 0x22, 0x81, 0xb4, - 0x97, 0xc5, 0xb5, 0x22, 0x9e, 0x4c, 0x11, 0x02, 0x93, 0xf0, 0x61, 0x64, 0x9b, 0x2a, 0xac, 0xc6, - 0xa8, 0x0c, 0x8b, 0x34, 0x18, 0xdb, 0x4b, 0x2a, 0x24, 0x87, 0x32, 0xe2, 0x7a, 0x49, 0xcf, 0x8b, - 0x58, 0x0e, 0x25, 0x2f, 0x8e, 0x28, 0xb7, 0x97, 0x55, 0x48, 0x8d, 0xd1, 0xdf, 0x20, 0x3f, 0x62, - 0x71, 0x20, 0x22, 0xbb, 0xa0, 0x0e, 0x7b, 0x3b, 0xeb, 0xb0, 0xdb, 0x12, 0xa1, 0xed, 0x4f, 0xc3, - 0xd1, 0x0b, 0xb8, 0x16, 0x09, 0x16, 0x0e, 0x86, 0x9c, 0x38, 0x74, 0x10, 0x52, 0xee, 0x31, 0x57, - 0x75, 0xe3, 0x02, 0x17, 0xed, 0xe8, 0x1b, 0x1e, 0x5f, 0x95, 0xb4, 0x4d, 0xc9, 0xea, 0x2b, 0x12, - 0xea, 0x43, 0x29, 0x8c, 0x7d, 0x7f, 0xc0, 0xc2, 0xc4, 0xcc, 0x41, 0x25, 0xf9, 0x8c, 0xaa, 0xf5, - 0x63, 0xdf, 0x7f, 0x99, 0x90, 0xb0, 0x15, 0xce, 0x26, 0xe8, 0x26, 0xe4, 0x87, 0x9c, 0xc5, 0x61, - 0x64, 0x5b, 0xaa, 0x1e, 0x7a, 0x86, 0x9e, 0xc3, 0x72, 0x44, 0x1d, 0x4e, 0x45, 0x64, 0x97, 0xd4, - 0xaf, 0xbd, 0x9f, 0xb5, 0xc9, 0xae, 0x82, 0x60, 0xba, 0x4f, 0x39, 0x0d, 0x1c, 0x8a, 0x27, 0x9c, - 0xca, 0x53, 0xb0, 0x52, 0x8d, 0x92, 0x05, 0x3e, 0xa4, 0x47, 0xba, 0xf7, 0x72, 0x28, 0xf5, 0x30, - 0x26, 0x7e, 0x9c, 0xbc, 0x30, 0x8a, 0x38, 0x99, 0xfc, 0x7d, 0xe1, 0x89, 0x51, 0x69, 0x80, 0x95, - 0x3a, 0x2d, 0xba, 0x0f, 0x2b, 0x9c, 0x0e, 0xbd, 0x48, 0xf0, 0xa3, 0x01, 0x89, 0xc5, 0x81, 0xfd, - 0x2f, 0x45, 0x28, 0x4d, 0x82, 0xcd, 0x58, 0x1c, 0xd4, 0x7f, 0x32, 0xa0, 0x94, 0xb6, 0x4c, 0xd4, - 0x4e, 0x8c, 0x52, 0xed, 0x78, 0xa5, 0xb1, 0xf1, 0x29, 0x8b, 0x55, 0xb6, 0xe4, 0xc7, 0x72, 0xc7, - 0x6d, 0xf9, 0xac, 0x51, 0x64, 0xf4, 0x57, 0x58, 0x0a, 0x19, 0x17, 0x13, 0x71, 0x56, 0x33, 0xad, - 0x84, 0xf1, 0xc9, 0x67, 0x9c, 0x80, 0xeb, 0x07, 0x70, 0x65, 0x3e, 0x1b, 0x7a, 0x00, 0x8b, 0x6f, - 0x7a, 0xfd, 0x72, 0xae, 0x72, 0xe7, 0xf8, 0xa4, 0x76, 0x6b, 0x7e, 0xf1, 0x8d, 0xc7, 0x45, 0x4c, - 0xfc, 0x5e, 0x1f, 0xfd, 0x1e, 0x96, 0x3a, 0x3b, 0xbb, 0x18, 0x97, 0x8d, 0xca, 0xea, 0xf1, 0x49, - 0xed, 0xce, 0x3c, 0x4e, 0x2e, 0xb1, 0x38, 0x70, 0x31, 0xdb, 0x9b, 0xde, 0xf4, 0xdf, 0x2c, 0x80, - 0xa5, 0xbf, 0xd9, 0xcb, 0xbd, 0xe9, 0xff, 0x09, 0x2b, 0x89, 0x0d, 0x0e, 0x1c, 0xf5, 0xd3, 0xb4, - 0xa1, 0x7f, 0xcc, 0x0d, 0x4b, 0x09, 0x21, 0x29, 0x85, 0xb4, 0x1e, 0x2f, 0x1c, 0x3f, 0x1e, 0xd0, - 0x80, 0xec, 0xf9, 0xfa, 0xd2, 0x2f, 0x60, 0x4b, 0xc6, 0xba, 0x49, 0x48, 0xde, 0x56, 0x5e, 0x20, - 0x28, 0x0f, 0xf4, 0x75, 0x5e, 0xc0, 0xd3, 0x39, 0x7a, 0x0e, 0xa6, 0x17, 0x92, 0x91, 0xb6, 0xf0, - 0xcc, 0x5f, 0xd0, 0xeb, 0x37, 0xb7, 0xb5, 0x44, 0x5a, 0x85, 0xf3, 0xd3, 0x55, 0x53, 0x06, 0xb0, - 0xa2, 0xa1, 0xea, 0xc4, 0x45, 0xe5, 0x4e, 0xea, 0xab, 0x2e, 0xe0, 0x54, 0xa4, 0xfe, 0xb5, 0x09, - 0x56, 0xdb, 0x8f, 0x23, 0xa1, 0xbd, 0xe9, 0xd2, 0xea, 0xf6, 0x3f, 0xb8, 0x46, 0xd4, 0xbb, 0x90, - 0x04, 0xf2, 0x43, 0x57, 0xb7, 0x93, 0xae, 0xdd, 0x83, 0xcc, 0x74, 0x53, 0x70, 0x72, 0x93, 0xb5, - 0xf2, 0x32, 0xa7, 0x6d, 0xe0, 0x32, 0xf9, 0xc5, 0x0a, 0xda, 0x85, 0x15, 0xc6, 0x9d, 0x03, 0x1a, - 0x89, 0xc4, 0x1b, 0xf4, 0x3b, 0x2a, 0xf3, 0x85, 0xfd, 0x32, 0x0d, 0xd4, 0xaf, 0x90, 0xe4, 0xb4, - 0xf3, 0x39, 0xd0, 0x13, 0x30, 0x39, 0xd9, 0x9f, 0xdc, 0xb4, 0x99, 0xfa, 0xc6, 0x64, 0x5f, 0xcc, - 0xa5, 0x50, 0x0c, 0xf4, 0x1f, 0x00, 0xd7, 0x8b, 0x42, 0x22, 0x9c, 0x03, 0xca, 0x75, 0x9f, 0x32, - 0x7f, 0x62, 0x67, 0x8a, 0x9a, 0xcb, 0x92, 0x62, 0xa3, 0x2d, 0x28, 0x3a, 0x64, 0xa2, 0xb4, 0xfc, - 0xc5, 0xb6, 0xd8, 0x6e, 0xea, 0x14, 0x65, 0x99, 0xe2, 0xfc, 0x74, 0xb5, 0x30, 0x89, 0xe0, 0x82, - 0x43, 0xb4, 0xf2, 0xb6, 0x60, 0x45, 0x3e, 0x3a, 0x07, 0x2e, 0xdd, 0x27, 0xb1, 0x2f, 0x22, 0xe5, - 0xe0, 0x17, 0x3c, 0xb2, 0xe4, 0xfb, 0xa7, 0xa3, 0x71, 0xfa, 0x5c, 0x25, 0x91, 0x8a, 0xd5, 0x3d, - 0x80, 0xc4, 0xe1, 0x2e, 0x57, 0x26, 0x08, 0x4c, 0x97, 0x08, 0xa2, 0x94, 0x51, 0xc2, 0x6a, 0xdc, - 0xba, 0xfb, 0xfe, 0xac, 0x9a, 0xfb, 0xee, 0xac, 0x9a, 0xfb, 0xf1, 0xac, 0x6a, 0x7c, 0x71, 0x5e, - 0x35, 0xde, 0x9f, 0x57, 0x8d, 0x6f, 0xcf, 0xab, 0xc6, 0xf7, 0xe7, 0x55, 0x63, 0x2f, 0xaf, 0xfe, - 0xeb, 0xfd, 0xe5, 0xe7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb6, 0x26, 0x4a, 0x64, 0x4a, 0x0e, 0x00, - 0x00, + // 1586 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x57, 0xdd, 0x6e, 0xe3, 0xc6, + 0x15, 0x16, 0x2d, 0x59, 0x3f, 0x87, 0xd2, 0xae, 0x76, 0x90, 0x1f, 0xae, 0x92, 0x4a, 0x5a, 0x65, + 0x9b, 0x3a, 0x0d, 0xea, 0x6d, 0xd5, 0x22, 0xdd, 0x74, 0x1b, 0xb4, 0xfa, 0xab, 0x57, 0x75, 0xed, + 0x08, 0x63, 0x67, 0x81, 0xbd, 0x12, 0xc6, 0xe4, 0x58, 0x22, 0x4c, 0x71, 0xd8, 0xe1, 0x50, 0x81, + 0xef, 0x7a, 0x19, 0xec, 0x45, 0xdf, 0xc0, 0x57, 0x2d, 0xfa, 0x06, 0x7d, 0x87, 0xbd, 0xec, 0x65, + 0xaf, 0x8c, 0x5a, 0x4f, 0x50, 0xa0, 0x2f, 0x50, 0xcc, 0x70, 0x28, 0x51, 0x0d, 0x1d, 0x07, 0xa8, + 0xef, 0x66, 0x0e, 0xbf, 0xef, 0x70, 0xe6, 0x9c, 0x8f, 0xe7, 0x1c, 0x82, 0x19, 0x06, 0xd4, 0x0e, + 0xf7, 0x03, 0xce, 0x04, 0x43, 0xc8, 0x61, 0xf6, 0x05, 0xe5, 0xfb, 0xe1, 0xd7, 0x84, 0x2f, 0x2e, + 0x5c, 0xb1, 0xbf, 0xfc, 0x59, 0xc3, 0x14, 0x97, 0x01, 0xd5, 0x80, 0xc6, 0x3b, 0x33, 0x36, 0x63, + 0x6a, 0xf9, 0x4c, 0xae, 0xb4, 0xf5, 0x7d, 0x27, 0xe2, 0x44, 0xb8, 0xcc, 0x7f, 0x96, 0x2c, 0xe2, + 0x07, 0x9d, 0x3f, 0x17, 0xa0, 0x7c, 0xcc, 0x1c, 0x7a, 0x12, 0x50, 0x1b, 0x1d, 0x80, 0x49, 0x7c, + 0x9f, 0x09, 0x05, 0x08, 0x2d, 0xa3, 0x6d, 0xec, 0x99, 0xdd, 0xd6, 0xfe, 0xb7, 0x5f, 0xb9, 0xdf, + 0xdb, 0xc0, 0xfa, 0x85, 0xb7, 0xd7, 0xad, 0x1c, 0x4e, 0x33, 0xd1, 0x4f, 0xa1, 0xc0, 0x99, 0x47, + 0xad, 0x9d, 0xb6, 0xb1, 0xf7, 0xa0, 0xfb, 0x61, 0x96, 0x07, 0xf9, 0x52, 0xcc, 0x3c, 0x8a, 0x15, + 0x12, 0x1d, 0x00, 0x2c, 0xe8, 0xe2, 0x8c, 0xf2, 0x70, 0xee, 0x06, 0x56, 0x5e, 0xf1, 0x7e, 0x74, + 0x1b, 0x4f, 0x1e, 0x76, 0xff, 0x68, 0x0d, 0xc7, 0x29, 0x2a, 0x3a, 0x82, 0x2a, 0x59, 0x12, 0xd7, + 0x23, 0x67, 0xae, 0xe7, 0x8a, 0x4b, 0xab, 0xa0, 0x5c, 0x7d, 0xf2, 0x9d, 0xae, 0x7a, 0x29, 0x02, + 0xde, 0xa2, 0x77, 0x1c, 0x80, 0xcd, 0x8b, 0xd0, 0xc7, 0x50, 0x9a, 0x8c, 0x8e, 0x87, 0xe3, 0xe3, + 0x83, 0x7a, 0xae, 0xf1, 0xf8, 0xcd, 0x55, 0xfb, 0x5d, 0xe9, 0x63, 0x03, 0x98, 0x50, 0xdf, 0x71, + 0xfd, 0x19, 0xda, 0x83, 0x72, 0x6f, 0x30, 0x18, 0x4d, 0x4e, 0x47, 0xc3, 0xba, 0xd1, 0x68, 0xbc, + 0xb9, 0x6a, 0xbf, 0xb7, 0x0d, 0xec, 0xd9, 0x36, 0x0d, 0x04, 0x75, 0x1a, 0x85, 0x6f, 0xfe, 0xd2, + 0xcc, 0x75, 0xbe, 0x31, 0xa0, 0x9a, 0x3e, 0x04, 0xfa, 0x18, 0x8a, 0xbd, 0xc1, 0xe9, 0xf8, 0xd5, + 0xa8, 0x9e, 0xdb, 0xd0, 0xd3, 0x88, 0x9e, 0x2d, 0xdc, 0x25, 0x45, 0x4f, 0x61, 0x77, 0xd2, 0xfb, + 0xea, 0x64, 0x54, 0x37, 0x36, 0xc7, 0x49, 0xc3, 0x26, 0x24, 0x0a, 0x15, 0x6a, 0x88, 0x7b, 0xe3, + 0xe3, 0xfa, 0x4e, 0x36, 0x6a, 0xc8, 0x89, 0xeb, 0xeb, 0xa3, 0xdc, 0xe4, 0xc1, 0x3c, 0xa1, 0x7c, + 0xe9, 0xda, 0xf7, 0xac, 0x89, 0xcf, 0xa0, 0x20, 0x48, 0x78, 0xa1, 0x34, 0x61, 0x66, 0x6b, 0xe2, + 0x94, 0x84, 0x17, 0xf2, 0xa5, 0x9a, 0xae, 0xf0, 0x52, 0x19, 0x9c, 0x06, 0x9e, 0x6b, 0x13, 0x41, + 0x1d, 0xa5, 0x0c, 0xb3, 0xfb, 0xc3, 0x2c, 0x36, 0x5e, 0xa3, 0xf4, 0xf9, 0x5f, 0xe6, 0x70, 0x8a, + 0x8a, 0x5e, 0x40, 0x71, 0xe6, 0xb1, 0x33, 0xe2, 0x29, 0x4d, 0x98, 0xdd, 0x27, 0x59, 0x4e, 0x0e, + 0x14, 0x62, 0xe3, 0x40, 0x53, 0xd0, 0x73, 0x28, 0x46, 0x81, 0x43, 0x04, 0xb5, 0x8a, 0x8a, 0xdc, + 0xce, 0x22, 0x7f, 0xa5, 0x10, 0x03, 0xe6, 0x9f, 0xbb, 0x33, 0xac, 0xf1, 0xe8, 0x10, 0xca, 0x3e, + 0x15, 0x5f, 0x33, 0x7e, 0x11, 0x5a, 0xa5, 0x76, 0x7e, 0xcf, 0xec, 0x7e, 0x9a, 0x29, 0xc6, 0x18, + 0xd3, 0x13, 0x82, 0xd8, 0xf3, 0x05, 0xf5, 0x45, 0xec, 0xa6, 0xbf, 0x63, 0x19, 0x78, 0xed, 0x00, + 0xfd, 0x1a, 0xca, 0xd4, 0x77, 0x02, 0xe6, 0xfa, 0xc2, 0x2a, 0xdf, 0x7e, 0x90, 0x91, 0xc6, 0xc8, + 0x60, 0xe2, 0x35, 0xa3, 0x5f, 0x84, 0xc2, 0x82, 0x39, 0xb4, 0xf3, 0x0c, 0x1e, 0x7d, 0x2b, 0x58, + 0xa8, 0x01, 0x65, 0x1d, 0xac, 0x38, 0xcb, 0x05, 0xbc, 0xde, 0x77, 0x1e, 0x42, 0x6d, 0x2b, 0x30, + 0xaa, 0x6c, 0x24, 0xd9, 0x42, 0x3d, 0xa8, 0xd8, 0xcc, 0x17, 0xc4, 0xf5, 0x29, 0xd7, 0x02, 0xc9, + 0x8c, 0xed, 0x20, 0x01, 0x49, 0xd6, 0xcb, 0x1c, 0xde, 0xb0, 0xd0, 0xef, 0xa0, 0xc2, 0x69, 0xc8, + 0x22, 0x6e, 0xd3, 0x50, 0x2b, 0x64, 0x2f, 0x3b, 0xc7, 0x31, 0x08, 0xd3, 0x3f, 0x46, 0x2e, 0xa7, + 0x32, 0x4e, 0x21, 0xde, 0x50, 0xd1, 0x0b, 0x28, 0x71, 0x1a, 0x0a, 0xc2, 0xc5, 0x77, 0x25, 0x19, + 0xc7, 0x90, 0x09, 0xf3, 0x5c, 0xfb, 0x12, 0x27, 0x0c, 0xf4, 0x02, 0x2a, 0x81, 0x47, 0x6c, 0xe5, + 0xd5, 0xda, 0x55, 0xf4, 0x1f, 0x64, 0xd1, 0x27, 0x09, 0x08, 0x6f, 0xf0, 0xe8, 0x73, 0x00, 0x8f, + 0xcd, 0xa6, 0x0e, 0x77, 0x97, 0x94, 0x6b, 0x91, 0x34, 0xb2, 0xd8, 0x43, 0x85, 0xc0, 0x15, 0x8f, + 0xcd, 0xe2, 0x25, 0x3a, 0xf8, 0xbf, 0x14, 0x92, 0x52, 0xc7, 0x21, 0x00, 0x59, 0x3f, 0xd5, 0xfa, + 0xf8, 0xe4, 0x7b, 0xb9, 0xd2, 0x19, 0x49, 0xd1, 0xd1, 0x13, 0xa8, 0x9e, 0x33, 0x6e, 0xd3, 0xa9, + 0xd6, 0x7d, 0x45, 0x69, 0xc2, 0x54, 0xb6, 0x58, 0xe8, 0xfd, 0x0a, 0x94, 0x78, 0xe4, 0x0b, 0x77, + 0x41, 0x3b, 0x87, 0xf0, 0x6e, 0xa6, 0x53, 0xd4, 0x85, 0xea, 0x3a, 0xcd, 0x53, 0xd7, 0x51, 0xfa, + 0xa8, 0xf4, 0x1f, 0xae, 0xae, 0x5b, 0xe6, 0x5a, 0x0f, 0xe3, 0x21, 0x36, 0xd7, 0xa0, 0xb1, 0xd3, + 0xf9, 0x6b, 0x09, 0x6a, 0x5b, 0x62, 0x41, 0xef, 0xc0, 0xae, 0xbb, 0x20, 0x33, 0x1a, 0xd3, 0x71, + 0xbc, 0x41, 0x23, 0x28, 0x7a, 0xe4, 0x8c, 0x7a, 0x52, 0x32, 0x32, 0x6c, 0x3f, 0xb9, 0x53, 0x75, + 0xfb, 0x7f, 0x50, 0xf8, 0x91, 0x2f, 0xf8, 0x25, 0xd6, 0x64, 0x64, 0x41, 0xc9, 0x66, 0x8b, 0x05, + 0xf1, 0x65, 0x79, 0xc9, 0xef, 0x55, 0x70, 0xb2, 0x45, 0x08, 0x0a, 0x84, 0xcf, 0x42, 0xab, 0xa0, + 0xcc, 0x6a, 0x8d, 0xea, 0x90, 0xa7, 0xfe, 0xd2, 0xda, 0x55, 0x26, 0xb9, 0x94, 0x16, 0xc7, 0x8d, + 0x73, 0x5e, 0xc1, 0x72, 0x29, 0x79, 0x51, 0x48, 0xb9, 0x55, 0x52, 0x26, 0xb5, 0x46, 0xbf, 0x84, + 0xe2, 0x82, 0x45, 0xbe, 0x08, 0xad, 0xb2, 0x3a, 0xec, 0xe3, 0xac, 0xc3, 0x1e, 0x49, 0x84, 0x2e, + 0x7f, 0x1a, 0x8e, 0x5e, 0xc2, 0xa3, 0x50, 0xb0, 0x60, 0x3a, 0xe3, 0xc4, 0xa6, 0xd3, 0x80, 0x72, + 0x97, 0x39, 0x2a, 0x1b, 0xb7, 0x54, 0xd1, 0xa1, 0xee, 0xf0, 0xf8, 0xa1, 0xa4, 0x1d, 0x48, 0xd6, + 0x44, 0x91, 0xd0, 0x04, 0xaa, 0x41, 0xe4, 0x79, 0x53, 0x16, 0xc4, 0xc5, 0x1c, 0x94, 0x93, 0xef, + 0x11, 0xb5, 0x49, 0xe4, 0x79, 0x5f, 0xc6, 0x24, 0x6c, 0x06, 0x9b, 0x0d, 0x7a, 0x0f, 0x8a, 0x33, + 0xce, 0xa2, 0x20, 0xb4, 0x4c, 0x15, 0x0f, 0xbd, 0x43, 0x5f, 0x40, 0x29, 0xa4, 0x36, 0xa7, 0x22, + 0xb4, 0xaa, 0xea, 0xb6, 0x1f, 0x65, 0xbd, 0xe4, 0x44, 0x41, 0x30, 0x3d, 0xa7, 0x9c, 0xfa, 0x36, + 0xc5, 0x09, 0x07, 0x3d, 0x86, 0xbc, 0x10, 0x97, 0x56, 0xad, 0x6d, 0xec, 0x95, 0xfb, 0xa5, 0xd5, + 0x75, 0x2b, 0x7f, 0x7a, 0xfa, 0x1a, 0x4b, 0x9b, 0x2c, 0x53, 0x73, 0x16, 0x0a, 0x9f, 0x2c, 0xa8, + 0xf5, 0x40, 0x85, 0x77, 0xbd, 0x47, 0xaf, 0x01, 0x1c, 0x3f, 0x9c, 0xda, 0xea, 0xbb, 0xb0, 0x1e, + 0xaa, 0xdb, 0x7d, 0x7a, 0xf7, 0xed, 0x86, 0xc7, 0x27, 0xba, 0xd8, 0xd6, 0x56, 0xd7, 0xad, 0xca, + 0x7a, 0x8b, 0x2b, 0x8e, 0x1f, 0xc6, 0x4b, 0xd4, 0x07, 0x73, 0x4e, 0x89, 0x27, 0xe6, 0xf6, 0x9c, + 0xda, 0x17, 0x56, 0xfd, 0xf6, 0xda, 0xfb, 0x52, 0xc1, 0xb4, 0x87, 0x34, 0xa9, 0xf1, 0x39, 0x98, + 0x29, 0xf9, 0x49, 0xd9, 0x5c, 0xd0, 0x4b, 0xad, 0x68, 0xb9, 0x94, 0x2a, 0x5f, 0x12, 0x2f, 0x8a, + 0xe7, 0xa6, 0x0a, 0x8e, 0x37, 0xbf, 0xda, 0x79, 0x6e, 0x34, 0xba, 0x60, 0xa6, 0x72, 0x80, 0x3e, + 0x82, 0x1a, 0xa7, 0x33, 0x37, 0x14, 0xfc, 0x72, 0x4a, 0x22, 0x31, 0xb7, 0x7e, 0xab, 0x08, 0xd5, + 0xc4, 0xd8, 0x8b, 0xc4, 0xbc, 0x31, 0x85, 0xcd, 0x55, 0x50, 0x1b, 0x4c, 0x19, 0xa2, 0x90, 0xf2, + 0x25, 0xe5, 0xb2, 0xc0, 0xcb, 0x6c, 0xa5, 0x4d, 0x32, 0x95, 0x21, 0x25, 0xdc, 0x9e, 0xab, 0x8f, + 0xa9, 0x82, 0xf5, 0x4e, 0x7e, 0x1d, 0x89, 0x5e, 0xf4, 0xd7, 0xa1, 0xb7, 0x9d, 0xff, 0x18, 0x50, + 0x4d, 0x77, 0x1a, 0x34, 0x88, 0xfb, 0x8b, 0xba, 0xd2, 0x83, 0xee, 0xb3, 0xbb, 0x3a, 0x93, 0xaa, + 0xe6, 0x5e, 0x24, 0x9d, 0x1d, 0xc9, 0x69, 0x50, 0x91, 0xd1, 0x2f, 0x60, 0x37, 0x60, 0x5c, 0x24, + 0xdf, 0x74, 0x33, 0xb3, 0x02, 0x33, 0x9e, 0x54, 0xbf, 0x18, 0xdc, 0x99, 0xc3, 0x83, 0x6d, 0x6f, + 0xe8, 0x29, 0xe4, 0x5f, 0x8d, 0x27, 0xf5, 0x5c, 0xe3, 0x83, 0x37, 0x57, 0xed, 0xf7, 0xb7, 0x1f, + 0xbe, 0x72, 0xb9, 0x88, 0x88, 0x37, 0x9e, 0xa0, 0x1f, 0xc3, 0xee, 0xf0, 0xf8, 0x04, 0xe3, 0xba, + 0xd1, 0x68, 0xbd, 0xb9, 0x6a, 0x7f, 0xb0, 0x8d, 0x93, 0x8f, 0x58, 0xe4, 0x3b, 0x98, 0x9d, 0xad, + 0x07, 0xa4, 0xbf, 0xef, 0x80, 0xa9, 0x4b, 0xdd, 0xfd, 0x0e, 0x48, 0xbf, 0x81, 0x5a, 0xdc, 0x3d, + 0x12, 0x01, 0xef, 0xdc, 0xd9, 0x44, 0xaa, 0x31, 0x41, 0xe7, 0xf8, 0x09, 0x54, 0xdd, 0x60, 0xf9, + 0xd9, 0x94, 0xfa, 0xe4, 0xcc, 0xd3, 0xb3, 0x52, 0x19, 0x9b, 0xd2, 0x36, 0x8a, 0x4d, 0xf2, 0xeb, + 0x71, 0x7d, 0x41, 0xb9, 0xaf, 0xa7, 0xa0, 0x32, 0x5e, 0xef, 0xd1, 0x17, 0x50, 0x70, 0x03, 0xb2, + 0xd0, 0x9d, 0x2f, 0xf3, 0x06, 0xe3, 0x49, 0xef, 0x48, 0x6b, 0xb0, 0x5f, 0x5e, 0x5d, 0xb7, 0x0a, + 0xd2, 0x80, 0x15, 0x0d, 0x35, 0x93, 0xe6, 0x23, 0xdf, 0xa4, 0x8a, 0x61, 0x19, 0xa7, 0x2c, 0x9d, + 0xbf, 0x15, 0xc0, 0x1c, 0x78, 0x51, 0x28, 0x74, 0x49, 0xbf, 0xb7, 0xb8, 0xbd, 0x86, 0x47, 0x44, + 0x8d, 0xd3, 0xc4, 0x97, 0xf5, 0x51, 0x35, 0x75, 0x1d, 0xbb, 0xa7, 0x99, 0xee, 0xd6, 0xe0, 0x78, + 0x00, 0xe8, 0x17, 0xa5, 0x4f, 0xcb, 0xc0, 0x75, 0xf2, 0x3f, 0x4f, 0xd0, 0x09, 0xd4, 0x18, 0xb7, + 0xe7, 0x34, 0x14, 0x71, 0x49, 0xd5, 0xe3, 0x67, 0xe6, 0x8f, 0xc9, 0x97, 0x69, 0xa0, 0xae, 0x27, + 0xf1, 0x69, 0xb7, 0x7d, 0xa0, 0xe7, 0x50, 0xe0, 0xe4, 0x3c, 0x19, 0x50, 0x32, 0xf5, 0x8d, 0xc9, + 0xb9, 0xd8, 0x72, 0xa1, 0x18, 0xe8, 0xf7, 0x00, 0x8e, 0x1b, 0x06, 0x44, 0xd8, 0x73, 0xca, 0x75, + 0x9e, 0x32, 0xaf, 0x38, 0x5c, 0xa3, 0xb6, 0xbc, 0xa4, 0xd8, 0xe8, 0x10, 0x2a, 0x36, 0x49, 0x94, + 0x56, 0xbc, 0xbd, 0x9b, 0x0c, 0x7a, 0xda, 0x45, 0x5d, 0xba, 0x58, 0x5d, 0xb7, 0xca, 0x89, 0x05, + 0x97, 0x6d, 0xa2, 0x95, 0x77, 0x08, 0x35, 0x39, 0xab, 0x4f, 0x1d, 0x7a, 0x4e, 0x22, 0x4f, 0x84, + 0xaa, 0xf1, 0xdd, 0x52, 0x1f, 0xe5, 0xd8, 0x38, 0xd4, 0x38, 0x7d, 0xae, 0xaa, 0x48, 0xd9, 0x3a, + 0x2e, 0x40, 0xdc, 0x18, 0xee, 0x57, 0x26, 0x08, 0x0a, 0x0e, 0x11, 0x44, 0x29, 0xa3, 0x8a, 0xd5, + 0xba, 0xff, 0xe1, 0xdb, 0x9b, 0x66, 0xee, 0x9f, 0x37, 0xcd, 0xdc, 0xbf, 0x6f, 0x9a, 0xc6, 0x9f, + 0x56, 0x4d, 0xe3, 0xed, 0xaa, 0x69, 0xfc, 0x63, 0xd5, 0x34, 0xfe, 0xb5, 0x6a, 0x1a, 0x67, 0x45, + 0xf5, 0x8b, 0xfc, 0xf3, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xc3, 0x59, 0xc9, 0x0e, 0x81, 0x0f, + 0x00, 0x00, } diff --git a/vendor/src/github.com/docker/swarmkit/api/specs.proto b/vendor/src/github.com/docker/swarmkit/api/specs.proto index 093b82272c9ff..7889b30006672 100644 --- a/vendor/src/github.com/docker/swarmkit/api/specs.proto +++ b/vendor/src/github.com/docker/swarmkit/api/specs.proto @@ -128,6 +128,7 @@ message NetworkAttachmentSpec { string container_id = 1 [(gogoproto.customname) = "ContainerID"]; } + // Container specifies runtime parameters for a container. message ContainerSpec { // image defines the image reference, as specified in the @@ -159,6 +160,10 @@ message ContainerSpec { // If Command and Args are provided, Args will be appended to Command. repeated string args = 4; + // Hostname specifies the hostname that will be set on containers created by docker swarm. + // All containers for a given service will have the same hostname + string hostname = 14; + // Env specifies the environment variables for the container in NAME=VALUE // format. These must be compliant with [IEEE Std // 1003.1-2001](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html). @@ -177,6 +182,10 @@ message ContainerSpec { // Groups specifies supplementary groups available to the user. repeated string groups = 11; + // TTY declares that a TTY should be attached to the standard streams, + // including stdin if it is still open. + bool tty = 13 [(gogoproto.customname) = "TTY"]; + repeated Mount mounts = 8 [(gogoproto.nullable) = false]; // StopGracePeriod the grace period for stopping the container before @@ -198,6 +207,30 @@ message ContainerSpec { // SecretReference contains references to zero or more secrets that // will be exposed to the container. repeated SecretReference secrets = 12; + + // DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf) + // Detailed documentation is available in: + // http://man7.org/linux/man-pages/man5/resolv.conf.5.html + // TODO: domain is not supported yet + message DNSConfig { + // Nameservers specifies the IP addresses of the name servers + repeated string nameservers = 1; + + // Search specifies the search list for host-name lookup + repeated string search = 2; + + // Options allows certain internal resolver variables to be modified + repeated string options = 3; + } + + // DNSConfig allows one to specify DNS related configuration in resolv.conf + DNSConfig dns_config = 15 [(gogoproto.customname) = "DNSConfig"]; + + // Healthcheck describes how to check the container is healthy. If the + // container is considered unhealthy, it will be destroyed, its creating + // task will exit and a new task will be rescheduled elsewhere. A container + // is considered unhealthy after `Retries` number of consecutive failures. + HealthConfig healthcheck = 16; } // EndpointSpec defines the properties that can be configured to diff --git a/vendor/src/github.com/docker/swarmkit/api/types.pb.go b/vendor/src/github.com/docker/swarmkit/api/types.pb.go index 314bc9698a971..6a0eca980e218 100644 --- a/vendor/src/github.com/docker/swarmkit/api/types.pb.go +++ b/vendor/src/github.com/docker/swarmkit/api/types.pb.go @@ -34,6 +34,7 @@ UpdateConfig UpdateStatus ContainerStatus + PortStatus TaskStatus NetworkAttachmentConfig IPAMConfig @@ -57,7 +58,8 @@ EncryptionKey ManagerStatus SecretReference - RemovedNode + BlacklistedCertificate + HealthConfig NodeSpec ServiceSpec ReplicatedService @@ -119,6 +121,8 @@ UpdateClusterResponse GetSecretRequest GetSecretResponse + UpdateSecretRequest + UpdateSecretResponse ListSecretsRequest ListSecretsResponse CreateSecretRequest @@ -202,8 +206,7 @@ type TaskState int32 const ( TaskStateNew TaskState = 0 - TaskStateAllocated TaskState = 64 - TaskStatePending TaskState = 128 + TaskStatePending TaskState = 64 TaskStateAssigned TaskState = 192 TaskStateAccepted TaskState = 256 TaskStatePreparing TaskState = 320 @@ -218,8 +221,7 @@ const ( var TaskState_name = map[int32]string{ 0: "NEW", - 64: "ALLOCATED", - 128: "PENDING", + 64: "PENDING", 192: "ASSIGNED", 256: "ACCEPTED", 320: "PREPARING", @@ -233,8 +235,7 @@ var TaskState_name = map[int32]string{ } var TaskState_value = map[string]int32{ "NEW": 0, - "ALLOCATED": 64, - "PENDING": 128, + "PENDING": 64, "ASSIGNED": 192, "ACCEPTED": 256, "PREPARING": 320, @@ -516,7 +517,7 @@ func (x IPAMConfig_AddressFamily) String() string { return proto.EnumName(IPAMConfig_AddressFamily_name, int32(x)) } func (IPAMConfig_AddressFamily) EnumDescriptor() ([]byte, []int) { - return fileDescriptorTypes, []int{18, 0} + return fileDescriptorTypes, []int{19, 0} } type PortConfig_Protocol int32 @@ -538,16 +539,52 @@ var PortConfig_Protocol_value = map[string]int32{ func (x PortConfig_Protocol) String() string { return proto.EnumName(PortConfig_Protocol_name, int32(x)) } -func (PortConfig_Protocol) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{19, 0} } +func (PortConfig_Protocol) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{20, 0} } + +// PublishMode controls how ports are published on the swarm. +type PortConfig_PublishMode int32 + +const ( + // PublishModeIngress exposes the port across the cluster on all nodes. + PublishModeIngress PortConfig_PublishMode = 0 + // PublishModeHost exposes the port on just the target host. If the + // published port is undefined, an ephemeral port will be allocated. If + // the published port is defined, the node will attempt to allocate it, + // erroring the task if it fails. + PublishModeHost PortConfig_PublishMode = 1 +) + +var PortConfig_PublishMode_name = map[int32]string{ + 0: "INGRESS", + 1: "HOST", +} +var PortConfig_PublishMode_value = map[string]int32{ + "INGRESS": 0, + "HOST": 1, +} + +func (x PortConfig_PublishMode) String() string { + return proto.EnumName(PortConfig_PublishMode_name, int32(x)) +} +func (PortConfig_PublishMode) EnumDescriptor() ([]byte, []int) { + return fileDescriptorTypes, []int{20, 1} +} type IssuanceStatus_State int32 const ( IssuanceStateUnknown IssuanceStatus_State = 0 - IssuanceStateRenew IssuanceStatus_State = 1 + // A new certificate should be issued + IssuanceStateRenew IssuanceStatus_State = 1 + // Certificate is pending acceptance IssuanceStatePending IssuanceStatus_State = 2 - IssuanceStateIssued IssuanceStatus_State = 3 - IssuanceStateFailed IssuanceStatus_State = 4 + // successful completion certificate issuance + IssuanceStateIssued IssuanceStatus_State = 3 + // Certificate issuance failed + IssuanceStateFailed IssuanceStatus_State = 4 + // Signals workers to renew their certificate. From the CA's perspective + // this is equivalent to IssuanceStateIssued: a noop. + IssuanceStateRotate IssuanceStatus_State = 5 ) var IssuanceStatus_State_name = map[int32]string{ @@ -556,6 +593,7 @@ var IssuanceStatus_State_name = map[int32]string{ 2: "PENDING", 3: "ISSUED", 4: "FAILED", + 5: "ROTATE", } var IssuanceStatus_State_value = map[string]int32{ "UNKNOWN": 0, @@ -563,12 +601,13 @@ var IssuanceStatus_State_value = map[string]int32{ "PENDING": 2, "ISSUED": 3, "FAILED": 4, + "ROTATE": 5, } func (x IssuanceStatus_State) String() string { return proto.EnumName(IssuanceStatus_State_name, int32(x)) } -func (IssuanceStatus_State) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{24, 0} } +func (IssuanceStatus_State) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{25, 0} } type ExternalCA_CAProtocol int32 @@ -587,7 +626,7 @@ func (x ExternalCA_CAProtocol) String() string { return proto.EnumName(ExternalCA_CAProtocol_name, int32(x)) } func (ExternalCA_CAProtocol) EnumDescriptor() ([]byte, []int) { - return fileDescriptorTypes, []int{26, 0} + return fileDescriptorTypes, []int{27, 0} } // Encryption algorithm that can implemented using this key @@ -608,7 +647,7 @@ func (x EncryptionKey_Algorithm) String() string { return proto.EnumName(EncryptionKey_Algorithm_name, int32(x)) } func (EncryptionKey_Algorithm) EnumDescriptor() ([]byte, []int) { - return fileDescriptorTypes, []int{36, 0} + return fileDescriptorTypes, []int{37, 0} } // Mode specifies how this secret should be exposed to the task. @@ -638,7 +677,7 @@ var SecretReference_Mode_value = map[string]int32{ func (x SecretReference_Mode) String() string { return proto.EnumName(SecretReference_Mode_name, int32(x)) } -func (SecretReference_Mode) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{38, 0} } +func (SecretReference_Mode) EnumDescriptor() ([]byte, []int) { return fileDescriptorTypes, []int{39, 0} } // Version tracks the last time an object in the store was updated. type Version struct { @@ -936,6 +975,16 @@ func (m *ContainerStatus) Reset() { *m = ContainerStatus{} } func (*ContainerStatus) ProtoMessage() {} func (*ContainerStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{15} } +// PortStatus specifies the actual allocated runtime state of a list +// of port configs. +type PortStatus struct { + Ports []*PortConfig `protobuf:"bytes,1,rep,name=ports" json:"ports,omitempty"` +} + +func (m *PortStatus) Reset() { *m = PortStatus{} } +func (*PortStatus) ProtoMessage() {} +func (*PortStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{16} } + type TaskStatus struct { Timestamp *docker_swarmkit_v1.Timestamp `protobuf:"bytes,1,opt,name=timestamp" json:"timestamp,omitempty"` // State expresses the current state of the task. @@ -963,11 +1012,14 @@ type TaskStatus struct { // Types that are valid to be assigned to RuntimeStatus: // *TaskStatus_Container RuntimeStatus isTaskStatus_RuntimeStatus `protobuf_oneof:"runtime_status"` + // HostPorts provides a list of ports allocated at the host + // level. + PortStatus *PortStatus `protobuf:"bytes,6,opt,name=port_status,json=portStatus" json:"port_status,omitempty"` } func (m *TaskStatus) Reset() { *m = TaskStatus{} } func (*TaskStatus) ProtoMessage() {} -func (*TaskStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{16} } +func (*TaskStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{17} } type isTaskStatus_RuntimeStatus interface { isTaskStatus_RuntimeStatus() @@ -1069,7 +1121,7 @@ type NetworkAttachmentConfig struct { func (m *NetworkAttachmentConfig) Reset() { *m = NetworkAttachmentConfig{} } func (*NetworkAttachmentConfig) ProtoMessage() {} -func (*NetworkAttachmentConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{17} } +func (*NetworkAttachmentConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{18} } // IPAMConfig specifies parameters for IP Address Management. type IPAMConfig struct { @@ -1090,7 +1142,7 @@ type IPAMConfig struct { func (m *IPAMConfig) Reset() { *m = IPAMConfig{} } func (*IPAMConfig) ProtoMessage() {} -func (*IPAMConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{18} } +func (*IPAMConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{19} } // PortConfig specifies an exposed port which can be // addressed using the given name. This can be later queried @@ -1106,16 +1158,17 @@ type PortConfig struct { Protocol PortConfig_Protocol `protobuf:"varint,2,opt,name=protocol,proto3,enum=docker.swarmkit.v1.PortConfig_Protocol" json:"protocol,omitempty"` // The port which the application is exposing and is bound to. TargetPort uint32 `protobuf:"varint,3,opt,name=target_port,json=targetPort,proto3" json:"target_port,omitempty"` - // PublishedPort specifies the port on which the service is - // exposed. If specified, the port must be - // within the available range. If not specified, an available - // port is automatically assigned. + // PublishedPort specifies the port on which the service is exposed. If + // specified, the port must be within the available range. If not specified + // (value is zero), an available port is automatically assigned. PublishedPort uint32 `protobuf:"varint,4,opt,name=published_port,json=publishedPort,proto3" json:"published_port,omitempty"` + // PublishMode controls how the port is published. + PublishMode PortConfig_PublishMode `protobuf:"varint,5,opt,name=publish_mode,json=publishMode,proto3,enum=docker.swarmkit.v1.PortConfig_PublishMode" json:"publish_mode,omitempty"` } func (m *PortConfig) Reset() { *m = PortConfig{} } func (*PortConfig) ProtoMessage() {} -func (*PortConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{19} } +func (*PortConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{20} } // Driver is a generic driver type to be used throughout the API. For now, a // driver is simply a name and set of options. The field contents depend on the @@ -1128,7 +1181,7 @@ type Driver struct { func (m *Driver) Reset() { *m = Driver{} } func (*Driver) ProtoMessage() {} -func (*Driver) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{20} } +func (*Driver) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{21} } type IPAMOptions struct { Driver *Driver `protobuf:"bytes,1,opt,name=driver" json:"driver,omitempty"` @@ -1137,7 +1190,7 @@ type IPAMOptions struct { func (m *IPAMOptions) Reset() { *m = IPAMOptions{} } func (*IPAMOptions) ProtoMessage() {} -func (*IPAMOptions) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{21} } +func (*IPAMOptions) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{22} } // Peer should be used anywhere where we are describing a remote peer. type Peer struct { @@ -1147,7 +1200,7 @@ type Peer struct { func (m *Peer) Reset() { *m = Peer{} } func (*Peer) ProtoMessage() {} -func (*Peer) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{22} } +func (*Peer) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{23} } // WeightedPeer should be used anywhere where we are describing a remote peer // with a weight. @@ -1158,7 +1211,7 @@ type WeightedPeer struct { func (m *WeightedPeer) Reset() { *m = WeightedPeer{} } func (*WeightedPeer) ProtoMessage() {} -func (*WeightedPeer) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{23} } +func (*WeightedPeer) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{24} } type IssuanceStatus struct { State IssuanceStatus_State `protobuf:"varint,1,opt,name=state,proto3,enum=docker.swarmkit.v1.IssuanceStatus_State" json:"state,omitempty"` @@ -1170,7 +1223,7 @@ type IssuanceStatus struct { func (m *IssuanceStatus) Reset() { *m = IssuanceStatus{} } func (*IssuanceStatus) ProtoMessage() {} -func (*IssuanceStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{24} } +func (*IssuanceStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{25} } type AcceptancePolicy struct { Policies []*AcceptancePolicy_RoleAdmissionPolicy `protobuf:"bytes,1,rep,name=policies" json:"policies,omitempty"` @@ -1178,7 +1231,7 @@ type AcceptancePolicy struct { func (m *AcceptancePolicy) Reset() { *m = AcceptancePolicy{} } func (*AcceptancePolicy) ProtoMessage() {} -func (*AcceptancePolicy) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{25} } +func (*AcceptancePolicy) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{26} } type AcceptancePolicy_RoleAdmissionPolicy struct { Role NodeRole `protobuf:"varint,1,opt,name=role,proto3,enum=docker.swarmkit.v1.NodeRole" json:"role,omitempty"` @@ -1193,7 +1246,7 @@ type AcceptancePolicy_RoleAdmissionPolicy struct { func (m *AcceptancePolicy_RoleAdmissionPolicy) Reset() { *m = AcceptancePolicy_RoleAdmissionPolicy{} } func (*AcceptancePolicy_RoleAdmissionPolicy) ProtoMessage() {} func (*AcceptancePolicy_RoleAdmissionPolicy) Descriptor() ([]byte, []int) { - return fileDescriptorTypes, []int{25, 0} + return fileDescriptorTypes, []int{26, 0} } type AcceptancePolicy_RoleAdmissionPolicy_Secret struct { @@ -1208,7 +1261,7 @@ func (m *AcceptancePolicy_RoleAdmissionPolicy_Secret) Reset() { } func (*AcceptancePolicy_RoleAdmissionPolicy_Secret) ProtoMessage() {} func (*AcceptancePolicy_RoleAdmissionPolicy_Secret) Descriptor() ([]byte, []int) { - return fileDescriptorTypes, []int{25, 0, 0} + return fileDescriptorTypes, []int{26, 0, 0} } type ExternalCA struct { @@ -1223,7 +1276,7 @@ type ExternalCA struct { func (m *ExternalCA) Reset() { *m = ExternalCA{} } func (*ExternalCA) ProtoMessage() {} -func (*ExternalCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{26} } +func (*ExternalCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{27} } type CAConfig struct { // NodeCertExpiry is the duration certificates should be issued for @@ -1235,7 +1288,7 @@ type CAConfig struct { func (m *CAConfig) Reset() { *m = CAConfig{} } func (*CAConfig) ProtoMessage() {} -func (*CAConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{27} } +func (*CAConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{28} } // OrchestrationConfig defines cluster-level orchestration settings. type OrchestrationConfig struct { @@ -1246,7 +1299,7 @@ type OrchestrationConfig struct { func (m *OrchestrationConfig) Reset() { *m = OrchestrationConfig{} } func (*OrchestrationConfig) ProtoMessage() {} -func (*OrchestrationConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{28} } +func (*OrchestrationConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{29} } // TaskDefaults specifies default values for task creation. type TaskDefaults struct { @@ -1260,7 +1313,7 @@ type TaskDefaults struct { func (m *TaskDefaults) Reset() { *m = TaskDefaults{} } func (*TaskDefaults) ProtoMessage() {} -func (*TaskDefaults) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{29} } +func (*TaskDefaults) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{30} } // DispatcherConfig defines cluster-level dispatcher settings. type DispatcherConfig struct { @@ -1271,7 +1324,7 @@ type DispatcherConfig struct { func (m *DispatcherConfig) Reset() { *m = DispatcherConfig{} } func (*DispatcherConfig) ProtoMessage() {} -func (*DispatcherConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{30} } +func (*DispatcherConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{31} } // RaftConfig defines raft settings for the cluster. type RaftConfig struct { @@ -1293,7 +1346,7 @@ type RaftConfig struct { func (m *RaftConfig) Reset() { *m = RaftConfig{} } func (*RaftConfig) ProtoMessage() {} -func (*RaftConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{31} } +func (*RaftConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{32} } // Placement specifies task distribution constraints. type Placement struct { @@ -1303,7 +1356,7 @@ type Placement struct { func (m *Placement) Reset() { *m = Placement{} } func (*Placement) ProtoMessage() {} -func (*Placement) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{32} } +func (*Placement) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{33} } // JoinToken contains the join tokens for workers and managers. type JoinTokens struct { @@ -1315,7 +1368,7 @@ type JoinTokens struct { func (m *JoinTokens) Reset() { *m = JoinTokens{} } func (*JoinTokens) ProtoMessage() {} -func (*JoinTokens) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{33} } +func (*JoinTokens) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{34} } type RootCA struct { // CAKey is the root CA private key. @@ -1330,7 +1383,7 @@ type RootCA struct { func (m *RootCA) Reset() { *m = RootCA{} } func (*RootCA) ProtoMessage() {} -func (*RootCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{34} } +func (*RootCA) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{35} } type Certificate struct { Role NodeRole `protobuf:"varint,1,opt,name=role,proto3,enum=docker.swarmkit.v1.NodeRole" json:"role,omitempty"` @@ -1343,7 +1396,7 @@ type Certificate struct { func (m *Certificate) Reset() { *m = Certificate{} } func (*Certificate) ProtoMessage() {} -func (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{35} } +func (*Certificate) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{36} } // Symmetric keys to encrypt inter-agent communication. type EncryptionKey struct { @@ -1359,7 +1412,7 @@ type EncryptionKey struct { func (m *EncryptionKey) Reset() { *m = EncryptionKey{} } func (*EncryptionKey) ProtoMessage() {} -func (*EncryptionKey) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{36} } +func (*EncryptionKey) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{37} } // ManagerStatus provides informations about the state of a manager in the cluster. type ManagerStatus struct { @@ -1376,7 +1429,7 @@ type ManagerStatus struct { func (m *ManagerStatus) Reset() { *m = ManagerStatus{} } func (*ManagerStatus) ProtoMessage() {} -func (*ManagerStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{37} } +func (*ManagerStatus) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{38} } // SecretReference is the linkage between a service and a secret that it uses. type SecretReference struct { @@ -1395,20 +1448,43 @@ type SecretReference struct { func (m *SecretReference) Reset() { *m = SecretReference{} } func (*SecretReference) ProtoMessage() {} -func (*SecretReference) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{38} } +func (*SecretReference) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{39} } -// RemovedNode is a record for a node that has been removed from the swarm. -type RemovedNode struct { - // ID is the ID of the removed node. - ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +// BlacklistedCertificate is a record for a blacklisted certificate. It does not +// contain the certificate's CN, because these records are indexed by CN. +type BlacklistedCertificate struct { // Expiry is the latest known expiration time of a certificate that - // was issued to this node. - Expiry *docker_swarmkit_v1.Timestamp `protobuf:"bytes,2,opt,name=expiry" json:"expiry,omitempty"` -} - -func (m *RemovedNode) Reset() { *m = RemovedNode{} } -func (*RemovedNode) ProtoMessage() {} -func (*RemovedNode) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{39} } + // was issued for the given CN. + Expiry *docker_swarmkit_v1.Timestamp `protobuf:"bytes,1,opt,name=expiry" json:"expiry,omitempty"` +} + +func (m *BlacklistedCertificate) Reset() { *m = BlacklistedCertificate{} } +func (*BlacklistedCertificate) ProtoMessage() {} +func (*BlacklistedCertificate) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{40} } + +// HealthConfig holds configuration settings for the HEALTHCHECK feature. +type HealthConfig struct { + // Test is the test to perform to check that the container is healthy. + // An empty slice means to inherit the default. + // The options are: + // {} : inherit healthcheck + // {"NONE"} : disable healthcheck + // {"CMD", args...} : exec arguments directly + // {"CMD-SHELL", command} : run command with system's default shell + Test []string `protobuf:"bytes,1,rep,name=test" json:"test,omitempty"` + // Interval is the time to wait between checks. Zero means inherit. + Interval *docker_swarmkit_v11.Duration `protobuf:"bytes,2,opt,name=interval" json:"interval,omitempty"` + // Timeout is the time to wait before considering the check to have hung. + // Zero means inherit. + Timeout *docker_swarmkit_v11.Duration `protobuf:"bytes,3,opt,name=timeout" json:"timeout,omitempty"` + // Retries is the number of consecutive failures needed to consider a + // container as unhealthy. Zero means inherit. + Retries int32 `protobuf:"varint,4,opt,name=retries,proto3" json:"retries,omitempty"` +} + +func (m *HealthConfig) Reset() { *m = HealthConfig{} } +func (*HealthConfig) ProtoMessage() {} +func (*HealthConfig) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{41} } func init() { proto.RegisterType((*Version)(nil), "docker.swarmkit.v1.Version") @@ -1430,6 +1506,7 @@ func init() { proto.RegisterType((*UpdateConfig)(nil), "docker.swarmkit.v1.UpdateConfig") proto.RegisterType((*UpdateStatus)(nil), "docker.swarmkit.v1.UpdateStatus") proto.RegisterType((*ContainerStatus)(nil), "docker.swarmkit.v1.ContainerStatus") + proto.RegisterType((*PortStatus)(nil), "docker.swarmkit.v1.PortStatus") proto.RegisterType((*TaskStatus)(nil), "docker.swarmkit.v1.TaskStatus") proto.RegisterType((*NetworkAttachmentConfig)(nil), "docker.swarmkit.v1.NetworkAttachmentConfig") proto.RegisterType((*IPAMConfig)(nil), "docker.swarmkit.v1.IPAMConfig") @@ -1455,7 +1532,8 @@ func init() { proto.RegisterType((*EncryptionKey)(nil), "docker.swarmkit.v1.EncryptionKey") proto.RegisterType((*ManagerStatus)(nil), "docker.swarmkit.v1.ManagerStatus") proto.RegisterType((*SecretReference)(nil), "docker.swarmkit.v1.SecretReference") - proto.RegisterType((*RemovedNode)(nil), "docker.swarmkit.v1.RemovedNode") + proto.RegisterType((*BlacklistedCertificate)(nil), "docker.swarmkit.v1.BlacklistedCertificate") + proto.RegisterType((*HealthConfig)(nil), "docker.swarmkit.v1.HealthConfig") proto.RegisterEnum("docker.swarmkit.v1.TaskState", TaskState_name, TaskState_value) proto.RegisterEnum("docker.swarmkit.v1.NodeRole", NodeRole_name, NodeRole_value) proto.RegisterEnum("docker.swarmkit.v1.RaftMemberStatus_Reachability", RaftMemberStatus_Reachability_name, RaftMemberStatus_Reachability_value) @@ -1467,6 +1545,7 @@ func init() { proto.RegisterEnum("docker.swarmkit.v1.UpdateStatus_UpdateState", UpdateStatus_UpdateState_name, UpdateStatus_UpdateState_value) proto.RegisterEnum("docker.swarmkit.v1.IPAMConfig_AddressFamily", IPAMConfig_AddressFamily_name, IPAMConfig_AddressFamily_value) proto.RegisterEnum("docker.swarmkit.v1.PortConfig_Protocol", PortConfig_Protocol_name, PortConfig_Protocol_value) + proto.RegisterEnum("docker.swarmkit.v1.PortConfig_PublishMode", PortConfig_PublishMode_name, PortConfig_PublishMode_value) proto.RegisterEnum("docker.swarmkit.v1.IssuanceStatus_State", IssuanceStatus_State_name, IssuanceStatus_State_value) proto.RegisterEnum("docker.swarmkit.v1.ExternalCA_CAProtocol", ExternalCA_CAProtocol_name, ExternalCA_CAProtocol_value) proto.RegisterEnum("docker.swarmkit.v1.EncryptionKey_Algorithm", EncryptionKey_Algorithm_name, EncryptionKey_Algorithm_value) @@ -1759,16 +1838,34 @@ func (m *ContainerStatus) Copy() *ContainerStatus { return o } +func (m *PortStatus) Copy() *PortStatus { + if m == nil { + return nil + } + + o := &PortStatus{} + + if m.Ports != nil { + o.Ports = make([]*PortConfig, 0, len(m.Ports)) + for _, v := range m.Ports { + o.Ports = append(o.Ports, v.Copy()) + } + } + + return o +} + func (m *TaskStatus) Copy() *TaskStatus { if m == nil { return nil } o := &TaskStatus{ - Timestamp: m.Timestamp.Copy(), - State: m.State, - Message: m.Message, - Err: m.Err, + Timestamp: m.Timestamp.Copy(), + State: m.State, + Message: m.Message, + Err: m.Err, + PortStatus: m.PortStatus.Copy(), } switch m.RuntimeStatus.(type) { @@ -1837,6 +1934,7 @@ func (m *PortConfig) Copy() *PortConfig { Protocol: m.Protocol, TargetPort: m.TargetPort, PublishedPort: m.PublishedPort, + PublishMode: m.PublishMode, } return o @@ -2158,19 +2256,37 @@ func (m *SecretReference) Copy() *SecretReference { return o } -func (m *RemovedNode) Copy() *RemovedNode { +func (m *BlacklistedCertificate) Copy() *BlacklistedCertificate { if m == nil { return nil } - o := &RemovedNode{ - ID: m.ID, + o := &BlacklistedCertificate{ Expiry: m.Expiry.Copy(), } return o } +func (m *HealthConfig) Copy() *HealthConfig { + if m == nil { + return nil + } + + o := &HealthConfig{ + Interval: m.Interval.Copy(), + Timeout: m.Timeout.Copy(), + Retries: m.Retries, + } + + if m.Test != nil { + o.Test = make([]string, 0, len(m.Test)) + o.Test = append(o.Test, m.Test...) + } + + return o +} + func (this *Version) GoString() string { if this == nil { return "nil" @@ -2461,11 +2577,23 @@ func (this *ContainerStatus) GoString() string { s = append(s, "}") return strings.Join(s, "") } +func (this *PortStatus) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 5) + s = append(s, "&api.PortStatus{") + if this.Ports != nil { + s = append(s, "Ports: "+fmt.Sprintf("%#v", this.Ports)+",\n") + } + s = append(s, "}") + return strings.Join(s, "") +} func (this *TaskStatus) GoString() string { if this == nil { return "nil" } - s := make([]string, 0, 9) + s := make([]string, 0, 10) s = append(s, "&api.TaskStatus{") if this.Timestamp != nil { s = append(s, "Timestamp: "+fmt.Sprintf("%#v", this.Timestamp)+",\n") @@ -2476,6 +2604,9 @@ func (this *TaskStatus) GoString() string { if this.RuntimeStatus != nil { s = append(s, "RuntimeStatus: "+fmt.Sprintf("%#v", this.RuntimeStatus)+",\n") } + if this.PortStatus != nil { + s = append(s, "PortStatus: "+fmt.Sprintf("%#v", this.PortStatus)+",\n") + } s = append(s, "}") return strings.Join(s, "") } @@ -2529,12 +2660,13 @@ func (this *PortConfig) GoString() string { if this == nil { return "nil" } - s := make([]string, 0, 8) + s := make([]string, 0, 9) s = append(s, "&api.PortConfig{") s = append(s, "Name: "+fmt.Sprintf("%#v", this.Name)+",\n") s = append(s, "Protocol: "+fmt.Sprintf("%#v", this.Protocol)+",\n") s = append(s, "TargetPort: "+fmt.Sprintf("%#v", this.TargetPort)+",\n") s = append(s, "PublishedPort: "+fmt.Sprintf("%#v", this.PublishedPort)+",\n") + s = append(s, "PublishMode: "+fmt.Sprintf("%#v", this.PublishMode)+",\n") s = append(s, "}") return strings.Join(s, "") } @@ -2822,19 +2954,35 @@ func (this *SecretReference) GoString() string { s = append(s, "}") return strings.Join(s, "") } -func (this *RemovedNode) GoString() string { +func (this *BlacklistedCertificate) GoString() string { if this == nil { return "nil" } - s := make([]string, 0, 6) - s = append(s, "&api.RemovedNode{") - s = append(s, "ID: "+fmt.Sprintf("%#v", this.ID)+",\n") + s := make([]string, 0, 5) + s = append(s, "&api.BlacklistedCertificate{") if this.Expiry != nil { s = append(s, "Expiry: "+fmt.Sprintf("%#v", this.Expiry)+",\n") } s = append(s, "}") return strings.Join(s, "") } +func (this *HealthConfig) GoString() string { + if this == nil { + return "nil" + } + s := make([]string, 0, 8) + s = append(s, "&api.HealthConfig{") + s = append(s, "Test: "+fmt.Sprintf("%#v", this.Test)+",\n") + if this.Interval != nil { + s = append(s, "Interval: "+fmt.Sprintf("%#v", this.Interval)+",\n") + } + if this.Timeout != nil { + s = append(s, "Timeout: "+fmt.Sprintf("%#v", this.Timeout)+",\n") + } + s = append(s, "Retries: "+fmt.Sprintf("%#v", this.Retries)+",\n") + s = append(s, "}") + return strings.Join(s, "") +} func valueToGoStringTypes(v interface{}, typ string) string { rv := reflect.ValueOf(v) if rv.IsNil() { @@ -3613,6 +3761,36 @@ func (m *ContainerStatus) MarshalTo(data []byte) (int, error) { return i, nil } +func (m *PortStatus) Marshal() (data []byte, err error) { + size := m.Size() + data = make([]byte, size) + n, err := m.MarshalTo(data) + if err != nil { + return nil, err + } + return data[:n], nil +} + +func (m *PortStatus) MarshalTo(data []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Ports) > 0 { + for _, msg := range m.Ports { + data[i] = 0xa + i++ + i = encodeVarintTypes(data, i, uint64(msg.Size())) + n, err := msg.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n + } + } + return i, nil +} + func (m *TaskStatus) Marshal() (data []byte, err error) { size := m.Size() data = make([]byte, size) @@ -3662,6 +3840,16 @@ func (m *TaskStatus) MarshalTo(data []byte) (int, error) { } i += nn17 } + if m.PortStatus != nil { + data[i] = 0x32 + i++ + i = encodeVarintTypes(data, i, uint64(m.PortStatus.Size())) + n18, err := m.PortStatus.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n18 + } return i, nil } @@ -3671,11 +3859,11 @@ func (m *TaskStatus_Container) MarshalTo(data []byte) (int, error) { data[i] = 0x2a i++ i = encodeVarintTypes(data, i, uint64(m.Container.Size())) - n18, err := m.Container.MarshalTo(data[i:]) + n19, err := m.Container.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n18 + i += n19 } return i, nil } @@ -3827,6 +4015,11 @@ func (m *PortConfig) MarshalTo(data []byte) (int, error) { i++ i = encodeVarintTypes(data, i, uint64(m.PublishedPort)) } + if m.PublishMode != 0 { + data[i] = 0x28 + i++ + i = encodeVarintTypes(data, i, uint64(m.PublishMode)) + } return i, nil } @@ -3890,11 +4083,11 @@ func (m *IPAMOptions) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintTypes(data, i, uint64(m.Driver.Size())) - n19, err := m.Driver.MarshalTo(data[i:]) + n20, err := m.Driver.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n19 + i += n20 } if len(m.Configs) > 0 { for _, msg := range m.Configs { @@ -3960,11 +4153,11 @@ func (m *WeightedPeer) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintTypes(data, i, uint64(m.Peer.Size())) - n20, err := m.Peer.MarshalTo(data[i:]) + n21, err := m.Peer.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n20 + i += n21 } if m.Weight != 0 { data[i] = 0x10 @@ -4067,11 +4260,11 @@ func (m *AcceptancePolicy_RoleAdmissionPolicy) MarshalTo(data []byte) (int, erro data[i] = 0x1a i++ i = encodeVarintTypes(data, i, uint64(m.Secret.Size())) - n21, err := m.Secret.MarshalTo(data[i:]) + n22, err := m.Secret.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n21 + i += n22 } return i, nil } @@ -4171,11 +4364,11 @@ func (m *CAConfig) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintTypes(data, i, uint64(m.NodeCertExpiry.Size())) - n22, err := m.NodeCertExpiry.MarshalTo(data[i:]) + n23, err := m.NodeCertExpiry.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n22 + i += n23 } if len(m.ExternalCAs) > 0 { for _, msg := range m.ExternalCAs { @@ -4234,11 +4427,11 @@ func (m *TaskDefaults) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintTypes(data, i, uint64(m.LogDriver.Size())) - n23, err := m.LogDriver.MarshalTo(data[i:]) + n24, err := m.LogDriver.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n23 + i += n24 } return i, nil } @@ -4262,11 +4455,11 @@ func (m *DispatcherConfig) MarshalTo(data []byte) (int, error) { data[i] = 0xa i++ i = encodeVarintTypes(data, i, uint64(m.HeartbeatPeriod.Size())) - n24, err := m.HeartbeatPeriod.MarshalTo(data[i:]) + n25, err := m.HeartbeatPeriod.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n24 + i += n25 } return i, nil } @@ -4413,11 +4606,11 @@ func (m *RootCA) MarshalTo(data []byte) (int, error) { data[i] = 0x22 i++ i = encodeVarintTypes(data, i, uint64(m.JoinTokens.Size())) - n25, err := m.JoinTokens.MarshalTo(data[i:]) + n26, err := m.JoinTokens.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n25 + i += n26 return i, nil } @@ -4450,11 +4643,11 @@ func (m *Certificate) MarshalTo(data []byte) (int, error) { data[i] = 0x1a i++ i = encodeVarintTypes(data, i, uint64(m.Status.Size())) - n26, err := m.Status.MarshalTo(data[i:]) + n27, err := m.Status.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n26 + i += n27 if len(m.Certificate) > 0 { data[i] = 0x22 i++ @@ -4595,7 +4788,7 @@ func (m *SecretReference) MarshalTo(data []byte) (int, error) { return i, nil } -func (m *RemovedNode) Marshal() (data []byte, err error) { +func (m *BlacklistedCertificate) Marshal() (data []byte, err error) { size := m.Size() data = make([]byte, size) n, err := m.MarshalTo(data) @@ -4605,26 +4798,78 @@ func (m *RemovedNode) Marshal() (data []byte, err error) { return data[:n], nil } -func (m *RemovedNode) MarshalTo(data []byte) (int, error) { +func (m *BlacklistedCertificate) MarshalTo(data []byte) (int, error) { var i int _ = i var l int _ = l - if len(m.ID) > 0 { + if m.Expiry != nil { data[i] = 0xa i++ - i = encodeVarintTypes(data, i, uint64(len(m.ID))) - i += copy(data[i:], m.ID) + i = encodeVarintTypes(data, i, uint64(m.Expiry.Size())) + n28, err := m.Expiry.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n28 } - if m.Expiry != nil { + return i, nil +} + +func (m *HealthConfig) Marshal() (data []byte, err error) { + size := m.Size() + data = make([]byte, size) + n, err := m.MarshalTo(data) + if err != nil { + return nil, err + } + return data[:n], nil +} + +func (m *HealthConfig) MarshalTo(data []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Test) > 0 { + for _, s := range m.Test { + data[i] = 0xa + i++ + l = len(s) + for l >= 1<<7 { + data[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + data[i] = uint8(l) + i++ + i += copy(data[i:], s) + } + } + if m.Interval != nil { data[i] = 0x12 i++ - i = encodeVarintTypes(data, i, uint64(m.Expiry.Size())) - n27, err := m.Expiry.MarshalTo(data[i:]) + i = encodeVarintTypes(data, i, uint64(m.Interval.Size())) + n29, err := m.Interval.MarshalTo(data[i:]) + if err != nil { + return 0, err + } + i += n29 + } + if m.Timeout != nil { + data[i] = 0x1a + i++ + i = encodeVarintTypes(data, i, uint64(m.Timeout.Size())) + n30, err := m.Timeout.MarshalTo(data[i:]) if err != nil { return 0, err } - i += n27 + i += n30 + } + if m.Retries != 0 { + data[i] = 0x20 + i++ + i = encodeVarintTypes(data, i, uint64(m.Retries)) } return i, nil } @@ -4975,6 +5220,18 @@ func (m *ContainerStatus) Size() (n int) { return n } +func (m *PortStatus) Size() (n int) { + var l int + _ = l + if len(m.Ports) > 0 { + for _, e := range m.Ports { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + func (m *TaskStatus) Size() (n int) { var l int _ = l @@ -4996,6 +5253,10 @@ func (m *TaskStatus) Size() (n int) { if m.RuntimeStatus != nil { n += m.RuntimeStatus.Size() } + if m.PortStatus != nil { + l = m.PortStatus.Size() + n += 1 + l + sovTypes(uint64(l)) + } return n } @@ -5075,6 +5336,9 @@ func (m *PortConfig) Size() (n int) { if m.PublishedPort != 0 { n += 1 + sovTypes(uint64(m.PublishedPort)) } + if m.PublishMode != 0 { + n += 1 + sovTypes(uint64(m.PublishMode)) + } return n } @@ -5410,13 +5674,9 @@ func (m *SecretReference) Size() (n int) { return n } -func (m *RemovedNode) Size() (n int) { +func (m *BlacklistedCertificate) Size() (n int) { var l int _ = l - l = len(m.ID) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } if m.Expiry != nil { l = m.Expiry.Size() n += 1 + l + sovTypes(uint64(l)) @@ -5424,6 +5684,29 @@ func (m *RemovedNode) Size() (n int) { return n } +func (m *HealthConfig) Size() (n int) { + var l int + _ = l + if len(m.Test) > 0 { + for _, s := range m.Test { + l = len(s) + n += 1 + l + sovTypes(uint64(l)) + } + } + if m.Interval != nil { + l = m.Interval.Size() + n += 1 + l + sovTypes(uint64(l)) + } + if m.Timeout != nil { + l = m.Timeout.Size() + n += 1 + l + sovTypes(uint64(l)) + } + if m.Retries != 0 { + n += 1 + sovTypes(uint64(m.Retries)) + } + return n +} + func sovTypes(x uint64) (n int) { for { n++ @@ -5691,6 +5974,16 @@ func (this *ContainerStatus) String() string { }, "") return s } +func (this *PortStatus) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PortStatus{`, + `Ports:` + strings.Replace(fmt.Sprintf("%v", this.Ports), "PortConfig", "PortConfig", 1) + `,`, + `}`, + }, "") + return s +} func (this *TaskStatus) String() string { if this == nil { return "nil" @@ -5701,6 +5994,7 @@ func (this *TaskStatus) String() string { `Message:` + fmt.Sprintf("%v", this.Message) + `,`, `Err:` + fmt.Sprintf("%v", this.Err) + `,`, `RuntimeStatus:` + fmt.Sprintf("%v", this.RuntimeStatus) + `,`, + `PortStatus:` + strings.Replace(fmt.Sprintf("%v", this.PortStatus), "PortStatus", "PortStatus", 1) + `,`, `}`, }, "") return s @@ -5760,6 +6054,7 @@ func (this *PortConfig) String() string { `Protocol:` + fmt.Sprintf("%v", this.Protocol) + `,`, `TargetPort:` + fmt.Sprintf("%v", this.TargetPort) + `,`, `PublishedPort:` + fmt.Sprintf("%v", this.PublishedPort) + `,`, + `PublishMode:` + fmt.Sprintf("%v", this.PublishMode) + `,`, `}`, }, "") return s @@ -6026,17 +6321,29 @@ func (this *SecretReference) String() string { }, "") return s } -func (this *RemovedNode) String() string { +func (this *BlacklistedCertificate) String() string { if this == nil { return "nil" } - s := strings.Join([]string{`&RemovedNode{`, - `ID:` + fmt.Sprintf("%v", this.ID) + `,`, + s := strings.Join([]string{`&BlacklistedCertificate{`, `Expiry:` + strings.Replace(fmt.Sprintf("%v", this.Expiry), "Timestamp", "docker_swarmkit_v1.Timestamp", 1) + `,`, `}`, }, "") return s } +func (this *HealthConfig) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&HealthConfig{`, + `Test:` + fmt.Sprintf("%v", this.Test) + `,`, + `Interval:` + strings.Replace(fmt.Sprintf("%v", this.Interval), "Duration", "docker_swarmkit_v11.Duration", 1) + `,`, + `Timeout:` + strings.Replace(fmt.Sprintf("%v", this.Timeout), "Duration", "docker_swarmkit_v11.Duration", 1) + `,`, + `Retries:` + fmt.Sprintf("%v", this.Retries) + `,`, + `}`, + }, "") + return s +} func valueToStringTypes(v interface{}) string { rv := reflect.ValueOf(v) if rv.IsNil() { @@ -8650,6 +8957,87 @@ func (m *ContainerStatus) Unmarshal(data []byte) error { } return nil } +func (m *PortStatus) Unmarshal(data []byte) error { + l := len(data) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PortStatus: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PortStatus: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ports", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Ports = append(m.Ports, &PortConfig{}) + if err := m.Ports[len(m.Ports)-1].Unmarshal(data[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(data[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *TaskStatus) Unmarshal(data []byte) error { l := len(data) iNdEx := 0 @@ -8821,6 +9209,39 @@ func (m *TaskStatus) Unmarshal(data []byte) error { } m.RuntimeStatus = &TaskStatus_Container{v} iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortStatus", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.PortStatus == nil { + m.PortStatus = &PortStatus{} + } + if err := m.PortStatus.Unmarshal(data[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(data[iNdEx:]) @@ -9366,6 +9787,25 @@ func (m *PortConfig) Unmarshal(data []byte) error { break } } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PublishMode", wireType) + } + m.PublishMode = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + m.PublishMode |= (PortConfig_PublishMode(b) & 0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTypes(data[iNdEx:]) @@ -12014,7 +12454,7 @@ func (m *SecretReference) Unmarshal(data []byte) error { } return nil } -func (m *RemovedNode) Unmarshal(data []byte) error { +func (m *BlacklistedCertificate) Unmarshal(data []byte) error { l := len(data) iNdEx := 0 for iNdEx < l { @@ -12037,15 +12477,98 @@ func (m *RemovedNode) Unmarshal(data []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: RemovedNode: wiretype end group for non-group") + return fmt.Errorf("proto: BlacklistedCertificate: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: RemovedNode: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: BlacklistedCertificate: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Expiry", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Expiry == nil { + m.Expiry = &docker_swarmkit_v1.Timestamp{} + } + if err := m.Expiry.Unmarshal(data[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(data[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HealthConfig) Unmarshal(data []byte) error { + l := len(data) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HealthConfig: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HealthConfig: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Test", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -12070,11 +12593,11 @@ func (m *RemovedNode) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ID = string(data[iNdEx:postIndex]) + m.Test = append(m.Test, string(data[iNdEx:postIndex])) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Expiry", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Interval", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -12098,13 +12621,65 @@ func (m *RemovedNode) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Expiry == nil { - m.Expiry = &docker_swarmkit_v1.Timestamp{} + if m.Interval == nil { + m.Interval = &docker_swarmkit_v11.Duration{} } - if err := m.Expiry.Unmarshal(data[iNdEx:postIndex]); err != nil { + if err := m.Interval.Unmarshal(data[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Timeout", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Timeout == nil { + m.Timeout = &docker_swarmkit_v11.Duration{} + } + if err := m.Timeout.Unmarshal(data[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Retries", wireType) + } + m.Retries = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + m.Retries |= (int32(b) & 0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTypes(data[iNdEx:]) @@ -12234,233 +12809,242 @@ var ( func init() { proto.RegisterFile("types.proto", fileDescriptorTypes) } var fileDescriptorTypes = []byte{ - // 3635 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x59, 0xcd, 0x6f, 0x23, 0x47, - 0x76, 0x17, 0x3f, 0x45, 0x3e, 0x52, 0x52, 0x4f, 0xcd, 0xec, 0x58, 0x43, 0x8f, 0x25, 0xba, 0xc7, - 0xb3, 0x1e, 0x7b, 0x1d, 0xda, 0x96, 0x77, 0x8d, 0x59, 0xcf, 0x66, 0xed, 0x16, 0x49, 0xcd, 0x70, - 0x47, 0xa2, 0x88, 0x22, 0x39, 0x03, 0x23, 0x41, 0x88, 0x52, 0x77, 0x89, 0x6a, 0xab, 0xd9, 0xc5, - 0x74, 0x17, 0xa5, 0x61, 0x82, 0x00, 0x93, 0x1c, 0x92, 0x40, 0xa7, 0xdc, 0x03, 0x61, 0x11, 0x24, - 0xc8, 0x2d, 0xe7, 0x00, 0x39, 0xf9, 0xe8, 0xe3, 0x06, 0x01, 0x82, 0xc5, 0x06, 0x19, 0xc4, 0xca, - 0x3f, 0xb0, 0x40, 0x10, 0xec, 0x21, 0x39, 0x04, 0xf5, 0xd1, 0xcd, 0x8f, 0xe1, 0xc8, 0x72, 0xd6, - 0x27, 0xb2, 0x5e, 0xfd, 0xde, 0xab, 0x57, 0x55, 0xaf, 0x5e, 0xfd, 0x5e, 0x35, 0x14, 0xf8, 0x78, - 0x48, 0xc3, 0xca, 0x30, 0x60, 0x9c, 0x21, 0xe4, 0x30, 0xfb, 0x98, 0x06, 0x95, 0xf0, 0x94, 0x04, - 0x83, 0x63, 0x97, 0x57, 0x4e, 0x3e, 0x2c, 0xdd, 0xe2, 0xee, 0x80, 0x86, 0x9c, 0x0c, 0x86, 0xef, - 0xc7, 0xff, 0x14, 0xbc, 0xf4, 0x9a, 0x33, 0x0a, 0x08, 0x77, 0x99, 0xff, 0x7e, 0xf4, 0x47, 0x77, - 0xdc, 0xe8, 0xb3, 0x3e, 0x93, 0x7f, 0xdf, 0x17, 0xff, 0x94, 0xd4, 0xdc, 0x84, 0xe5, 0x27, 0x34, - 0x08, 0x5d, 0xe6, 0xa3, 0x1b, 0x90, 0x71, 0x7d, 0x87, 0x3e, 0x5b, 0x4f, 0x94, 0x13, 0xf7, 0xd2, - 0x58, 0x35, 0xcc, 0xbf, 0x49, 0x40, 0xc1, 0xf2, 0x7d, 0xc6, 0xa5, 0xad, 0x10, 0x21, 0x48, 0xfb, - 0x64, 0x40, 0x25, 0x28, 0x8f, 0xe5, 0x7f, 0x54, 0x85, 0xac, 0x47, 0x0e, 0xa8, 0x17, 0xae, 0x27, - 0xcb, 0xa9, 0x7b, 0x85, 0xad, 0x1f, 0x54, 0x5e, 0xf6, 0xb9, 0x32, 0x65, 0xa4, 0xb2, 0x2b, 0xd1, - 0x75, 0x9f, 0x07, 0x63, 0xac, 0x55, 0x4b, 0x3f, 0x86, 0xc2, 0x94, 0x18, 0x19, 0x90, 0x3a, 0xa6, - 0x63, 0x3d, 0x8c, 0xf8, 0x2b, 0xfc, 0x3b, 0x21, 0xde, 0x88, 0xae, 0x27, 0xa5, 0x4c, 0x35, 0x3e, - 0x49, 0xde, 0x4f, 0x98, 0x9f, 0x43, 0x1e, 0xd3, 0x90, 0x8d, 0x02, 0x9b, 0x86, 0xe8, 0x1d, 0xc8, - 0xfb, 0xc4, 0x67, 0x3d, 0x7b, 0x38, 0x0a, 0xa5, 0x7a, 0x6a, 0xbb, 0x78, 0xf1, 0x62, 0x33, 0xd7, - 0x24, 0x3e, 0xab, 0xb6, 0xba, 0x21, 0xce, 0x89, 0xee, 0xea, 0x70, 0x14, 0xa2, 0x37, 0xa1, 0x38, - 0xa0, 0x03, 0x16, 0x8c, 0x7b, 0x07, 0x63, 0x4e, 0x43, 0x69, 0x38, 0x85, 0x0b, 0x4a, 0xb6, 0x2d, - 0x44, 0xe6, 0x5f, 0x25, 0xe0, 0x46, 0x64, 0x1b, 0xd3, 0x3f, 0x1c, 0xb9, 0x01, 0x1d, 0x50, 0x9f, - 0x87, 0xe8, 0x47, 0x90, 0xf5, 0xdc, 0x81, 0xcb, 0xd5, 0x18, 0x85, 0xad, 0x37, 0x16, 0xcd, 0x39, - 0xf6, 0x0a, 0x6b, 0x30, 0xb2, 0xa0, 0x18, 0xd0, 0x90, 0x06, 0x27, 0x6a, 0x25, 0xe4, 0x90, 0xdf, - 0xa8, 0x3c, 0xa3, 0x62, 0xee, 0x40, 0xae, 0xe5, 0x11, 0x7e, 0xc8, 0x82, 0x01, 0x32, 0xa1, 0x48, - 0x02, 0xfb, 0xc8, 0xe5, 0xd4, 0xe6, 0xa3, 0x20, 0xda, 0x95, 0x19, 0x19, 0xba, 0x09, 0x49, 0xa6, - 0x06, 0xca, 0x6f, 0x67, 0x2f, 0x5e, 0x6c, 0x26, 0xf7, 0xdb, 0x38, 0xc9, 0x42, 0xf3, 0x01, 0x5c, - 0x6b, 0x79, 0xa3, 0xbe, 0xeb, 0xd7, 0x68, 0x68, 0x07, 0xee, 0x50, 0x58, 0x17, 0xdb, 0x2b, 0x82, - 0x2f, 0xda, 0x5e, 0xf1, 0x3f, 0xde, 0xf2, 0xe4, 0x64, 0xcb, 0xcd, 0xbf, 0x48, 0xc2, 0xb5, 0xba, - 0xdf, 0x77, 0x7d, 0x3a, 0xad, 0x7d, 0x17, 0x56, 0xa9, 0x14, 0xf6, 0x4e, 0x54, 0x50, 0x69, 0x3b, - 0x2b, 0x4a, 0x1a, 0x45, 0x5a, 0x63, 0x2e, 0x5e, 0x3e, 0x5c, 0x34, 0xfd, 0x97, 0xac, 0x2f, 0x8a, - 0x1a, 0x54, 0x87, 0xe5, 0xa1, 0x9c, 0x44, 0xb8, 0x9e, 0x92, 0xb6, 0xee, 0x2e, 0xb2, 0xf5, 0xd2, - 0x3c, 0xb7, 0xd3, 0x5f, 0xbd, 0xd8, 0x5c, 0xc2, 0x91, 0xee, 0x6f, 0x13, 0x7c, 0xff, 0x99, 0x80, - 0xb5, 0x26, 0x73, 0x66, 0xd6, 0xa1, 0x04, 0xb9, 0x23, 0x16, 0xf2, 0xa9, 0x83, 0x12, 0xb7, 0xd1, - 0x7d, 0xc8, 0x0d, 0xf5, 0xf6, 0xe9, 0xdd, 0xbf, 0xbd, 0xd8, 0x65, 0x85, 0xc1, 0x31, 0x1a, 0x3d, - 0x80, 0x7c, 0x10, 0xc5, 0xc4, 0x7a, 0xea, 0x2a, 0x81, 0x33, 0xc1, 0xa3, 0xdf, 0x85, 0xac, 0xda, - 0x84, 0xf5, 0xb4, 0xd4, 0xbc, 0x7b, 0xa5, 0x35, 0xc7, 0x5a, 0xc9, 0xfc, 0x65, 0x02, 0x0c, 0x4c, - 0x0e, 0xf9, 0x1e, 0x1d, 0x1c, 0xd0, 0xa0, 0xcd, 0x09, 0x1f, 0x85, 0xe8, 0x26, 0x64, 0x3d, 0x4a, - 0x1c, 0x1a, 0xc8, 0x49, 0xe6, 0xb0, 0x6e, 0xa1, 0xae, 0x08, 0x72, 0x62, 0x1f, 0x91, 0x03, 0xd7, - 0x73, 0xf9, 0x58, 0x4e, 0x73, 0x75, 0xf1, 0x2e, 0xcf, 0xdb, 0xac, 0xe0, 0x29, 0x45, 0x3c, 0x63, - 0x06, 0xad, 0xc3, 0xf2, 0x80, 0x86, 0x21, 0xe9, 0x53, 0x39, 0xfb, 0x3c, 0x8e, 0x9a, 0xe6, 0x03, - 0x28, 0x4e, 0xeb, 0xa1, 0x02, 0x2c, 0x77, 0x9b, 0x8f, 0x9b, 0xfb, 0x4f, 0x9b, 0xc6, 0x12, 0x5a, - 0x83, 0x42, 0xb7, 0x89, 0xeb, 0x56, 0xf5, 0x91, 0xb5, 0xbd, 0x5b, 0x37, 0x12, 0x68, 0x05, 0xf2, - 0x93, 0x66, 0xd2, 0xfc, 0x79, 0x02, 0x40, 0x6c, 0xa0, 0x9e, 0xd4, 0x27, 0x90, 0x09, 0x39, 0xe1, - 0x6a, 0xe3, 0x56, 0xb7, 0xde, 0x5a, 0xe4, 0xf5, 0x04, 0x5e, 0x11, 0x3f, 0x14, 0x2b, 0x95, 0x69, - 0x0f, 0x93, 0xf3, 0x1e, 0x66, 0x24, 0x72, 0xd6, 0xb5, 0x1c, 0xa4, 0x6b, 0xe2, 0x5f, 0x02, 0xe5, - 0x21, 0x83, 0xeb, 0x56, 0xed, 0x73, 0x23, 0x89, 0x0c, 0x28, 0xd6, 0x1a, 0xed, 0xea, 0x7e, 0xb3, - 0x59, 0xaf, 0x76, 0xea, 0x35, 0x23, 0x65, 0xde, 0x85, 0x4c, 0x63, 0x40, 0xfa, 0x14, 0xdd, 0x16, - 0x11, 0x70, 0x48, 0x03, 0xea, 0xdb, 0x51, 0x60, 0x4d, 0x04, 0xe6, 0x2f, 0xf2, 0x90, 0xd9, 0x63, - 0x23, 0x9f, 0xa3, 0xad, 0xa9, 0x53, 0xbc, 0xba, 0xb5, 0xb1, 0x68, 0x0a, 0x12, 0x58, 0xe9, 0x8c, - 0x87, 0x54, 0x9f, 0xf2, 0x9b, 0x90, 0x55, 0xb1, 0xa2, 0x5d, 0xd7, 0x2d, 0x21, 0xe7, 0x24, 0xe8, - 0x53, 0xae, 0x17, 0x5d, 0xb7, 0xd0, 0x3d, 0xc8, 0x05, 0x94, 0x38, 0xcc, 0xf7, 0xc6, 0x32, 0xa4, - 0x72, 0x2a, 0xcd, 0x62, 0x4a, 0x9c, 0x7d, 0xdf, 0x1b, 0xe3, 0xb8, 0x17, 0x3d, 0x82, 0xe2, 0x81, - 0xeb, 0x3b, 0x3d, 0x36, 0x54, 0x39, 0x2f, 0xf3, 0xea, 0x00, 0x54, 0x5e, 0x6d, 0xbb, 0xbe, 0xb3, - 0xaf, 0xc0, 0xb8, 0x70, 0x30, 0x69, 0xa0, 0x26, 0xac, 0x9e, 0x30, 0x6f, 0x34, 0xa0, 0xb1, 0xad, - 0xac, 0xb4, 0xf5, 0xf6, 0xab, 0x6d, 0x3d, 0x91, 0xf8, 0xc8, 0xda, 0xca, 0xc9, 0x74, 0x13, 0x3d, - 0x86, 0x15, 0x3e, 0x18, 0x1e, 0x86, 0xb1, 0xb9, 0x65, 0x69, 0xee, 0xfb, 0x97, 0x2c, 0x98, 0x80, - 0x47, 0xd6, 0x8a, 0x7c, 0xaa, 0x55, 0xfa, 0xb3, 0x14, 0x14, 0xa6, 0x3c, 0x47, 0x6d, 0x28, 0x0c, - 0x03, 0x36, 0x24, 0x7d, 0x99, 0xb7, 0xf5, 0x5e, 0x7c, 0x78, 0xa5, 0x59, 0x57, 0x5a, 0x13, 0x45, - 0x3c, 0x6d, 0xc5, 0x3c, 0x4f, 0x42, 0x61, 0xaa, 0x13, 0xbd, 0x0b, 0x39, 0xdc, 0xc2, 0x8d, 0x27, - 0x56, 0xa7, 0x6e, 0x2c, 0x95, 0x6e, 0x9f, 0x9d, 0x97, 0xd7, 0xa5, 0xb5, 0x69, 0x03, 0xad, 0xc0, - 0x3d, 0x11, 0xa1, 0x77, 0x0f, 0x96, 0x23, 0x68, 0xa2, 0xf4, 0xfa, 0xd9, 0x79, 0xf9, 0xb5, 0x79, - 0xe8, 0x14, 0x12, 0xb7, 0x1f, 0x59, 0xb8, 0x5e, 0x33, 0x92, 0x8b, 0x91, 0xb8, 0x7d, 0x44, 0x02, - 0xea, 0xa0, 0xef, 0x43, 0x56, 0x03, 0x53, 0xa5, 0xd2, 0xd9, 0x79, 0xf9, 0xe6, 0x3c, 0x70, 0x82, - 0xc3, 0xed, 0x5d, 0xeb, 0x49, 0xdd, 0x48, 0x2f, 0xc6, 0xe1, 0xb6, 0x47, 0x4e, 0x28, 0x7a, 0x0b, - 0x32, 0x0a, 0x96, 0x29, 0xdd, 0x3a, 0x3b, 0x2f, 0x7f, 0xef, 0x25, 0x73, 0x02, 0x55, 0x5a, 0xff, - 0xcb, 0xbf, 0xdd, 0x58, 0xfa, 0xa7, 0xbf, 0xdb, 0x30, 0xe6, 0xbb, 0x4b, 0xff, 0x9b, 0x80, 0x95, - 0x99, 0x2d, 0x47, 0x26, 0x64, 0x7d, 0x66, 0xb3, 0xa1, 0x4a, 0xe7, 0xb9, 0x6d, 0xb8, 0x78, 0xb1, - 0x99, 0x6d, 0xb2, 0x2a, 0x1b, 0x8e, 0xb1, 0xee, 0x41, 0x8f, 0xe7, 0x2e, 0xa4, 0x8f, 0xae, 0x18, - 0x4f, 0x0b, 0xaf, 0xa4, 0x4f, 0x61, 0xc5, 0x09, 0xdc, 0x13, 0x1a, 0xf4, 0x6c, 0xe6, 0x1f, 0xba, - 0x7d, 0x9d, 0xaa, 0x4b, 0x8b, 0x6c, 0xd6, 0x24, 0x10, 0x17, 0x95, 0x42, 0x55, 0xe2, 0x7f, 0x8b, - 0xcb, 0xa8, 0xf4, 0x04, 0x8a, 0xd3, 0x11, 0x8a, 0xde, 0x00, 0x08, 0xdd, 0x3f, 0xa2, 0x9a, 0xdf, - 0x48, 0x36, 0x84, 0xf3, 0x42, 0x22, 0xd9, 0x0d, 0x7a, 0x1b, 0xd2, 0x03, 0xe6, 0x28, 0x3b, 0x99, - 0xed, 0xeb, 0xe2, 0x4e, 0xfc, 0xd5, 0x8b, 0xcd, 0x02, 0x0b, 0x2b, 0x3b, 0xae, 0x47, 0xf7, 0x98, - 0x43, 0xb1, 0x04, 0x98, 0x27, 0x90, 0x16, 0xa9, 0x02, 0xbd, 0x0e, 0xe9, 0xed, 0x46, 0xb3, 0x66, - 0x2c, 0x95, 0xae, 0x9d, 0x9d, 0x97, 0x57, 0xe4, 0x92, 0x88, 0x0e, 0x11, 0xbb, 0x68, 0x13, 0xb2, - 0x4f, 0xf6, 0x77, 0xbb, 0x7b, 0x22, 0xbc, 0xae, 0x9f, 0x9d, 0x97, 0xd7, 0xe2, 0x6e, 0xb5, 0x68, - 0xe8, 0x0d, 0xc8, 0x74, 0xf6, 0x5a, 0x3b, 0x6d, 0x23, 0x59, 0x42, 0x67, 0xe7, 0xe5, 0xd5, 0xb8, - 0x5f, 0xfa, 0x5c, 0xba, 0xa6, 0x77, 0x35, 0x1f, 0xcb, 0xcd, 0xff, 0x49, 0xc2, 0x0a, 0x16, 0xfc, - 0x36, 0xe0, 0x2d, 0xe6, 0xb9, 0xf6, 0x18, 0xb5, 0x20, 0x6f, 0x33, 0xdf, 0x71, 0xa7, 0xce, 0xd4, - 0xd6, 0x2b, 0x2e, 0xc1, 0x89, 0x56, 0xd4, 0xaa, 0x46, 0x9a, 0x78, 0x62, 0x04, 0x6d, 0x41, 0xc6, - 0xa1, 0x1e, 0x19, 0x5f, 0x76, 0x1b, 0xd7, 0x34, 0x97, 0xc6, 0x0a, 0x2a, 0x99, 0x23, 0x79, 0xd6, - 0x23, 0x9c, 0xd3, 0xc1, 0x90, 0xab, 0xdb, 0x38, 0x8d, 0x0b, 0x03, 0xf2, 0xcc, 0xd2, 0x22, 0xf4, - 0x43, 0xc8, 0x9e, 0xba, 0xbe, 0xc3, 0x4e, 0xf5, 0x85, 0x7b, 0xb9, 0x5d, 0x8d, 0x35, 0xcf, 0xc4, - 0x3d, 0x3b, 0xe7, 0xac, 0x58, 0xf5, 0xe6, 0x7e, 0xb3, 0x1e, 0xad, 0xba, 0xee, 0xdf, 0xf7, 0x9b, - 0xcc, 0x17, 0x27, 0x06, 0xf6, 0x9b, 0xbd, 0x1d, 0xab, 0xb1, 0xdb, 0xc5, 0x62, 0xe5, 0x6f, 0x9c, - 0x9d, 0x97, 0x8d, 0x18, 0xb2, 0x43, 0x5c, 0x4f, 0x90, 0xc0, 0x5b, 0x90, 0xb2, 0x9a, 0x9f, 0x1b, - 0xc9, 0x92, 0x71, 0x76, 0x5e, 0x2e, 0xc6, 0xdd, 0x96, 0x3f, 0x9e, 0x1c, 0xa6, 0xf9, 0x71, 0xcd, - 0x7f, 0x4f, 0x42, 0xb1, 0x3b, 0x74, 0x08, 0xa7, 0x2a, 0x32, 0x51, 0x19, 0x0a, 0x43, 0x12, 0x10, - 0xcf, 0xa3, 0x9e, 0x1b, 0x0e, 0x74, 0xa1, 0x30, 0x2d, 0x42, 0xf7, 0xbf, 0xc5, 0x62, 0x6a, 0x12, - 0xa6, 0x97, 0xb4, 0x0b, 0xab, 0x87, 0xca, 0xd9, 0x1e, 0xb1, 0xe5, 0xee, 0xa6, 0xe4, 0xee, 0x56, - 0x16, 0x99, 0x98, 0xf6, 0xaa, 0xa2, 0xe7, 0x68, 0x49, 0x2d, 0xbc, 0x72, 0x38, 0xdd, 0x44, 0x1f, - 0xc3, 0xf2, 0x80, 0xf9, 0x2e, 0x67, 0xc1, 0x95, 0xf6, 0x21, 0x02, 0xa3, 0x77, 0xe1, 0x9a, 0xd8, - 0xe1, 0xc8, 0x25, 0xd9, 0x2d, 0x6f, 0xae, 0x24, 0x5e, 0x1b, 0x90, 0x67, 0x7a, 0x4c, 0x2c, 0xc4, - 0xe6, 0xc7, 0xb0, 0x32, 0xe3, 0x83, 0xb8, 0xcd, 0x5b, 0x56, 0xb7, 0x5d, 0x37, 0x96, 0x50, 0x11, - 0x72, 0xd5, 0xfd, 0x66, 0xa7, 0xd1, 0xec, 0x0a, 0xea, 0x51, 0x84, 0x1c, 0xde, 0xdf, 0xdd, 0xdd, - 0xb6, 0xaa, 0x8f, 0x8d, 0xa4, 0xf9, 0xdf, 0xf1, 0xfa, 0x6a, 0xee, 0xb1, 0x3d, 0xcb, 0x3d, 0xde, - 0x7b, 0xf5, 0xd4, 0x35, 0xfb, 0x98, 0x34, 0x62, 0x0e, 0xf2, 0x13, 0x00, 0xb9, 0x8d, 0xd4, 0xe9, - 0x11, 0x7e, 0x59, 0x7d, 0xd1, 0x89, 0x2a, 0x47, 0x9c, 0xd7, 0x0a, 0x16, 0x47, 0x9f, 0x41, 0xd1, - 0x66, 0x83, 0xa1, 0x47, 0xb5, 0x7e, 0xea, 0x2a, 0xfa, 0x85, 0x58, 0xc5, 0xe2, 0xd3, 0x1c, 0x28, - 0x3d, 0xcb, 0x81, 0xfe, 0x3c, 0x01, 0x85, 0x29, 0x87, 0x67, 0xa9, 0x50, 0x11, 0x72, 0xdd, 0x56, - 0xcd, 0xea, 0x34, 0x9a, 0x0f, 0x8d, 0x04, 0x02, 0xc8, 0xca, 0x05, 0xac, 0x19, 0x49, 0x41, 0xd7, - 0xaa, 0xfb, 0x7b, 0xad, 0xdd, 0xba, 0x24, 0x43, 0xe8, 0x06, 0x18, 0xd1, 0x12, 0xf6, 0xda, 0x1d, - 0x0b, 0x0b, 0x69, 0x1a, 0x5d, 0x87, 0xb5, 0x58, 0xaa, 0x35, 0x33, 0xe8, 0x26, 0xa0, 0x58, 0x38, - 0x31, 0x91, 0x35, 0xff, 0x04, 0xd6, 0xaa, 0xcc, 0xe7, 0xc4, 0xf5, 0x63, 0x2a, 0xbb, 0x25, 0xe6, - 0xad, 0x45, 0x3d, 0xd7, 0x51, 0xd9, 0x76, 0x7b, 0xed, 0xe2, 0xc5, 0x66, 0x21, 0x86, 0x36, 0x6a, - 0x62, 0xa6, 0x51, 0xc3, 0x11, 0x67, 0x6a, 0xe8, 0x3a, 0x3a, 0x79, 0x2e, 0x5f, 0xbc, 0xd8, 0x4c, - 0xb5, 0x1a, 0x35, 0x2c, 0x64, 0xe8, 0x75, 0xc8, 0xd3, 0x67, 0x2e, 0xef, 0xd9, 0x22, 0xbb, 0x8a, - 0x35, 0xcc, 0xe0, 0x9c, 0x10, 0x54, 0x45, 0x32, 0xfd, 0xd3, 0x24, 0x40, 0x87, 0x84, 0xc7, 0x7a, - 0xe8, 0x07, 0x90, 0x8f, 0x8b, 0xf8, 0xcb, 0x8a, 0xc9, 0xa9, 0xfd, 0x8a, 0xf1, 0xe8, 0xa3, 0x28, - 0x62, 0x14, 0xc7, 0x5e, 0xac, 0xa8, 0xc7, 0x5a, 0x44, 0x53, 0x67, 0x89, 0xb4, 0xb8, 0x6b, 0x68, - 0x10, 0xe8, 0x8d, 0x13, 0x7f, 0x51, 0x55, 0xe6, 0x5b, 0x35, 0x67, 0xcd, 0xdc, 0xee, 0x2c, 0x1a, - 0x64, 0x6e, 0x41, 0x1f, 0x2d, 0xe1, 0x89, 0xde, 0xb6, 0x01, 0xab, 0xc1, 0xc8, 0x17, 0x5e, 0xf7, - 0x42, 0xd9, 0x6d, 0xba, 0xf0, 0x5a, 0x93, 0xf2, 0x53, 0x16, 0x1c, 0x5b, 0x9c, 0x13, 0xfb, 0x48, - 0x14, 0xd5, 0x3a, 0xc9, 0x4c, 0x08, 0x67, 0x62, 0x86, 0x70, 0xae, 0xc3, 0x32, 0xf1, 0x5c, 0x12, - 0x52, 0x75, 0x4b, 0xe7, 0x71, 0xd4, 0x14, 0xb4, 0x98, 0x38, 0x4e, 0x40, 0xc3, 0x90, 0xaa, 0x32, - 0x30, 0x8f, 0x27, 0x02, 0xf3, 0x5f, 0x92, 0x00, 0x8d, 0x96, 0xb5, 0xa7, 0xcd, 0xd7, 0x20, 0x7b, - 0x48, 0x06, 0xae, 0x37, 0xbe, 0xec, 0x90, 0x4d, 0xf0, 0x15, 0x4b, 0x19, 0xda, 0x91, 0x3a, 0x58, - 0xeb, 0x4a, 0xb6, 0x3c, 0x3a, 0xf0, 0x29, 0x8f, 0xd9, 0xb2, 0x6c, 0x89, 0xab, 0x39, 0x20, 0x7e, - 0xbc, 0xb0, 0xaa, 0x21, 0x5c, 0xef, 0x13, 0x4e, 0x4f, 0xc9, 0x38, 0x3a, 0x13, 0xba, 0x89, 0x1e, - 0x09, 0x16, 0x2d, 0x8a, 0x7b, 0xea, 0xac, 0x67, 0x24, 0xf7, 0xf8, 0x26, 0x7f, 0xb0, 0x86, 0x2b, - 0xd2, 0x11, 0x6b, 0x97, 0x1e, 0xc8, 0x9b, 0x72, 0xd2, 0xf5, 0xad, 0x8a, 0xd8, 0x0f, 0x60, 0x65, - 0x66, 0x9e, 0x2f, 0x95, 0x29, 0x8d, 0xd6, 0x93, 0x1f, 0x1a, 0x69, 0xfd, 0xef, 0x63, 0x23, 0x6b, - 0xfe, 0x57, 0x02, 0xa0, 0xc5, 0x82, 0x68, 0xd3, 0x16, 0x3f, 0x0b, 0xe5, 0xe4, 0x23, 0x93, 0xcd, - 0x3c, 0x1d, 0x9e, 0x0b, 0x79, 0xfa, 0xc4, 0x8a, 0xa0, 0xbd, 0x12, 0x8e, 0x63, 0x45, 0xb4, 0x09, - 0x05, 0xb5, 0xff, 0xbd, 0x21, 0x0b, 0x54, 0x3e, 0x5a, 0xc1, 0xa0, 0x44, 0x42, 0x13, 0xdd, 0x85, - 0xd5, 0xe1, 0xe8, 0xc0, 0x73, 0xc3, 0x23, 0xea, 0x28, 0x4c, 0x5a, 0x62, 0x56, 0x62, 0xa9, 0x80, - 0x99, 0x35, 0xc8, 0x45, 0xd6, 0xd1, 0x3a, 0xa4, 0x3a, 0xd5, 0x96, 0xb1, 0x54, 0x5a, 0x3b, 0x3b, - 0x2f, 0x17, 0x22, 0x71, 0xa7, 0xda, 0x12, 0x3d, 0xdd, 0x5a, 0xcb, 0x48, 0xcc, 0xf6, 0x74, 0x6b, - 0xad, 0x52, 0x5a, 0xdc, 0x92, 0xe6, 0x5f, 0x27, 0x20, 0xab, 0x38, 0xdb, 0xc2, 0x19, 0x5b, 0xb0, - 0x1c, 0x55, 0x12, 0x8a, 0x48, 0xbe, 0xfd, 0x6a, 0xd2, 0x57, 0xd1, 0x1c, 0x4d, 0xed, 0x63, 0xa4, - 0x57, 0xfa, 0x04, 0x8a, 0xd3, 0x1d, 0xdf, 0x6a, 0x17, 0xff, 0x18, 0x0a, 0x22, 0x50, 0x22, 0xf2, - 0xb7, 0x05, 0x59, 0xc5, 0x2b, 0x75, 0x56, 0xb9, 0x8c, 0x81, 0x6a, 0x24, 0xba, 0x0f, 0xcb, 0x8a, - 0xb5, 0x46, 0xef, 0x29, 0x1b, 0x97, 0x87, 0x23, 0x8e, 0xe0, 0xe6, 0xa7, 0x90, 0x6e, 0x51, 0x1a, - 0xa0, 0x3b, 0xb0, 0xec, 0x33, 0x87, 0x4e, 0x92, 0xa8, 0x26, 0xdc, 0x0e, 0x6d, 0xd4, 0x04, 0xe1, - 0x76, 0x68, 0xc3, 0x11, 0x8b, 0x27, 0x0e, 0x68, 0xf4, 0xa4, 0x24, 0xfe, 0x9b, 0x1d, 0x28, 0x3e, - 0xa5, 0x6e, 0xff, 0x88, 0x53, 0x47, 0x1a, 0x7a, 0x0f, 0xd2, 0x43, 0x1a, 0x3b, 0xbf, 0xbe, 0x30, - 0x74, 0x28, 0x0d, 0xb0, 0x44, 0x89, 0x03, 0x79, 0x2a, 0xb5, 0xf5, 0x2b, 0x9e, 0x6e, 0x99, 0xff, - 0x90, 0x84, 0xd5, 0x46, 0x18, 0x8e, 0x88, 0x6f, 0x47, 0xb7, 0xec, 0x4f, 0x67, 0x6f, 0xd9, 0x7b, - 0x0b, 0x67, 0x38, 0xa3, 0x32, 0x5b, 0xe5, 0xeb, 0x24, 0x99, 0x8c, 0x93, 0xa4, 0xf9, 0x55, 0x22, - 0x2a, 0xef, 0xef, 0x4e, 0x9d, 0x9b, 0xd2, 0xfa, 0xd9, 0x79, 0xf9, 0xc6, 0xb4, 0x25, 0xda, 0xf5, - 0x8f, 0x7d, 0x76, 0xea, 0xa3, 0x37, 0x45, 0xb9, 0xdf, 0xac, 0x3f, 0x35, 0x12, 0xa5, 0x9b, 0x67, - 0xe7, 0x65, 0x34, 0x03, 0xc2, 0xd4, 0xa7, 0xa7, 0xc2, 0x52, 0xab, 0xde, 0xac, 0x89, 0xfb, 0x30, - 0xb9, 0xc0, 0x52, 0x8b, 0xfa, 0x8e, 0xeb, 0xf7, 0xd1, 0x1d, 0xc8, 0x36, 0xda, 0xed, 0xae, 0x2c, - 0xc0, 0x5e, 0x3b, 0x3b, 0x2f, 0x5f, 0x9f, 0x41, 0x89, 0x06, 0x75, 0x04, 0x48, 0x10, 0x44, 0x71, - 0x53, 0x2e, 0x00, 0x09, 0xee, 0x42, 0x1d, 0x1d, 0xe1, 0xff, 0x96, 0x04, 0xc3, 0xb2, 0x6d, 0x3a, - 0xe4, 0xa2, 0x5f, 0x93, 0xee, 0x0e, 0xe4, 0x86, 0xe2, 0x9f, 0x2b, 0x8b, 0x08, 0x11, 0x16, 0xf7, - 0x17, 0x3e, 0xf1, 0xce, 0xe9, 0x55, 0x30, 0xf3, 0xa8, 0xe5, 0x0c, 0xdc, 0x30, 0x14, 0xc5, 0xa5, - 0x94, 0xe1, 0xd8, 0x52, 0xe9, 0xd7, 0x09, 0xb8, 0xbe, 0x00, 0x81, 0x3e, 0x80, 0x74, 0xc0, 0xbc, - 0x68, 0x7b, 0x6e, 0xbf, 0xea, 0x01, 0x46, 0xa8, 0x62, 0x89, 0x44, 0x1b, 0x00, 0x64, 0xc4, 0x19, - 0x91, 0xe3, 0xcb, 0x8d, 0xc9, 0xe1, 0x29, 0x09, 0x7a, 0x0a, 0xd9, 0x90, 0xda, 0x01, 0x8d, 0xf8, - 0xcc, 0xa7, 0xff, 0x5f, 0xef, 0x2b, 0x6d, 0x69, 0x06, 0x6b, 0x73, 0xa5, 0x0a, 0x64, 0x95, 0x44, - 0x44, 0xb4, 0x43, 0x38, 0x91, 0x4e, 0x17, 0xb1, 0xfc, 0x2f, 0x02, 0x85, 0x78, 0xfd, 0x28, 0x50, - 0x88, 0xd7, 0x37, 0x7f, 0x9e, 0x04, 0xa8, 0x3f, 0xe3, 0x34, 0xf0, 0x89, 0x57, 0xb5, 0x50, 0x7d, - 0x2a, 0x43, 0xaa, 0xd9, 0xbe, 0xb3, 0xf0, 0x59, 0x2e, 0xd6, 0xa8, 0x54, 0xad, 0x05, 0x39, 0xf2, - 0x16, 0xa4, 0x46, 0x81, 0xa7, 0x9f, 0x78, 0x25, 0x11, 0xe9, 0xe2, 0x5d, 0x2c, 0x64, 0xa8, 0x3e, - 0xc9, 0x48, 0xa9, 0x57, 0xbf, 0xcd, 0x4f, 0x0d, 0xf0, 0xdd, 0x67, 0xa5, 0xf7, 0x00, 0x26, 0x5e, - 0xa3, 0x0d, 0xc8, 0x54, 0x77, 0xda, 0xed, 0x5d, 0x63, 0x49, 0xd5, 0x88, 0x93, 0x2e, 0x29, 0x36, - 0xff, 0x3e, 0x01, 0xb9, 0xaa, 0xa5, 0x6f, 0x95, 0x1d, 0x30, 0x64, 0x2e, 0xb1, 0x69, 0xc0, 0x7b, - 0xf4, 0xd9, 0xd0, 0x0d, 0xc6, 0x3a, 0x1d, 0x5c, 0xce, 0xe2, 0x57, 0x85, 0x56, 0x95, 0x06, 0xbc, - 0x2e, 0x75, 0x10, 0x86, 0x22, 0xd5, 0x53, 0xec, 0xd9, 0x24, 0x4a, 0xce, 0x1b, 0x97, 0x2f, 0x85, - 0x62, 0x7f, 0x93, 0x76, 0x88, 0x0b, 0x91, 0x91, 0x2a, 0x09, 0xcd, 0x27, 0x70, 0x7d, 0x3f, 0xb0, - 0x8f, 0x68, 0xc8, 0xd5, 0xa0, 0xda, 0xe5, 0x4f, 0xe1, 0x36, 0x27, 0xe1, 0x71, 0xef, 0xc8, 0x0d, - 0x39, 0x0b, 0xc6, 0xbd, 0x80, 0x72, 0xea, 0x8b, 0xfe, 0x9e, 0xfc, 0x02, 0xa0, 0x6b, 0xf0, 0x5b, - 0x02, 0xf3, 0x48, 0x41, 0x70, 0x84, 0xd8, 0x15, 0x00, 0xb3, 0x01, 0x45, 0x41, 0xd8, 0x6a, 0xf4, - 0x90, 0x8c, 0x3c, 0x1e, 0xa2, 0x1f, 0x03, 0x78, 0xac, 0xdf, 0xbb, 0x72, 0x26, 0xcf, 0x7b, 0xac, - 0xaf, 0xfe, 0x9a, 0xbf, 0x07, 0x46, 0xcd, 0x0d, 0x87, 0x84, 0xdb, 0x47, 0xd1, 0xe3, 0x02, 0x7a, - 0x08, 0xc6, 0x11, 0x25, 0x01, 0x3f, 0xa0, 0x84, 0xf7, 0x86, 0x34, 0x70, 0x99, 0x73, 0xa5, 0x25, - 0x5d, 0x8b, 0xb5, 0x5a, 0x52, 0xc9, 0xfc, 0x4d, 0x02, 0x00, 0x93, 0xc3, 0x88, 0x00, 0xfc, 0x00, - 0xae, 0x85, 0x3e, 0x19, 0x86, 0x47, 0x8c, 0xf7, 0x5c, 0x9f, 0xd3, 0xe0, 0x84, 0x78, 0xba, 0x40, - 0x34, 0xa2, 0x8e, 0x86, 0x96, 0xa3, 0xf7, 0x00, 0x1d, 0x53, 0x3a, 0xec, 0x31, 0xcf, 0xe9, 0x45, - 0x9d, 0xea, 0x13, 0x45, 0x1a, 0x1b, 0xa2, 0x67, 0xdf, 0x73, 0xda, 0x91, 0x1c, 0x6d, 0xc3, 0x86, - 0x58, 0x01, 0xea, 0xf3, 0xc0, 0xa5, 0x61, 0xef, 0x90, 0x05, 0xbd, 0xd0, 0x63, 0xa7, 0xbd, 0x43, - 0xe6, 0x79, 0xec, 0x94, 0x06, 0x51, 0xf9, 0x5d, 0xf2, 0x58, 0xbf, 0xae, 0x40, 0x3b, 0x2c, 0x68, - 0x7b, 0xec, 0x74, 0x27, 0x42, 0x08, 0x96, 0x30, 0x99, 0x36, 0x77, 0xed, 0xe3, 0x88, 0x25, 0xc4, - 0xd2, 0x8e, 0x6b, 0x1f, 0xa3, 0x3b, 0xb0, 0x42, 0x3d, 0x2a, 0x8b, 0x38, 0x85, 0xca, 0x48, 0x54, - 0x31, 0x12, 0x0a, 0x90, 0xf9, 0x3b, 0x90, 0x6f, 0x79, 0xc4, 0x96, 0x1f, 0x82, 0x44, 0x49, 0x6c, - 0x33, 0x5f, 0x04, 0x81, 0xeb, 0x73, 0x95, 0x1d, 0xf3, 0x78, 0x5a, 0x64, 0xfe, 0x14, 0xe0, 0x67, - 0xcc, 0xf5, 0x3b, 0xec, 0x98, 0xfa, 0xf2, 0xcd, 0x5c, 0xb0, 0x5e, 0xbd, 0x95, 0x79, 0xac, 0x5b, - 0x92, 0x93, 0x13, 0x9f, 0xf4, 0x69, 0x10, 0x3f, 0x1d, 0xab, 0xa6, 0xb8, 0x5c, 0xb2, 0x98, 0x31, - 0x5e, 0xb5, 0x50, 0x19, 0xb2, 0x36, 0xe9, 0x45, 0x27, 0xaf, 0xb8, 0x9d, 0xbf, 0x78, 0xb1, 0x99, - 0xa9, 0x5a, 0x8f, 0xe9, 0x18, 0x67, 0x6c, 0xf2, 0x98, 0x8e, 0xc5, 0xed, 0x6b, 0x13, 0x79, 0x5e, - 0xa4, 0x99, 0xa2, 0xba, 0x7d, 0xab, 0x96, 0x38, 0x0c, 0x38, 0x6b, 0x13, 0xf1, 0x8b, 0x3e, 0x80, - 0xa2, 0x06, 0xf5, 0x8e, 0x48, 0x78, 0xa4, 0xb8, 0xea, 0xf6, 0xea, 0xc5, 0x8b, 0x4d, 0x50, 0xc8, - 0x47, 0x24, 0x3c, 0xc2, 0xa0, 0xd0, 0xe2, 0x3f, 0xaa, 0x43, 0xe1, 0x0b, 0xe6, 0xfa, 0x3d, 0x2e, - 0x27, 0xa1, 0x2b, 0xe9, 0x85, 0xe7, 0x67, 0x32, 0x55, 0x5d, 0xde, 0xc3, 0x17, 0xb1, 0xc4, 0xfc, - 0xd7, 0x04, 0x14, 0x84, 0x4d, 0xf7, 0xd0, 0xb5, 0xc5, 0x6d, 0xf9, 0xed, 0x33, 0xfd, 0x2d, 0x48, - 0xd9, 0x61, 0xa0, 0xe7, 0x26, 0x53, 0x5d, 0xb5, 0x8d, 0xb1, 0x90, 0xa1, 0xcf, 0x20, 0xab, 0x8a, - 0x0b, 0x9d, 0xe4, 0xcd, 0x6f, 0xbe, 0xd7, 0xb5, 0x8b, 0x5a, 0x4f, 0xee, 0xe5, 0xc4, 0x3b, 0x39, - 0xcb, 0x22, 0x9e, 0x16, 0xa1, 0x9b, 0x90, 0xb4, 0x7d, 0x19, 0x14, 0xfa, 0x5b, 0x5a, 0xb5, 0x89, - 0x93, 0xb6, 0x6f, 0xfe, 0x73, 0x02, 0x56, 0xea, 0xbe, 0x1d, 0x8c, 0x65, 0x92, 0x14, 0x1b, 0x71, - 0x1b, 0xf2, 0xe1, 0xe8, 0x20, 0x1c, 0x87, 0x9c, 0x0e, 0xa2, 0xa7, 0xfa, 0x58, 0x80, 0x1a, 0x90, - 0x27, 0x5e, 0x9f, 0x05, 0x2e, 0x3f, 0x1a, 0x68, 0x6e, 0xbc, 0x38, 0x31, 0x4f, 0xdb, 0xac, 0x58, - 0x91, 0x0a, 0x9e, 0x68, 0x47, 0xa9, 0x38, 0x25, 0x9d, 0x95, 0xa9, 0xf8, 0x4d, 0x28, 0x7a, 0x64, - 0x20, 0xa8, 0x70, 0x4f, 0x94, 0x5c, 0x72, 0x1e, 0x69, 0x5c, 0xd0, 0x32, 0x51, 0x46, 0x9a, 0x26, - 0xe4, 0x63, 0x63, 0x68, 0x0d, 0x0a, 0x56, 0xbd, 0xdd, 0xfb, 0x70, 0xeb, 0x7e, 0xef, 0x61, 0x75, - 0xcf, 0x58, 0xd2, 0x4c, 0xe0, 0x1f, 0x13, 0xb0, 0xb2, 0xa7, 0x62, 0x50, 0x13, 0xa7, 0x3b, 0xb0, - 0x1c, 0x90, 0x43, 0x1e, 0x51, 0xbb, 0xb4, 0x0a, 0x2e, 0x91, 0x04, 0x04, 0xb5, 0x13, 0x5d, 0x8b, - 0xa9, 0xdd, 0xd4, 0x87, 0xa2, 0xd4, 0xa5, 0x1f, 0x8a, 0xd2, 0xdf, 0xc9, 0x87, 0x22, 0xf3, 0x57, - 0x09, 0x58, 0xd3, 0x17, 0x75, 0xf4, 0x71, 0x04, 0xbd, 0x03, 0x79, 0x75, 0x67, 0x4f, 0x88, 0xa9, - 0xfc, 0x5e, 0xa1, 0x70, 0x8d, 0x1a, 0xce, 0xa9, 0xee, 0x86, 0x83, 0x7e, 0x32, 0xf5, 0x2a, 0xfa, - 0x0a, 0x7a, 0x38, 0x67, 0xbd, 0x32, 0x79, 0x2a, 0x7d, 0xe5, 0xf7, 0x92, 0x4d, 0x28, 0x68, 0x07, - 0x64, 0xd9, 0xa0, 0xea, 0x40, 0x50, 0xa2, 0x26, 0x19, 0x50, 0xf3, 0x2e, 0xa4, 0x85, 0x19, 0x04, - 0x90, 0x6d, 0x7f, 0xde, 0xee, 0xd4, 0xf7, 0x54, 0xe5, 0xb5, 0xd3, 0x90, 0x1f, 0xad, 0x96, 0x21, - 0x55, 0x6f, 0x3e, 0x31, 0x92, 0xe6, 0xef, 0x43, 0x01, 0xd3, 0x01, 0x3b, 0xa1, 0x4e, 0x53, 0x0d, - 0x97, 0x8c, 0x27, 0x24, 0x23, 0xb2, 0x51, 0xc3, 0x49, 0xd7, 0x41, 0x3f, 0x82, 0xac, 0xbe, 0x30, - 0xaf, 0xf4, 0x04, 0xa4, 0xc1, 0xef, 0xfe, 0x26, 0x05, 0xf9, 0xf8, 0xbd, 0x40, 0x9c, 0x36, 0x41, - 0x52, 0x97, 0xd4, 0xab, 0x61, 0x2c, 0x6f, 0x4a, 0x7a, 0x9a, 0xb7, 0x76, 0x77, 0xf7, 0xab, 0x56, - 0xa7, 0x5e, 0x33, 0x3e, 0x53, 0x2c, 0x36, 0x06, 0x58, 0x9e, 0xc7, 0xc4, 0x79, 0x71, 0x90, 0x39, - 0x61, 0xb1, 0xcf, 0xf5, 0xdb, 0x64, 0x8c, 0x8a, 0x28, 0xec, 0x5b, 0x90, 0xb3, 0xda, 0xed, 0xc6, - 0xc3, 0x66, 0xbd, 0x66, 0x7c, 0x99, 0x28, 0x7d, 0xef, 0xec, 0xbc, 0x7c, 0x6d, 0x62, 0x2a, 0x0c, - 0xdd, 0xbe, 0x4f, 0x1d, 0x89, 0xaa, 0x56, 0xeb, 0x2d, 0x31, 0xde, 0xf3, 0xe4, 0x3c, 0x4a, 0x72, - 0x37, 0xf9, 0x9d, 0x21, 0xdf, 0xc2, 0xf5, 0x96, 0x85, 0xc5, 0x88, 0x5f, 0x26, 0xe7, 0xfc, 0x6a, - 0x05, 0x74, 0x48, 0x02, 0x31, 0xe6, 0x46, 0xf4, 0xbd, 0xed, 0x79, 0x4a, 0xbd, 0x45, 0x4f, 0x1e, - 0x49, 0x28, 0x71, 0xc6, 0x62, 0x34, 0xf9, 0xb8, 0x24, 0xcd, 0xa4, 0xe6, 0x46, 0x6b, 0x73, 0x12, - 0x70, 0x61, 0xc5, 0x84, 0x65, 0xdc, 0x6d, 0x36, 0xe5, 0xec, 0xd2, 0x73, 0xb3, 0xc3, 0x23, 0xdf, - 0x17, 0x98, 0xbb, 0x90, 0x8b, 0xde, 0x9e, 0x8c, 0x2f, 0xd3, 0x73, 0x0e, 0x55, 0xa3, 0x87, 0x33, - 0x39, 0xe0, 0xa3, 0x6e, 0x47, 0x7e, 0x0e, 0x7c, 0x9e, 0x99, 0x1f, 0xf0, 0x68, 0xc4, 0x1d, 0x51, - 0x37, 0x94, 0x63, 0x22, 0xff, 0x65, 0x46, 0xf1, 0xa7, 0x18, 0xa3, 0x58, 0xbc, 0xb0, 0x83, 0xeb, - 0x3f, 0x53, 0x5f, 0x0e, 0x9f, 0x67, 0xe7, 0xec, 0x60, 0xfa, 0x05, 0xb5, 0x39, 0x75, 0x26, 0x4f, - 0xed, 0x71, 0xd7, 0xbb, 0x7f, 0x00, 0xb9, 0x28, 0xd7, 0xa2, 0x0d, 0xc8, 0x3e, 0xdd, 0xc7, 0x8f, - 0xeb, 0xd8, 0x58, 0x52, 0xab, 0x13, 0xf5, 0x3c, 0x55, 0x97, 0x55, 0x19, 0x96, 0xf7, 0xac, 0xa6, - 0xf5, 0xb0, 0x8e, 0xa3, 0xa7, 0xfe, 0x08, 0xa0, 0x13, 0x46, 0xc9, 0xd0, 0x03, 0xc4, 0x36, 0xb7, - 0x6f, 0x7f, 0xf5, 0xf5, 0xc6, 0xd2, 0x2f, 0xbf, 0xde, 0x58, 0xfa, 0xf5, 0xd7, 0x1b, 0x89, 0xe7, - 0x17, 0x1b, 0x89, 0xaf, 0x2e, 0x36, 0x12, 0xbf, 0xb8, 0xd8, 0x48, 0xfc, 0xc7, 0xc5, 0x46, 0xe2, - 0x20, 0x2b, 0xc9, 0xec, 0x47, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0x1f, 0x9b, 0xee, 0x67, 0xfb, - 0x22, 0x00, 0x00, + // 3787 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x59, 0x4d, 0x6c, 0x23, 0x47, + 0x76, 0x16, 0x7f, 0x45, 0x3e, 0x52, 0x52, 0x4f, 0xcd, 0xec, 0x58, 0x43, 0x8f, 0x25, 0xba, 0xc7, + 0xb3, 0x1e, 0xcf, 0x3a, 0xb4, 0x2d, 0x7b, 0x8d, 0x59, 0xcf, 0x66, 0xc7, 0xcd, 0x1f, 0x8d, 0xb8, + 0x23, 0x51, 0x44, 0x91, 0x9a, 0x81, 0x11, 0x20, 0x44, 0xa9, 0xbb, 0x44, 0xb5, 0xd5, 0xec, 0x66, + 0xba, 0x8b, 0xd2, 0x30, 0x41, 0x80, 0x41, 0x0e, 0x49, 0xa0, 0x53, 0xee, 0x81, 0xb0, 0x08, 0x12, + 0xe4, 0x90, 0x43, 0xae, 0x01, 0x72, 0x32, 0x72, 0xf2, 0x2d, 0x9b, 0x04, 0x08, 0x16, 0x1b, 0x64, + 0x10, 0x2b, 0xe7, 0x00, 0x7b, 0x09, 0x72, 0x48, 0x0e, 0x41, 0xfd, 0x74, 0xb3, 0xc9, 0xa1, 0x34, + 0xf2, 0xae, 0x2f, 0x64, 0xd7, 0xab, 0xef, 0xbd, 0xfa, 0x7b, 0xf5, 0xea, 0x7b, 0x55, 0x50, 0x60, + 0xe3, 0x21, 0x0d, 0x2a, 0x43, 0xdf, 0x63, 0x1e, 0x42, 0x96, 0x67, 0x1e, 0x51, 0xbf, 0x12, 0x9c, + 0x10, 0x7f, 0x70, 0x64, 0xb3, 0xca, 0xf1, 0x47, 0xa5, 0x5b, 0xcc, 0x1e, 0xd0, 0x80, 0x91, 0xc1, + 0xf0, 0x83, 0xe8, 0x4b, 0xc2, 0x4b, 0x6f, 0x58, 0x23, 0x9f, 0x30, 0xdb, 0x73, 0x3f, 0x08, 0x3f, + 0x54, 0xc5, 0x8d, 0xbe, 0xd7, 0xf7, 0xc4, 0xe7, 0x07, 0xfc, 0x4b, 0x4a, 0xf5, 0x75, 0x58, 0x7c, + 0x4a, 0xfd, 0xc0, 0xf6, 0x5c, 0x74, 0x03, 0x32, 0xb6, 0x6b, 0xd1, 0xe7, 0xab, 0x89, 0x72, 0xe2, + 0x5e, 0x1a, 0xcb, 0x82, 0xfe, 0x17, 0x09, 0x28, 0x18, 0xae, 0xeb, 0x31, 0x61, 0x2b, 0x40, 0x08, + 0xd2, 0x2e, 0x19, 0x50, 0x01, 0xca, 0x63, 0xf1, 0x8d, 0x6a, 0x90, 0x75, 0xc8, 0x3e, 0x75, 0x82, + 0xd5, 0x64, 0x39, 0x75, 0xaf, 0xb0, 0xf1, 0x83, 0xca, 0xab, 0x7d, 0xae, 0xc4, 0x8c, 0x54, 0xb6, + 0x05, 0xba, 0xe1, 0x32, 0x7f, 0x8c, 0x95, 0x6a, 0xe9, 0x47, 0x50, 0x88, 0x89, 0x91, 0x06, 0xa9, + 0x23, 0x3a, 0x56, 0xcd, 0xf0, 0x4f, 0xde, 0xbf, 0x63, 0xe2, 0x8c, 0xe8, 0x6a, 0x52, 0xc8, 0x64, + 0xe1, 0xb3, 0xe4, 0x83, 0x84, 0xfe, 0x05, 0xe4, 0x31, 0x0d, 0xbc, 0x91, 0x6f, 0xd2, 0x00, 0xbd, + 0x07, 0x79, 0x97, 0xb8, 0x5e, 0xcf, 0x1c, 0x8e, 0x02, 0xa1, 0x9e, 0xaa, 0x16, 0xcf, 0x5f, 0xae, + 0xe7, 0x5a, 0xc4, 0xf5, 0x6a, 0xed, 0xbd, 0x00, 0xe7, 0x78, 0x75, 0x6d, 0x38, 0x0a, 0xd0, 0xdb, + 0x50, 0x1c, 0xd0, 0x81, 0xe7, 0x8f, 0x7b, 0xfb, 0x63, 0x46, 0x03, 0x61, 0x38, 0x85, 0x0b, 0x52, + 0x56, 0xe5, 0x22, 0xfd, 0xcf, 0x12, 0x70, 0x23, 0xb4, 0x8d, 0xe9, 0xef, 0x8d, 0x6c, 0x9f, 0x0e, + 0xa8, 0xcb, 0x02, 0xf4, 0x43, 0xc8, 0x3a, 0xf6, 0xc0, 0x66, 0xb2, 0x8d, 0xc2, 0xc6, 0x5b, 0xf3, + 0xc6, 0x1c, 0xf5, 0x0a, 0x2b, 0x30, 0x32, 0xa0, 0xe8, 0xd3, 0x80, 0xfa, 0xc7, 0x72, 0x26, 0x44, + 0x93, 0xaf, 0x55, 0x9e, 0x52, 0xd1, 0x37, 0x21, 0xd7, 0x76, 0x08, 0x3b, 0xf0, 0xfc, 0x01, 0xd2, + 0xa1, 0x48, 0x7c, 0xf3, 0xd0, 0x66, 0xd4, 0x64, 0x23, 0x3f, 0x5c, 0x95, 0x29, 0x19, 0xba, 0x09, + 0x49, 0x4f, 0x36, 0x94, 0xaf, 0x66, 0xcf, 0x5f, 0xae, 0x27, 0x77, 0x3b, 0x38, 0xe9, 0x05, 0xfa, + 0x43, 0xb8, 0xd6, 0x76, 0x46, 0x7d, 0xdb, 0xad, 0xd3, 0xc0, 0xf4, 0xed, 0x21, 0xb7, 0xce, 0x97, + 0x97, 0x3b, 0x5f, 0xb8, 0xbc, 0xfc, 0x3b, 0x5a, 0xf2, 0xe4, 0x64, 0xc9, 0xf5, 0x3f, 0x49, 0xc2, + 0xb5, 0x86, 0xdb, 0xb7, 0x5d, 0x1a, 0xd7, 0xbe, 0x0b, 0xcb, 0x54, 0x08, 0x7b, 0xc7, 0xd2, 0xa9, + 0x94, 0x9d, 0x25, 0x29, 0x0d, 0x3d, 0xad, 0x39, 0xe3, 0x2f, 0x1f, 0xcd, 0x1b, 0xfe, 0x2b, 0xd6, + 0xe7, 0x79, 0x0d, 0x6a, 0xc0, 0xe2, 0x50, 0x0c, 0x22, 0x58, 0x4d, 0x09, 0x5b, 0x77, 0xe7, 0xd9, + 0x7a, 0x65, 0x9c, 0xd5, 0xf4, 0xd7, 0x2f, 0xd7, 0x17, 0x70, 0xa8, 0xfb, 0x9b, 0x38, 0xdf, 0x7f, + 0x26, 0x60, 0xa5, 0xe5, 0x59, 0x53, 0xf3, 0x50, 0x82, 0xdc, 0xa1, 0x17, 0xb0, 0xd8, 0x46, 0x89, + 0xca, 0xe8, 0x01, 0xe4, 0x86, 0x6a, 0xf9, 0xd4, 0xea, 0xdf, 0x9e, 0xdf, 0x65, 0x89, 0xc1, 0x11, + 0x1a, 0x3d, 0x84, 0xbc, 0x1f, 0xfa, 0xc4, 0x6a, 0xea, 0x2a, 0x8e, 0x33, 0xc1, 0xa3, 0xdf, 0x86, + 0xac, 0x5c, 0x84, 0xd5, 0xb4, 0xd0, 0xbc, 0x7b, 0xa5, 0x39, 0xc7, 0x4a, 0x49, 0xff, 0x45, 0x02, + 0x34, 0x4c, 0x0e, 0xd8, 0x0e, 0x1d, 0xec, 0x53, 0xbf, 0xc3, 0x08, 0x1b, 0x05, 0xe8, 0x26, 0x64, + 0x1d, 0x4a, 0x2c, 0xea, 0x8b, 0x41, 0xe6, 0xb0, 0x2a, 0xa1, 0x3d, 0xee, 0xe4, 0xc4, 0x3c, 0x24, + 0xfb, 0xb6, 0x63, 0xb3, 0xb1, 0x18, 0xe6, 0xf2, 0xfc, 0x55, 0x9e, 0xb5, 0x59, 0xc1, 0x31, 0x45, + 0x3c, 0x65, 0x06, 0xad, 0xc2, 0xe2, 0x80, 0x06, 0x01, 0xe9, 0x53, 0x31, 0xfa, 0x3c, 0x0e, 0x8b, + 0xfa, 0x43, 0x28, 0xc6, 0xf5, 0x50, 0x01, 0x16, 0xf7, 0x5a, 0x4f, 0x5a, 0xbb, 0xcf, 0x5a, 0xda, + 0x02, 0x5a, 0x81, 0xc2, 0x5e, 0x0b, 0x37, 0x8c, 0xda, 0x96, 0x51, 0xdd, 0x6e, 0x68, 0x09, 0xb4, + 0x04, 0xf9, 0x49, 0x31, 0xa9, 0xff, 0x2c, 0x01, 0xc0, 0x17, 0x50, 0x0d, 0xea, 0x33, 0xc8, 0x04, + 0x8c, 0x30, 0xb9, 0x70, 0xcb, 0x1b, 0xef, 0xcc, 0xeb, 0xf5, 0x04, 0x5e, 0xe1, 0x7f, 0x14, 0x4b, + 0x95, 0x78, 0x0f, 0x93, 0xb3, 0x3d, 0xcc, 0x08, 0xe4, 0x74, 0xd7, 0x72, 0x90, 0xae, 0xf3, 0xaf, + 0x04, 0xca, 0x43, 0x06, 0x37, 0x8c, 0xfa, 0x17, 0x5a, 0x12, 0x69, 0x50, 0xac, 0x37, 0x3b, 0xb5, + 0xdd, 0x56, 0xab, 0x51, 0xeb, 0x36, 0xea, 0x5a, 0x4a, 0xbf, 0x0b, 0x99, 0xe6, 0x80, 0xf4, 0x29, + 0xba, 0xcd, 0x3d, 0xe0, 0x80, 0xfa, 0xd4, 0x35, 0x43, 0xc7, 0x9a, 0x08, 0xf4, 0x9f, 0xe7, 0x21, + 0xb3, 0xe3, 0x8d, 0x5c, 0x86, 0x36, 0x62, 0xbb, 0x78, 0x79, 0x63, 0x6d, 0xde, 0x10, 0x04, 0xb0, + 0xd2, 0x1d, 0x0f, 0xa9, 0xda, 0xe5, 0x37, 0x21, 0x2b, 0x7d, 0x45, 0x75, 0x5d, 0x95, 0xb8, 0x9c, + 0x11, 0xbf, 0x4f, 0x99, 0x9a, 0x74, 0x55, 0x42, 0xf7, 0x20, 0xe7, 0x53, 0x62, 0x79, 0xae, 0x33, + 0x16, 0x2e, 0x95, 0x93, 0x61, 0x16, 0x53, 0x62, 0xed, 0xba, 0xce, 0x18, 0x47, 0xb5, 0x68, 0x0b, + 0x8a, 0xfb, 0xb6, 0x6b, 0xf5, 0xbc, 0xa1, 0x8c, 0x79, 0x99, 0x8b, 0x1d, 0x50, 0xf6, 0xaa, 0x6a, + 0xbb, 0xd6, 0xae, 0x04, 0xe3, 0xc2, 0xfe, 0xa4, 0x80, 0x5a, 0xb0, 0x7c, 0xec, 0x39, 0xa3, 0x01, + 0x8d, 0x6c, 0x65, 0x85, 0xad, 0x77, 0x2f, 0xb6, 0xf5, 0x54, 0xe0, 0x43, 0x6b, 0x4b, 0xc7, 0xf1, + 0x22, 0x7a, 0x02, 0x4b, 0x6c, 0x30, 0x3c, 0x08, 0x22, 0x73, 0x8b, 0xc2, 0xdc, 0xf7, 0x2f, 0x99, + 0x30, 0x0e, 0x0f, 0xad, 0x15, 0x59, 0xac, 0x54, 0xfa, 0xa3, 0x14, 0x14, 0x62, 0x3d, 0x47, 0x1d, + 0x28, 0x0c, 0x7d, 0x6f, 0x48, 0xfa, 0x22, 0x6e, 0xab, 0xb5, 0xf8, 0xe8, 0x4a, 0xa3, 0xae, 0xb4, + 0x27, 0x8a, 0x38, 0x6e, 0x45, 0x3f, 0x4b, 0x42, 0x21, 0x56, 0x89, 0xee, 0x43, 0x0e, 0xb7, 0x71, + 0xf3, 0xa9, 0xd1, 0x6d, 0x68, 0x0b, 0xa5, 0xdb, 0xa7, 0x67, 0xe5, 0x55, 0x61, 0x2d, 0x6e, 0xa0, + 0xed, 0xdb, 0xc7, 0xdc, 0xf5, 0xee, 0xc1, 0x62, 0x08, 0x4d, 0x94, 0xde, 0x3c, 0x3d, 0x2b, 0xbf, + 0x31, 0x0b, 0x8d, 0x21, 0x71, 0x67, 0xcb, 0xc0, 0x8d, 0xba, 0x96, 0x9c, 0x8f, 0xc4, 0x9d, 0x43, + 0xe2, 0x53, 0x0b, 0x7d, 0x1f, 0xb2, 0x0a, 0x98, 0x2a, 0x95, 0x4e, 0xcf, 0xca, 0x37, 0x67, 0x81, + 0x13, 0x1c, 0xee, 0x6c, 0x1b, 0x4f, 0x1b, 0x5a, 0x7a, 0x3e, 0x0e, 0x77, 0x1c, 0x72, 0x4c, 0xd1, + 0x3b, 0x90, 0x91, 0xb0, 0x4c, 0xe9, 0xd6, 0xe9, 0x59, 0xf9, 0x7b, 0xaf, 0x98, 0xe3, 0xa8, 0xd2, + 0xea, 0x9f, 0xfe, 0xe5, 0xda, 0xc2, 0xdf, 0xff, 0xd5, 0x9a, 0x36, 0x5b, 0x5d, 0xfa, 0xbf, 0x04, + 0x2c, 0x4d, 0x2d, 0x39, 0xd2, 0x21, 0xeb, 0x7a, 0xa6, 0x37, 0x94, 0xe1, 0x3c, 0x57, 0x85, 0xf3, + 0x97, 0xeb, 0xd9, 0x96, 0x57, 0xf3, 0x86, 0x63, 0xac, 0x6a, 0xd0, 0x93, 0x99, 0x03, 0xe9, 0xe3, + 0x2b, 0xfa, 0xd3, 0xdc, 0x23, 0xe9, 0x11, 0x2c, 0x59, 0xbe, 0x7d, 0x4c, 0xfd, 0x9e, 0xe9, 0xb9, + 0x07, 0x76, 0x5f, 0x85, 0xea, 0xd2, 0x3c, 0x9b, 0x75, 0x01, 0xc4, 0x45, 0xa9, 0x50, 0x13, 0xf8, + 0xdf, 0xe0, 0x30, 0x2a, 0x3d, 0x85, 0x62, 0xdc, 0x43, 0xd1, 0x5b, 0x00, 0x81, 0xfd, 0xfb, 0x54, + 0xf1, 0x1b, 0xc1, 0x86, 0x70, 0x9e, 0x4b, 0x04, 0xbb, 0x41, 0xef, 0x42, 0x7a, 0xe0, 0x59, 0xd2, + 0x4e, 0xa6, 0x7a, 0x9d, 0x9f, 0x89, 0xbf, 0x7c, 0xb9, 0x5e, 0xf0, 0x82, 0xca, 0xa6, 0xed, 0xd0, + 0x1d, 0xcf, 0xa2, 0x58, 0x00, 0xf4, 0x63, 0x48, 0xf3, 0x50, 0x81, 0xde, 0x84, 0x74, 0xb5, 0xd9, + 0xaa, 0x6b, 0x0b, 0xa5, 0x6b, 0xa7, 0x67, 0xe5, 0x25, 0x31, 0x25, 0xbc, 0x82, 0xfb, 0x2e, 0x5a, + 0x87, 0xec, 0xd3, 0xdd, 0xed, 0xbd, 0x1d, 0xee, 0x5e, 0xd7, 0x4f, 0xcf, 0xca, 0x2b, 0x51, 0xb5, + 0x9c, 0x34, 0xf4, 0x16, 0x64, 0xba, 0x3b, 0xed, 0xcd, 0x8e, 0x96, 0x2c, 0xa1, 0xd3, 0xb3, 0xf2, + 0x72, 0x54, 0x2f, 0xfa, 0x5c, 0xba, 0xa6, 0x56, 0x35, 0x1f, 0xc9, 0xf5, 0xff, 0x4d, 0xc2, 0x12, + 0xe6, 0xfc, 0xd6, 0x67, 0x6d, 0xcf, 0xb1, 0xcd, 0x31, 0x6a, 0x43, 0xde, 0xf4, 0x5c, 0xcb, 0x8e, + 0xed, 0xa9, 0x8d, 0x0b, 0x0e, 0xc1, 0x89, 0x56, 0x58, 0xaa, 0x85, 0x9a, 0x78, 0x62, 0x04, 0x6d, + 0x40, 0xc6, 0xa2, 0x0e, 0x19, 0x5f, 0x76, 0x1a, 0xd7, 0x15, 0x97, 0xc6, 0x12, 0x2a, 0x98, 0x23, + 0x79, 0xde, 0x23, 0x8c, 0xd1, 0xc1, 0x90, 0xc9, 0xd3, 0x38, 0x8d, 0x0b, 0x03, 0xf2, 0xdc, 0x50, + 0x22, 0xf4, 0x09, 0x64, 0x4f, 0x6c, 0xd7, 0xf2, 0x4e, 0xd4, 0x81, 0x7b, 0xb9, 0x5d, 0x85, 0xd5, + 0x4f, 0xf9, 0x39, 0x3b, 0xd3, 0x59, 0x3e, 0xeb, 0xad, 0xdd, 0x56, 0x23, 0x9c, 0x75, 0x55, 0xbf, + 0xeb, 0xb6, 0x3c, 0x97, 0xef, 0x18, 0xd8, 0x6d, 0xf5, 0x36, 0x8d, 0xe6, 0xf6, 0x1e, 0xe6, 0x33, + 0x7f, 0xe3, 0xf4, 0xac, 0xac, 0x45, 0x90, 0x4d, 0x62, 0x3b, 0x9c, 0x04, 0xde, 0x82, 0x94, 0xd1, + 0xfa, 0x42, 0x4b, 0x96, 0xb4, 0xd3, 0xb3, 0x72, 0x31, 0xaa, 0x36, 0xdc, 0xf1, 0x64, 0x33, 0xcd, + 0xb6, 0xab, 0xff, 0x7b, 0x12, 0x8a, 0x7b, 0x43, 0x8b, 0x30, 0x2a, 0x3d, 0x13, 0x95, 0xa1, 0x30, + 0x24, 0x3e, 0x71, 0x1c, 0xea, 0xd8, 0xc1, 0x40, 0x25, 0x0a, 0x71, 0x11, 0x7a, 0xf0, 0x2d, 0x26, + 0x53, 0x91, 0x30, 0x35, 0xa5, 0x7b, 0xb0, 0x7c, 0x20, 0x3b, 0xdb, 0x23, 0xa6, 0x58, 0xdd, 0x94, + 0x58, 0xdd, 0xca, 0x3c, 0x13, 0xf1, 0x5e, 0x55, 0xd4, 0x18, 0x0d, 0xa1, 0x85, 0x97, 0x0e, 0xe2, + 0x45, 0xf4, 0x29, 0x2c, 0x0e, 0x3c, 0xd7, 0x66, 0x9e, 0x7f, 0xa5, 0x75, 0x08, 0xc1, 0xe8, 0x3e, + 0x5c, 0xe3, 0x2b, 0x1c, 0x76, 0x49, 0x54, 0x8b, 0x93, 0x2b, 0x89, 0x57, 0x06, 0xe4, 0xb9, 0x6a, + 0x13, 0x73, 0xb1, 0xfe, 0x29, 0x2c, 0x4d, 0xf5, 0x81, 0x9f, 0xe6, 0x6d, 0x63, 0xaf, 0xd3, 0xd0, + 0x16, 0x50, 0x11, 0x72, 0xb5, 0xdd, 0x56, 0xb7, 0xd9, 0xda, 0xe3, 0xd4, 0xa3, 0x08, 0x39, 0xbc, + 0xbb, 0xbd, 0x5d, 0x35, 0x6a, 0x4f, 0xb4, 0xa4, 0xfe, 0xdf, 0xd1, 0xfc, 0x2a, 0xee, 0x51, 0x9d, + 0xe6, 0x1e, 0xef, 0x5f, 0x3c, 0x74, 0xc5, 0x3e, 0x26, 0x85, 0x88, 0x83, 0xfc, 0x18, 0x40, 0x2c, + 0x23, 0xb5, 0x7a, 0x84, 0x5d, 0x96, 0x5f, 0x74, 0xc3, 0xcc, 0x11, 0xe7, 0x95, 0x82, 0xc1, 0xd0, + 0xe7, 0x50, 0x34, 0xbd, 0xc1, 0xd0, 0xa1, 0x4a, 0x3f, 0x75, 0x15, 0xfd, 0x42, 0xa4, 0x62, 0xb0, + 0x38, 0x07, 0x4a, 0x4f, 0x73, 0xa0, 0x3f, 0x4e, 0x40, 0x21, 0xd6, 0xe1, 0x69, 0x2a, 0x54, 0x84, + 0xdc, 0x5e, 0xbb, 0x6e, 0x74, 0x9b, 0xad, 0xc7, 0x5a, 0x02, 0x01, 0x64, 0xc5, 0x04, 0xd6, 0xb5, + 0x24, 0xa7, 0x6b, 0xb5, 0xdd, 0x9d, 0xf6, 0x76, 0x43, 0x90, 0x21, 0x74, 0x03, 0xb4, 0x70, 0x0a, + 0x7b, 0x9d, 0xae, 0x81, 0xb9, 0x34, 0x8d, 0xae, 0xc3, 0x4a, 0x24, 0x55, 0x9a, 0x19, 0x74, 0x13, + 0x50, 0x24, 0x9c, 0x98, 0xc8, 0xea, 0x7f, 0x08, 0x2b, 0x35, 0xcf, 0x65, 0xc4, 0x76, 0x23, 0x2a, + 0xbb, 0xc1, 0xc7, 0xad, 0x44, 0x3d, 0xdb, 0x92, 0xd1, 0xb6, 0xba, 0x72, 0xfe, 0x72, 0xbd, 0x10, + 0x41, 0x9b, 0x75, 0x3e, 0xd2, 0xb0, 0x60, 0xf1, 0x3d, 0x35, 0xb4, 0x2d, 0x15, 0x3c, 0x17, 0xcf, + 0x5f, 0xae, 0xa7, 0xda, 0xcd, 0x3a, 0xe6, 0x32, 0xf4, 0x26, 0xe4, 0xe9, 0x73, 0x9b, 0xf5, 0x4c, + 0x1e, 0x5d, 0xf9, 0x1c, 0x66, 0x70, 0x8e, 0x0b, 0x6a, 0x3c, 0x98, 0x56, 0x01, 0xda, 0x9e, 0xcf, + 0x54, 0xcb, 0x9f, 0x40, 0x66, 0xe8, 0xf9, 0x22, 0x8f, 0xe4, 0x47, 0xcf, 0x5c, 0xb2, 0xc6, 0xe1, + 0xd2, 0xd9, 0xb1, 0x04, 0xeb, 0xff, 0x90, 0x04, 0xe8, 0x92, 0xe0, 0x48, 0x19, 0x79, 0x08, 0xf9, + 0xe8, 0x22, 0xe0, 0xb2, 0x84, 0x34, 0xb6, 0xe6, 0x11, 0x1e, 0x7d, 0x1c, 0x7a, 0x9d, 0xe4, 0xe9, + 0xf3, 0x15, 0x55, 0x5b, 0xf3, 0xa8, 0xee, 0x34, 0x19, 0xe7, 0xe7, 0x15, 0xf5, 0x7d, 0xb5, 0xf8, + 0xfc, 0x13, 0xd5, 0x44, 0xcc, 0x96, 0xf3, 0xa6, 0xd8, 0xdf, 0x9d, 0x79, 0x8d, 0xcc, 0x2c, 0xca, + 0xd6, 0x02, 0x9e, 0xe8, 0xa1, 0x47, 0x50, 0xe0, 0x43, 0xef, 0x05, 0xa2, 0x4e, 0x11, 0xbf, 0x0b, + 0x67, 0x4b, 0x5a, 0xc0, 0x30, 0x8c, 0xbe, 0xab, 0x1a, 0x2c, 0xfb, 0x23, 0x97, 0x0f, 0x5b, 0xd9, + 0xd0, 0x6d, 0x78, 0xa3, 0x45, 0xd9, 0x89, 0xe7, 0x1f, 0x19, 0x8c, 0x11, 0xf3, 0x90, 0x67, 0xf6, + 0x2a, 0xd2, 0x4d, 0x58, 0x6f, 0x62, 0x8a, 0xf5, 0xae, 0xc2, 0x22, 0x71, 0x6c, 0x12, 0x50, 0x49, + 0x15, 0xf2, 0x38, 0x2c, 0x72, 0x6e, 0x4e, 0x2c, 0xcb, 0xa7, 0x41, 0x40, 0x65, 0x2e, 0x9a, 0xc7, + 0x13, 0x81, 0xfe, 0x2f, 0x49, 0x80, 0x66, 0xdb, 0xd8, 0x51, 0xe6, 0xeb, 0x90, 0x3d, 0x20, 0x03, + 0xdb, 0x19, 0x5f, 0xb6, 0xd3, 0x27, 0xf8, 0x8a, 0x21, 0x0d, 0x6d, 0x0a, 0x1d, 0xac, 0x74, 0x05, + 0x65, 0x1f, 0xed, 0xbb, 0x94, 0x45, 0x94, 0x5d, 0x94, 0x38, 0x3f, 0xf0, 0x89, 0x1b, 0xad, 0x8c, + 0x2c, 0xf0, 0xae, 0xf7, 0x09, 0xa3, 0x27, 0x64, 0x1c, 0x6e, 0x4c, 0x55, 0x44, 0x5b, 0x9c, 0xca, + 0x07, 0xd4, 0x3f, 0xa6, 0xd6, 0x6a, 0x46, 0x78, 0xe1, 0xeb, 0xfa, 0x83, 0x15, 0x5c, 0x32, 0x9f, + 0x48, 0xbb, 0xf4, 0x50, 0x1c, 0xd7, 0x93, 0xaa, 0x6f, 0x95, 0x49, 0x7f, 0x08, 0x4b, 0x53, 0xe3, + 0x7c, 0x25, 0x57, 0x6a, 0xb6, 0x9f, 0x7e, 0xa2, 0xa5, 0xd5, 0xd7, 0xa7, 0x5a, 0x56, 0xff, 0x9b, + 0x94, 0xdc, 0x4a, 0x6a, 0x56, 0xe7, 0xdf, 0x4d, 0xe5, 0xc4, 0x4d, 0x97, 0xe9, 0x39, 0xca, 0xbf, + 0xdf, 0xbd, 0x7c, 0x87, 0x71, 0xee, 0x2d, 0xe0, 0x38, 0x52, 0x44, 0xeb, 0x50, 0x90, 0xeb, 0xdf, + 0xe3, 0xfe, 0x24, 0xa6, 0x75, 0x09, 0x83, 0x14, 0x71, 0x4d, 0x74, 0x17, 0x96, 0x87, 0xa3, 0x7d, + 0xc7, 0x0e, 0x0e, 0xa9, 0x25, 0x31, 0x69, 0x81, 0x59, 0x8a, 0xa4, 0x02, 0xb6, 0x03, 0x45, 0x25, + 0xe8, 0x09, 0xde, 0x95, 0x11, 0x1d, 0xba, 0xff, 0xba, 0x0e, 0x49, 0x15, 0x41, 0xc7, 0x0a, 0xc3, + 0x49, 0x41, 0xaf, 0x43, 0x2e, 0xec, 0x2c, 0x5a, 0x85, 0x54, 0xb7, 0xd6, 0xd6, 0x16, 0x4a, 0x2b, + 0xa7, 0x67, 0xe5, 0x42, 0x28, 0xee, 0xd6, 0xda, 0xbc, 0x66, 0xaf, 0xde, 0xd6, 0x12, 0xd3, 0x35, + 0x7b, 0xf5, 0x76, 0x29, 0xcd, 0x4f, 0x7e, 0xfd, 0x00, 0x0a, 0xb1, 0x16, 0xd0, 0x1d, 0x58, 0x6c, + 0xb6, 0x1e, 0xe3, 0x46, 0xa7, 0xa3, 0x2d, 0x94, 0x6e, 0x9e, 0x9e, 0x95, 0x51, 0xac, 0xb6, 0xe9, + 0xf6, 0xf9, 0xfa, 0xa0, 0xb7, 0x20, 0xbd, 0xb5, 0xdb, 0xe9, 0x86, 0x44, 0x2f, 0x86, 0xd8, 0xf2, + 0x02, 0x56, 0xba, 0xae, 0x28, 0x45, 0xdc, 0xb0, 0xfe, 0xe7, 0x09, 0xc8, 0x4a, 0xbe, 0x3b, 0x77, + 0xa1, 0x0c, 0x58, 0x0c, 0xb3, 0x30, 0x49, 0xc2, 0xdf, 0xbd, 0x98, 0x30, 0x57, 0x14, 0xbf, 0x95, + 0xee, 0x17, 0xea, 0x95, 0x3e, 0x83, 0x62, 0xbc, 0xe2, 0x5b, 0x39, 0xdf, 0x1f, 0x40, 0x81, 0xfb, + 0x77, 0x48, 0x9c, 0x37, 0x20, 0x2b, 0x39, 0xb9, 0x8a, 0xa6, 0x97, 0xb1, 0x77, 0x85, 0x44, 0x0f, + 0x60, 0x51, 0x32, 0xfe, 0xf0, 0x2e, 0x6a, 0xed, 0xf2, 0x5d, 0x84, 0x43, 0xb8, 0xfe, 0x08, 0xd2, + 0x6d, 0x4a, 0x7d, 0x3e, 0xf7, 0xae, 0x67, 0xd1, 0xc9, 0x01, 0xa4, 0x92, 0x15, 0x8b, 0x36, 0xeb, + 0x3c, 0x59, 0xb1, 0x68, 0xd3, 0xe2, 0x93, 0xc7, 0xe3, 0x4a, 0x78, 0x1d, 0xc7, 0xbf, 0xf5, 0x2e, + 0x14, 0x9f, 0x51, 0xbb, 0x7f, 0xc8, 0xa8, 0x25, 0x0c, 0xbd, 0x0f, 0xe9, 0x21, 0x8d, 0x3a, 0xbf, + 0x3a, 0xd7, 0xc1, 0x28, 0xf5, 0xb1, 0x40, 0xf1, 0x38, 0x72, 0x22, 0xb4, 0xd5, 0x0d, 0xa8, 0x2a, + 0xe9, 0xff, 0x9c, 0x84, 0xe5, 0x66, 0x10, 0x8c, 0x88, 0x6b, 0x86, 0x0c, 0xe5, 0x27, 0xd3, 0x0c, + 0xe5, 0xde, 0xdc, 0x11, 0x4e, 0xa9, 0x4c, 0xdf, 0x90, 0xa8, 0xc3, 0x21, 0x19, 0x1d, 0x0e, 0xfa, + 0x7f, 0x25, 0xc2, 0xab, 0x91, 0xbb, 0xb1, 0xed, 0x5e, 0x5a, 0x3d, 0x3d, 0x2b, 0xdf, 0x88, 0x5b, + 0xa2, 0x7b, 0xee, 0x91, 0xeb, 0x9d, 0xb8, 0xe8, 0x6d, 0xc8, 0xe0, 0x46, 0xab, 0xf1, 0x4c, 0x4b, + 0x48, 0xf7, 0x9c, 0x02, 0x61, 0xea, 0xd2, 0x13, 0x6e, 0xa9, 0xdd, 0x68, 0xd5, 0x39, 0x97, 0x48, + 0xce, 0xb1, 0xd4, 0xa6, 0xae, 0x65, 0xbb, 0x7d, 0x74, 0x07, 0xb2, 0xcd, 0x4e, 0x67, 0x4f, 0x24, + 0xaf, 0x6f, 0x9c, 0x9e, 0x95, 0xaf, 0x4f, 0xa1, 0x78, 0x81, 0x5a, 0x1c, 0xc4, 0xc9, 0x35, 0x67, + 0x19, 0x73, 0x40, 0x9c, 0xf7, 0x49, 0x10, 0xde, 0xed, 0xf2, 0xcc, 0x3a, 0x33, 0x07, 0x84, 0x3d, + 0xfe, 0xab, 0xb6, 0xdb, 0xbf, 0x25, 0x41, 0x33, 0x4c, 0x93, 0x0e, 0x19, 0xaf, 0x57, 0x59, 0x4d, + 0x17, 0x72, 0x43, 0xfe, 0x65, 0xd3, 0x90, 0x07, 0x3c, 0x98, 0x7b, 0x87, 0x3e, 0xa3, 0x57, 0xc1, + 0x9e, 0x43, 0x0d, 0x6b, 0x60, 0x07, 0x01, 0xcf, 0xde, 0x85, 0x0c, 0x47, 0x96, 0x4a, 0xbf, 0x4a, + 0xc0, 0xf5, 0x39, 0x08, 0xf4, 0x21, 0xa4, 0x7d, 0xcf, 0x09, 0xd7, 0xf0, 0xf6, 0x45, 0x37, 0x5c, + 0x5c, 0x15, 0x0b, 0x24, 0x5a, 0x03, 0x20, 0x23, 0xe6, 0x11, 0xd1, 0xbe, 0x58, 0xbd, 0x1c, 0x8e, + 0x49, 0xd0, 0x33, 0xc8, 0x06, 0xd4, 0xf4, 0x69, 0x48, 0x18, 0x1f, 0xfd, 0xba, 0xbd, 0xaf, 0x74, + 0x84, 0x19, 0xac, 0xcc, 0x95, 0x2a, 0x90, 0x95, 0x12, 0xee, 0xf6, 0x16, 0x61, 0x44, 0x74, 0xba, + 0x88, 0xc5, 0x37, 0xf7, 0x26, 0xe2, 0xf4, 0x43, 0x6f, 0x22, 0x4e, 0x5f, 0xff, 0x59, 0x12, 0xa0, + 0xf1, 0x9c, 0x51, 0xdf, 0x25, 0x4e, 0xcd, 0x40, 0x8d, 0x58, 0xf4, 0x97, 0xa3, 0x7d, 0x6f, 0xee, + 0xbd, 0x67, 0xa4, 0x51, 0xa9, 0x19, 0x73, 0xe2, 0xff, 0x2d, 0x48, 0x8d, 0x7c, 0x47, 0xdd, 0xa1, + 0x0b, 0xa6, 0xb7, 0x87, 0xb7, 0x31, 0x97, 0xa1, 0xc6, 0x24, 0x6c, 0xa5, 0x2e, 0x7e, 0xfc, 0x88, + 0x35, 0xf0, 0xdd, 0x87, 0xae, 0xf7, 0x01, 0x26, 0xbd, 0x46, 0x6b, 0x90, 0xa9, 0x6d, 0x76, 0x3a, + 0xdb, 0xda, 0x82, 0x8c, 0xcd, 0x93, 0x2a, 0x21, 0xd6, 0xff, 0x3a, 0x01, 0xb9, 0x9a, 0xa1, 0x4e, + 0xcc, 0x4d, 0xd0, 0x44, 0xc0, 0x31, 0xa9, 0xcf, 0x7a, 0xf4, 0xf9, 0xd0, 0xf6, 0xc7, 0x2a, 0x66, + 0x5c, 0x9e, 0x26, 0x2d, 0x73, 0xad, 0x1a, 0xf5, 0x59, 0x43, 0xe8, 0x20, 0x0c, 0x45, 0xaa, 0x86, + 0xd8, 0x33, 0x49, 0x18, 0xc1, 0xd7, 0x2e, 0x9f, 0x0a, 0x49, 0xaf, 0x27, 0xe5, 0x00, 0x17, 0x42, + 0x23, 0x35, 0x12, 0xe8, 0x4f, 0xe1, 0xfa, 0xae, 0x6f, 0x1e, 0xd2, 0x80, 0xc9, 0x46, 0x55, 0x97, + 0x1f, 0xc1, 0x6d, 0x46, 0x82, 0xa3, 0xde, 0xa1, 0x1d, 0x30, 0xcf, 0x1f, 0xf7, 0x7c, 0xca, 0xa8, + 0xcb, 0xeb, 0x7b, 0xe2, 0x89, 0x45, 0x5d, 0x72, 0xdc, 0xe2, 0x98, 0x2d, 0x09, 0xc1, 0x21, 0x62, + 0x9b, 0x03, 0xf4, 0x26, 0x14, 0x39, 0x9b, 0xad, 0xd3, 0x03, 0x32, 0x72, 0x58, 0x80, 0x7e, 0x04, + 0xe0, 0x78, 0xfd, 0xde, 0x95, 0xc3, 0x7d, 0xde, 0xf1, 0xfa, 0xf2, 0x53, 0xff, 0x1d, 0xd0, 0xea, + 0x76, 0x30, 0x24, 0xcc, 0x3c, 0x0c, 0x6f, 0x6f, 0xd0, 0x63, 0xd0, 0x0e, 0x29, 0xf1, 0xd9, 0x3e, + 0x25, 0xac, 0x37, 0xa4, 0xbe, 0xed, 0x59, 0x57, 0x9a, 0xd2, 0x95, 0x48, 0xab, 0x2d, 0x94, 0xf4, + 0xff, 0x49, 0x00, 0x60, 0x72, 0x10, 0x92, 0x9b, 0x1f, 0xc0, 0xb5, 0xc0, 0x25, 0xc3, 0xe0, 0xd0, + 0x63, 0x3d, 0xdb, 0x65, 0xd4, 0x3f, 0x26, 0x8e, 0xca, 0xc0, 0xb5, 0xb0, 0xa2, 0xa9, 0xe4, 0xe8, + 0x7d, 0x40, 0x47, 0x94, 0x0e, 0x7b, 0x9e, 0x63, 0xf5, 0xc2, 0x4a, 0xf9, 0x06, 0x94, 0xc6, 0x1a, + 0xaf, 0xd9, 0x75, 0xac, 0x4e, 0x28, 0x47, 0x55, 0x58, 0xe3, 0x33, 0x40, 0x5d, 0xe6, 0xdb, 0x34, + 0xe8, 0x1d, 0x78, 0x7e, 0x2f, 0x70, 0xbc, 0x93, 0xde, 0x81, 0xe7, 0x38, 0xde, 0x09, 0xf5, 0xc3, + 0xfb, 0x8d, 0x92, 0xe3, 0xf5, 0x1b, 0x12, 0xb4, 0xe9, 0xf9, 0x1d, 0xc7, 0x3b, 0xd9, 0x0c, 0x11, + 0x9c, 0x01, 0x4d, 0x86, 0xcd, 0x6c, 0xf3, 0x28, 0x64, 0x40, 0x91, 0xb4, 0x6b, 0x9b, 0x47, 0xe8, + 0x0e, 0x2c, 0x51, 0x87, 0x8a, 0x2c, 0x59, 0xa2, 0x32, 0x02, 0x55, 0x0c, 0x85, 0x1c, 0xa4, 0xff, + 0x16, 0xe4, 0xdb, 0x0e, 0x31, 0xc5, 0x4b, 0x1b, 0x2a, 0x03, 0x4f, 0xba, 0xb8, 0x13, 0xd8, 0xae, + 0xca, 0x92, 0xf2, 0x38, 0x2e, 0xd2, 0x7f, 0x02, 0xf0, 0x53, 0xcf, 0x76, 0xbb, 0xde, 0x11, 0x75, + 0xc5, 0xa3, 0x04, 0x67, 0xf4, 0x6a, 0x29, 0xf3, 0x58, 0x95, 0x44, 0xc2, 0x42, 0x5c, 0xd2, 0xa7, + 0x7e, 0x74, 0x37, 0x2f, 0x8b, 0xfa, 0xd7, 0x09, 0xc8, 0x62, 0xcf, 0x63, 0x35, 0x03, 0x95, 0x21, + 0x6b, 0x92, 0x5e, 0xb8, 0xf3, 0x8a, 0xd5, 0xfc, 0xf9, 0xcb, 0xf5, 0x4c, 0xcd, 0x78, 0x42, 0xc7, + 0x38, 0x63, 0x92, 0x27, 0x74, 0xcc, 0x8f, 0x68, 0x93, 0x88, 0xfd, 0x22, 0xcc, 0x14, 0xe5, 0x11, + 0x5d, 0x33, 0xf8, 0x66, 0xc0, 0x59, 0x93, 0xf0, 0x7f, 0xf4, 0x21, 0x14, 0x15, 0xa8, 0x77, 0x48, + 0x82, 0x43, 0xc9, 0xc3, 0xab, 0xcb, 0xe7, 0x2f, 0xd7, 0x41, 0x22, 0xb7, 0x48, 0x70, 0x88, 0x41, + 0xa2, 0xf9, 0x37, 0x6a, 0x40, 0xe1, 0x4b, 0xcf, 0x76, 0x7b, 0x4c, 0x0c, 0x42, 0x5d, 0x55, 0xcc, + 0xdd, 0x3f, 0x93, 0xa1, 0xaa, 0xfb, 0x13, 0xf8, 0x32, 0x92, 0xe8, 0xff, 0x9a, 0x80, 0x02, 0xb7, + 0x69, 0x1f, 0xd8, 0x26, 0x3f, 0x52, 0xbf, 0x7d, 0xa4, 0xbf, 0x05, 0x29, 0x33, 0xf0, 0xd5, 0xd8, + 0x44, 0xa8, 0xab, 0x75, 0x30, 0xe6, 0x32, 0xf4, 0x39, 0x64, 0x55, 0xf2, 0x25, 0x83, 0xbc, 0xfe, + 0xfa, 0xc3, 0x5f, 0x75, 0x51, 0xe9, 0x89, 0xb5, 0x9c, 0xf4, 0x4e, 0x8c, 0xb2, 0x88, 0xe3, 0x22, + 0x74, 0x13, 0x92, 0xa6, 0x2b, 0x9c, 0x42, 0x3d, 0x56, 0xd6, 0x5a, 0x38, 0x69, 0xba, 0xfa, 0x3f, + 0x25, 0x60, 0xa9, 0xe1, 0x9a, 0xfe, 0x58, 0x04, 0x49, 0xbe, 0x10, 0xb7, 0x21, 0x1f, 0x8c, 0xf6, + 0x83, 0x71, 0xc0, 0xe8, 0x20, 0x7c, 0x0b, 0x89, 0x04, 0xa8, 0x09, 0x79, 0xe2, 0xf4, 0x3d, 0xdf, + 0x66, 0x87, 0x03, 0xc5, 0xfb, 0xe7, 0x07, 0xe6, 0xb8, 0xcd, 0x8a, 0x11, 0xaa, 0xe0, 0x89, 0x76, + 0x18, 0x8a, 0x53, 0xa2, 0xb3, 0x22, 0x14, 0xbf, 0x0d, 0x45, 0x87, 0x0c, 0x44, 0x36, 0xca, 0xd3, + 0x49, 0x31, 0x8e, 0x34, 0x2e, 0x28, 0x19, 0xcf, 0xb1, 0x75, 0x1d, 0xf2, 0x91, 0x31, 0xb4, 0x02, + 0x05, 0xa3, 0xd1, 0xe9, 0x7d, 0xb4, 0xf1, 0xa0, 0xf7, 0xb8, 0xb6, 0xa3, 0x2d, 0x28, 0x26, 0xf0, + 0x77, 0x09, 0x58, 0xda, 0x91, 0x3e, 0xa8, 0xd8, 0xd5, 0x1d, 0x58, 0xf4, 0xc9, 0x01, 0x0b, 0xf9, + 0x5f, 0x5a, 0x3a, 0x17, 0x0f, 0x02, 0x9c, 0xff, 0xf1, 0xaa, 0xf9, 0xfc, 0x2f, 0xf6, 0x12, 0x97, + 0xba, 0xf4, 0x25, 0x2e, 0xfd, 0x9d, 0xbc, 0xc4, 0xe9, 0xbf, 0x4c, 0xc0, 0x8a, 0x3a, 0xa8, 0xc3, + 0xd7, 0x27, 0xf4, 0x1e, 0xe4, 0xe5, 0x99, 0x3d, 0x61, 0xaf, 0xe2, 0x41, 0x48, 0xe2, 0x9a, 0x75, + 0x9c, 0x93, 0xd5, 0x4d, 0x0b, 0xfd, 0x38, 0x76, 0xed, 0x7c, 0x01, 0x87, 0x9c, 0xb1, 0x5e, 0x99, + 0xdc, 0x45, 0x5f, 0xf8, 0x20, 0xb5, 0x0e, 0x05, 0xd5, 0x01, 0x91, 0x5b, 0xc8, 0x1c, 0x17, 0xa4, + 0xa8, 0x45, 0x06, 0x54, 0xbf, 0x0b, 0x69, 0x91, 0xe1, 0x00, 0x64, 0x3b, 0x5f, 0x74, 0xba, 0x8d, + 0x1d, 0x99, 0x55, 0x6e, 0x36, 0xc5, 0xab, 0xe0, 0x22, 0xa4, 0x1a, 0xad, 0xa7, 0x5a, 0x52, 0xdf, + 0x85, 0x9b, 0x55, 0x87, 0x98, 0x47, 0x8e, 0x1d, 0x30, 0x6a, 0xc5, 0x77, 0xd3, 0x0f, 0x21, 0x3b, + 0x75, 0x46, 0xbe, 0xe6, 0x8a, 0x45, 0x81, 0xf5, 0xbf, 0x4d, 0x40, 0x71, 0x8b, 0x12, 0x87, 0x1d, + 0x4e, 0xf2, 0x54, 0x46, 0x03, 0xa6, 0x62, 0x99, 0xf8, 0x46, 0x0f, 0x20, 0x17, 0x45, 0xf5, 0xab, + 0x5c, 0x44, 0x47, 0x68, 0xf4, 0x29, 0x2c, 0x72, 0x2f, 0xf4, 0x46, 0x21, 0xf9, 0x7a, 0xcd, 0x0d, + 0xa7, 0x02, 0xf3, 0x80, 0xe8, 0x53, 0x11, 0xcc, 0xc5, 0x5c, 0x65, 0x70, 0x58, 0xbc, 0xff, 0x8f, + 0x29, 0xc8, 0x47, 0x17, 0x3e, 0x3c, 0x22, 0x70, 0xb6, 0xbd, 0x20, 0xaf, 0x8e, 0x23, 0x79, 0x8b, + 0x9e, 0xa0, 0xb7, 0x27, 0x3c, 0xfb, 0x73, 0x79, 0xf1, 0x1c, 0x55, 0x87, 0x1c, 0xfb, 0x1d, 0xc8, + 0x19, 0x9d, 0x4e, 0xf3, 0x71, 0xab, 0x51, 0xd7, 0xbe, 0x4a, 0x94, 0xbe, 0x77, 0x7a, 0x56, 0xbe, + 0x16, 0x81, 0x8c, 0x20, 0xb0, 0xfb, 0x2e, 0xb5, 0x04, 0xaa, 0x56, 0x6b, 0xb4, 0xbb, 0x8d, 0xba, + 0xf6, 0x22, 0x39, 0x8b, 0x12, 0xbc, 0x51, 0x3c, 0x22, 0xe5, 0xdb, 0xb8, 0xd1, 0x36, 0x30, 0x6f, + 0xf0, 0xab, 0xa4, 0xa4, 0xff, 0x93, 0x16, 0x7d, 0x3a, 0x24, 0x3e, 0x6f, 0x73, 0x2d, 0x7c, 0x4c, + 0x7d, 0x91, 0x92, 0x0f, 0x0d, 0x93, 0xdb, 0x2b, 0x4a, 0xac, 0x31, 0x6f, 0x4d, 0xdc, 0x1c, 0x0a, + 0x33, 0xa9, 0x99, 0xd6, 0x3a, 0x8c, 0xf8, 0x8c, 0x5b, 0xd1, 0x61, 0x11, 0xef, 0xb5, 0x5a, 0x1c, + 0xf4, 0x22, 0x3d, 0x33, 0x3a, 0x3c, 0x72, 0x5d, 0x8e, 0xb9, 0x0b, 0xb9, 0xf0, 0x62, 0x51, 0xfb, + 0x2a, 0x3d, 0xd3, 0xa1, 0x5a, 0x78, 0x2b, 0x2a, 0x1a, 0xdc, 0xda, 0xeb, 0x8a, 0xb7, 0xde, 0x17, + 0x99, 0xd9, 0x06, 0x0f, 0x47, 0xcc, 0xe2, 0x89, 0x4d, 0x39, 0xca, 0x34, 0xbe, 0xca, 0x48, 0xee, + 0x16, 0x61, 0x54, 0x9a, 0xf1, 0x0e, 0xe4, 0x70, 0xe3, 0xa7, 0xf2, 0x59, 0xf8, 0x45, 0x76, 0xc6, + 0x0e, 0xa6, 0x5f, 0x52, 0x93, 0x51, 0x6b, 0xf2, 0x8e, 0x12, 0x55, 0xdd, 0xff, 0x5d, 0xc8, 0x85, + 0x71, 0x1e, 0xad, 0x41, 0xf6, 0xd9, 0x2e, 0x7e, 0xd2, 0xc0, 0xda, 0x82, 0x9c, 0x9d, 0xb0, 0xe6, + 0x99, 0x3c, 0x28, 0xcb, 0xb0, 0xb8, 0x63, 0xb4, 0x8c, 0xc7, 0x0d, 0x1c, 0xa6, 0xf7, 0x21, 0x40, + 0x05, 0xab, 0x92, 0xa6, 0x1a, 0x88, 0x6c, 0x56, 0x6f, 0x7f, 0xfd, 0xcd, 0xda, 0xc2, 0x2f, 0xbe, + 0x59, 0x5b, 0xf8, 0xd5, 0x37, 0x6b, 0x89, 0x17, 0xe7, 0x6b, 0x89, 0xaf, 0xcf, 0xd7, 0x12, 0x3f, + 0x3f, 0x5f, 0x4b, 0xfc, 0xc7, 0xf9, 0x5a, 0x62, 0x3f, 0x2b, 0x88, 0xf4, 0xc7, 0xff, 0x1f, 0x00, + 0x00, 0xff, 0xff, 0x24, 0x7a, 0x55, 0x47, 0xd8, 0x24, 0x00, 0x00, } diff --git a/vendor/src/github.com/docker/swarmkit/api/types.proto b/vendor/src/github.com/docker/swarmkit/api/types.proto index a72b65fb459f1..2c6067674b731 100644 --- a/vendor/src/github.com/docker/swarmkit/api/types.proto +++ b/vendor/src/github.com/docker/swarmkit/api/types.proto @@ -371,8 +371,7 @@ enum TaskState { option (gogoproto.goproto_enum_prefix) = false; option (gogoproto.enum_customname) = "TaskState"; NEW = 0 [(gogoproto.enumvalue_customname)="TaskStateNew"]; - ALLOCATED = 64 [(gogoproto.enumvalue_customname)="TaskStateAllocated"]; // successful allocation of resources that the task needs - PENDING = 128 [(gogoproto.enumvalue_customname) = "TaskStatePending"]; // observed by scheduler but unassigned. + PENDING = 64 [(gogoproto.enumvalue_customname)="TaskStatePending"]; // waiting for scheduling decision ASSIGNED = 192 [(gogoproto.enumvalue_customname)="TaskStateAssigned"]; ACCEPTED = 256 [(gogoproto.enumvalue_customname)="TaskStateAccepted"]; // task has been accepted by an agent. PREPARING = 320 [(gogoproto.enumvalue_customname)="TaskStatePreparing"]; @@ -409,6 +408,12 @@ message ContainerStatus { int32 exit_code = 3; } +// PortStatus specifies the actual allocated runtime state of a list +// of port configs. +message PortStatus { + repeated PortConfig ports = 1; +} + message TaskStatus { Timestamp timestamp = 1; @@ -439,6 +444,10 @@ message TaskStatus { oneof runtime_status { ContainerStatus container = 5; } + + // HostPorts provides a list of ports allocated at the host + // level. + PortStatus port_status = 6; } // NetworkAttachmentConfig specifies how a service should be attached to a particular network. @@ -506,6 +515,21 @@ message PortConfig { UDP = 1 [(gogoproto.enumvalue_customname) = "ProtocolUDP"]; } + // PublishMode controls how ports are published on the swarm. + enum PublishMode { + option (gogoproto.enum_customname) = "PublishMode"; + option (gogoproto.goproto_enum_prefix) = false; + + // PublishModeIngress exposes the port across the cluster on all nodes. + INGRESS = 0 [(gogoproto.enumvalue_customname) = "PublishModeIngress"]; + + // PublishModeHost exposes the port on just the target host. If the + // published port is undefined, an ephemeral port will be allocated. If + // the published port is defined, the node will attempt to allocate it, + // erroring the task if it fails. + HOST = 1 [(gogoproto.enumvalue_customname) = "PublishModeHost"]; + } + // Name for the port. If provided the port information can // be queried using the name as in a DNS SRV query. string name = 1; @@ -516,11 +540,13 @@ message PortConfig { // The port which the application is exposing and is bound to. uint32 target_port = 3; - // PublishedPort specifies the port on which the service is - // exposed. If specified, the port must be - // within the available range. If not specified, an available - // port is automatically assigned. + // PublishedPort specifies the port on which the service is exposed. If + // specified, the port must be within the available range. If not specified + // (value is zero), an available port is automatically assigned. uint32 published_port = 4; + + // PublishMode controls how the port is published. + PublishMode publish_mode = 5; } // Driver is a generic driver type to be used throughout the API. For now, a @@ -556,10 +582,17 @@ message IssuanceStatus { option (gogoproto.goproto_enum_prefix) = false; UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "IssuanceStateUnknown"]; - RENEW = 1 [(gogoproto.enumvalue_customname)="IssuanceStateRenew"]; // Certificate should be issued - PENDING = 2 [(gogoproto.enumvalue_customname)="IssuanceStatePending"]; // Certificate is pending acceptance - ISSUED = 3 [(gogoproto.enumvalue_customname)="IssuanceStateIssued"]; // successful completion certificate issuance - FAILED = 4 [(gogoproto.enumvalue_customname)="IssuanceStateFailed"]; // Certificate issuance failed + // A new certificate should be issued + RENEW = 1 [(gogoproto.enumvalue_customname)="IssuanceStateRenew"]; + // Certificate is pending acceptance + PENDING = 2 [(gogoproto.enumvalue_customname)="IssuanceStatePending"]; + // successful completion certificate issuance + ISSUED = 3 [(gogoproto.enumvalue_customname)="IssuanceStateIssued"]; + // Certificate issuance failed + FAILED = 4 [(gogoproto.enumvalue_customname)="IssuanceStateFailed"]; + // Signals workers to renew their certificate. From the CA's perspective + // this is equivalent to IssuanceStateIssued: a noop. + ROTATE = 5 [(gogoproto.enumvalue_customname)="IssuanceStateRotate"]; } State state = 1; @@ -777,12 +810,33 @@ message SecretReference { string secret_name = 4; } -// RemovedNode is a record for a node that has been removed from the swarm. -message RemovedNode { - // ID is the ID of the removed node. - string id = 1 [(gogoproto.customname) = "ID"]; - +// BlacklistedCertificate is a record for a blacklisted certificate. It does not +// contain the certificate's CN, because these records are indexed by CN. +message BlacklistedCertificate { // Expiry is the latest known expiration time of a certificate that - // was issued to this node. - Timestamp expiry = 2; + // was issued for the given CN. + Timestamp expiry = 1; +} + +// HealthConfig holds configuration settings for the HEALTHCHECK feature. +message HealthConfig { + // Test is the test to perform to check that the container is healthy. + // An empty slice means to inherit the default. + // The options are: + // {} : inherit healthcheck + // {"NONE"} : disable healthcheck + // {"CMD", args...} : exec arguments directly + // {"CMD-SHELL", command} : run command with system's default shell + repeated string test = 1; + + // Interval is the time to wait between checks. Zero means inherit. + Duration interval = 2; + + // Timeout is the time to wait before considering the check to have hung. + // Zero means inherit. + Duration timeout = 3; + + // Retries is the number of consecutive failures needed to consider a + // container as unhealthy. Zero means inherit. + int32 retries = 4; } diff --git a/vendor/src/github.com/docker/swarmkit/ca/auth.go b/vendor/src/github.com/docker/swarmkit/ca/auth.go index 724416c77cf38..d81b543da031c 100644 --- a/vendor/src/github.com/docker/swarmkit/ca/auth.go +++ b/vendor/src/github.com/docker/swarmkit/ca/auth.go @@ -80,7 +80,7 @@ func certSubjectFromContext(ctx context.Context) (pkix.Name, error) { // AuthorizeOrgAndRole takes in a context and a list of roles, and returns // the Node ID of the node. -func AuthorizeOrgAndRole(ctx context.Context, org string, removedNodes []*api.RemovedNode, ou ...string) (string, error) { +func AuthorizeOrgAndRole(ctx context.Context, org string, blacklistedCerts map[string]*api.BlacklistedCertificate, ou ...string) (string, error) { certSubj, err := certSubjectFromContext(ctx) if err != nil { return "", err @@ -88,7 +88,7 @@ func AuthorizeOrgAndRole(ctx context.Context, org string, removedNodes []*api.Re // Check if the current certificate has an OU that authorizes // access to this method if intersectArrays(certSubj.OrganizationalUnit, ou) { - return authorizeOrg(certSubj, org, removedNodes) + return authorizeOrg(certSubj, org, blacklistedCerts) } return "", grpc.Errorf(codes.PermissionDenied, "Permission denied: remote certificate not part of OUs: %v", ou) @@ -96,11 +96,9 @@ func AuthorizeOrgAndRole(ctx context.Context, org string, removedNodes []*api.Re // authorizeOrg takes in a certificate subject and an organization, and returns // the Node ID of the node. -func authorizeOrg(certSubj pkix.Name, org string, removedNodes []*api.RemovedNode) (string, error) { - for _, removedNode := range removedNodes { - if removedNode.ID == certSubj.CommonName { - return "", grpc.Errorf(codes.PermissionDenied, "Permission denied: node %s was removed from swarm", certSubj.CommonName) - } +func authorizeOrg(certSubj pkix.Name, org string, blacklistedCerts map[string]*api.BlacklistedCertificate) (string, error) { + if _, ok := blacklistedCerts[certSubj.CommonName]; ok { + return "", grpc.Errorf(codes.PermissionDenied, "Permission denied: node %s was removed from swarm", certSubj.CommonName) } if len(certSubj.Organization) > 0 && certSubj.Organization[0] == org { @@ -114,9 +112,9 @@ func authorizeOrg(certSubj pkix.Name, org string, removedNodes []*api.RemovedNod // been proxied by a manager, in which case the manager is authenticated and // so is the certificate information that it forwarded. It returns the node ID // of the original client. -func AuthorizeForwardedRoleAndOrg(ctx context.Context, authorizedRoles, forwarderRoles []string, org string, removedNodes []*api.RemovedNode) (string, error) { +func AuthorizeForwardedRoleAndOrg(ctx context.Context, authorizedRoles, forwarderRoles []string, org string, blacklistedCerts map[string]*api.BlacklistedCertificate) (string, error) { if isForwardedRequest(ctx) { - _, err := AuthorizeOrgAndRole(ctx, org, removedNodes, forwarderRoles...) + _, err := AuthorizeOrgAndRole(ctx, org, blacklistedCerts, forwarderRoles...) if err != nil { return "", grpc.Errorf(codes.PermissionDenied, "Permission denied: unauthorized forwarder role: %v", err) } @@ -142,7 +140,7 @@ func AuthorizeForwardedRoleAndOrg(ctx context.Context, authorizedRoles, forwarde } // There wasn't any node being forwarded, check if this is a direct call by the expected role - nodeID, err := AuthorizeOrgAndRole(ctx, org, removedNodes, authorizedRoles...) + nodeID, err := AuthorizeOrgAndRole(ctx, org, blacklistedCerts, authorizedRoles...) if err == nil { return nodeID, nil } diff --git a/vendor/src/github.com/docker/swarmkit/ca/certificates.go b/vendor/src/github.com/docker/swarmkit/ca/certificates.go index d12b8960954b1..19022d58ef950 100644 --- a/vendor/src/github.com/docker/swarmkit/ca/certificates.go +++ b/vendor/src/github.com/docker/swarmkit/ca/certificates.go @@ -629,6 +629,7 @@ func GetRemoteSignedCertificate(ctx context.Context, csr []byte, token string, r issueRequest := &api.IssueNodeCertificateRequest{CSR: csr, Token: token} issueResponse, err := caClient.IssueNodeCertificate(ctx, issueRequest) if err != nil { + r.Observe(peer, -remotes.DefaultObservationWeight) return nil, err } diff --git a/vendor/src/github.com/docker/swarmkit/ca/server.go b/vendor/src/github.com/docker/swarmkit/ca/server.go index c35c4040868e4..5b27e73880803 100644 --- a/vendor/src/github.com/docker/swarmkit/ca/server.go +++ b/vendor/src/github.com/docker/swarmkit/ca/server.go @@ -168,9 +168,9 @@ func (s *Server) IssueNodeCertificate(ctx context.Context, request *api.IssueNod defer s.doneTask() var ( - removedNodes []*api.RemovedNode - clusters []*api.Cluster - err error + blacklistedCerts map[string]*api.BlacklistedCertificate + clusters []*api.Cluster + err error ) s.store.View(func(readTx store.ReadTx) { @@ -181,19 +181,19 @@ func (s *Server) IssueNodeCertificate(ctx context.Context, request *api.IssueNod // Not having a cluster object yet means we can't check // the blacklist. if err == nil && len(clusters) == 1 { - removedNodes = clusters[0].RemovedNodes + blacklistedCerts = clusters[0].BlacklistedCertificates } // If the remote node is a worker (either forwarded by a manager, or calling directly), // issue a renew worker certificate entry with the correct ID - nodeID, err := AuthorizeForwardedRoleAndOrg(ctx, []string{WorkerRole}, []string{ManagerRole}, s.securityConfig.ClientTLSCreds.Organization(), removedNodes) + nodeID, err := AuthorizeForwardedRoleAndOrg(ctx, []string{WorkerRole}, []string{ManagerRole}, s.securityConfig.ClientTLSCreds.Organization(), blacklistedCerts) if err == nil { return s.issueRenewCertificate(ctx, nodeID, request.CSR) } // If the remote node is a manager (either forwarded by another manager, or calling directly), // issue a renew certificate entry with the correct ID - nodeID, err = AuthorizeForwardedRoleAndOrg(ctx, []string{ManagerRole}, []string{ManagerRole}, s.securityConfig.ClientTLSCreds.Organization(), removedNodes) + nodeID, err = AuthorizeForwardedRoleAndOrg(ctx, []string{ManagerRole}, []string{ManagerRole}, s.securityConfig.ClientTLSCreds.Organization(), blacklistedCerts) if err == nil { return s.issueRenewCertificate(ctx, nodeID, request.CSR) } @@ -542,18 +542,20 @@ func (s *Server) updateCluster(ctx context.Context, cluster *api.Cluster) { func (s *Server) evaluateAndSignNodeCert(ctx context.Context, node *api.Node) error { // If the desired membership and actual state are in sync, there's // nothing to do. - if node.Spec.Membership == api.NodeMembershipAccepted && node.Certificate.Status.State == api.IssuanceStateIssued { + certState := node.Certificate.Status.State + if node.Spec.Membership == api.NodeMembershipAccepted && + (certState == api.IssuanceStateIssued || certState == api.IssuanceStateRotate) { return nil } // If the certificate state is renew, then it is a server-sided accepted cert (cert renewals) - if node.Certificate.Status.State == api.IssuanceStateRenew { + if certState == api.IssuanceStateRenew { return s.signNodeCert(ctx, node) } // Sign this certificate if a user explicitly changed it to Accepted, and // the certificate is in pending state - if node.Spec.Membership == api.NodeMembershipAccepted && node.Certificate.Status.State == api.IssuanceStatePending { + if node.Spec.Membership == api.NodeMembershipAccepted && certState == api.IssuanceStatePending { return s.signNodeCert(ctx, node) } @@ -688,7 +690,8 @@ func (s *Server) reconcileNodeCertificates(ctx context.Context, nodes []*api.Nod // A successfully issued certificate and a failed certificate are our current final states func isFinalState(status api.IssuanceStatus) bool { - if status.State == api.IssuanceStateIssued || status.State == api.IssuanceStateFailed { + if status.State == api.IssuanceStateIssued || status.State == api.IssuanceStateFailed || + status.State == api.IssuanceStateRotate { return true } diff --git a/vendor/src/github.com/docker/swarmkit/manager/allocator/network.go b/vendor/src/github.com/docker/swarmkit/manager/allocator/network.go index 3e6cdefdc85d4..0da215131b07f 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/allocator/network.go +++ b/vendor/src/github.com/docker/swarmkit/manager/allocator/network.go @@ -22,8 +22,12 @@ const ( ingressNetworkName = "ingress" ingressSubnet = "10.255.0.0/16" + + allocatedStatusMessage = "pending task scheduling" ) +var errNoChanges = errors.New("task unchanged") + func newIngressNetwork() *api.Network { return &api.Network{ Spec: api.NetworkSpec{ @@ -134,17 +138,13 @@ func (a *Allocator) doNetworkInit(ctx context.Context) (err error) { if !na.IsAllocated(nc.ingressNetwork) { if err := a.allocateNetwork(ctx, nc.ingressNetwork); err != nil { log.G(ctx).WithError(err).Error("failed allocating ingress network during init") - } - - // Update store after allocation - if err := a.store.Update(func(tx store.Tx) error { - if err := store.UpdateNetwork(tx, nc.ingressNetwork); err != nil { - return err + } else if _, err := a.store.Batch(func(batch *store.Batch) error { + if err := a.commitAllocatedNetwork(ctx, batch, nc.ingressNetwork); err != nil { + log.G(ctx).WithError(err).Error("failed committing allocation of ingress network during init") } - return nil }); err != nil { - return errors.Wrap(err, "failed to create ingress network") + log.G(ctx).WithError(err).Error("failed committing allocation of ingress network during init") } } @@ -157,6 +157,7 @@ func (a *Allocator) doNetworkInit(ctx context.Context) (err error) { return errors.Wrap(err, "error listing all networks in store while trying to allocate during init") } + var allocatedNetworks []*api.Network for _, n := range networks { if na.IsAllocated(n) { continue @@ -164,7 +165,20 @@ func (a *Allocator) doNetworkInit(ctx context.Context) (err error) { if err := a.allocateNetwork(ctx, n); err != nil { log.G(ctx).WithError(err).Errorf("failed allocating network %s during init", n.ID) + continue + } + allocatedNetworks = append(allocatedNetworks, n) + } + + if _, err := a.store.Batch(func(batch *store.Batch) error { + for _, n := range allocatedNetworks { + if err := a.commitAllocatedNetwork(ctx, batch, n); err != nil { + log.G(ctx).WithError(err).Errorf("failed committing allocation of network %s during init", n.ID) + } } + return nil + }); err != nil { + log.G(ctx).WithError(err).Error("failed committing allocation of networks during init") } // Allocate nodes in the store so far before we process watched events. @@ -176,6 +190,7 @@ func (a *Allocator) doNetworkInit(ctx context.Context) (err error) { return errors.Wrap(err, "error listing all nodes in store while trying to allocate during init") } + var allocatedNodes []*api.Node for _, node := range nodes { if na.IsNodeAllocated(node) { continue @@ -188,7 +203,21 @@ func (a *Allocator) doNetworkInit(ctx context.Context) (err error) { node.Attachment.Network = nc.ingressNetwork.Copy() if err := a.allocateNode(ctx, node); err != nil { log.G(ctx).WithError(err).Errorf("Failed to allocate network resources for node %s during init", node.ID) + continue } + + allocatedNodes = append(allocatedNodes, node) + } + + if _, err := a.store.Batch(func(batch *store.Batch) error { + for _, node := range allocatedNodes { + if err := a.commitAllocatedNode(ctx, batch, node); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to commit allocation of network resources for node %s during init", node.ID) + } + } + return nil + }); err != nil { + log.G(ctx).WithError(err).Error("Failed to commit allocation of network resources for nodes during init") } // Allocate services in the store so far before we process watched events. @@ -200,6 +229,7 @@ func (a *Allocator) doNetworkInit(ctx context.Context) (err error) { return errors.Wrap(err, "error listing all services in store while trying to allocate during init") } + var allocatedServices []*api.Service for _, s := range services { if nc.nwkAllocator.IsServiceAllocated(s) { continue @@ -207,11 +237,27 @@ func (a *Allocator) doNetworkInit(ctx context.Context) (err error) { if err := a.allocateService(ctx, s); err != nil { log.G(ctx).WithError(err).Errorf("failed allocating service %s during init", s.ID) + continue } + allocatedServices = append(allocatedServices, s) + } + + if _, err := a.store.Batch(func(batch *store.Batch) error { + for _, s := range allocatedServices { + if err := a.commitAllocatedService(ctx, batch, s); err != nil { + log.G(ctx).WithError(err).Errorf("failed committing allocation of service %s during init", s.ID) + } + } + return nil + }); err != nil { + log.G(ctx).WithError(err).Error("failed committing allocation of services during init") } // Allocate tasks in the store so far before we started watching. - var tasks []*api.Task + var ( + tasks []*api.Task + allocatedTasks []*api.Task + ) a.store.View(func(tx store.ReadTx) { tasks, err = store.FindTasks(tx, store.All) }) @@ -219,66 +265,56 @@ func (a *Allocator) doNetworkInit(ctx context.Context) (err error) { return errors.Wrap(err, "error listing all tasks in store while trying to allocate during init") } - if _, err := a.store.Batch(func(batch *store.Batch) error { - for _, t := range tasks { - if taskDead(t) { - continue - } - - var s *api.Service - if t.ServiceID != "" { - a.store.View(func(tx store.ReadTx) { - s = store.GetService(tx, t.ServiceID) - }) - } + for _, t := range tasks { + if taskDead(t) { + continue + } - // Populate network attachments in the task - // based on service spec. - a.taskCreateNetworkAttachments(t, s) + var s *api.Service + if t.ServiceID != "" { + a.store.View(func(tx store.ReadTx) { + s = store.GetService(tx, t.ServiceID) + }) + } - if taskReadyForNetworkVote(t, s, nc) { - if t.Status.State >= api.TaskStateAllocated { - continue - } + // Populate network attachments in the task + // based on service spec. + a.taskCreateNetworkAttachments(t, s) - if a.taskAllocateVote(networkVoter, t.ID) { - // If the task is not attached to any network, network - // allocators job is done. Immediately cast a vote so - // that the task can be moved to ALLOCATED state as - // soon as possible. - if err := batch.Update(func(tx store.Tx) error { - storeT := store.GetTask(tx, t.ID) - if storeT == nil { - return fmt.Errorf("task %s not found while trying to update state", t.ID) - } - - updateTaskStatus(storeT, api.TaskStateAllocated, "allocated") - - if err := store.UpdateTask(tx, storeT); err != nil { - return errors.Wrapf(err, "failed updating state in store transaction for task %s", storeT.ID) - } - - return nil - }); err != nil { - log.G(ctx).WithError(err).Error("error updating task network") - } - } + if taskReadyForNetworkVote(t, s, nc) { + if t.Status.State >= api.TaskStatePending { continue } - err := batch.Update(func(tx store.Tx) error { - _, err := a.allocateTask(ctx, tx, t) - return err - }) - if err != nil { - log.G(ctx).WithError(err).Errorf("failed allocating task %s during init", t.ID) - nc.unallocatedTasks[t.ID] = t + if a.taskAllocateVote(networkVoter, t.ID) { + // If the task is not attached to any network, network + // allocators job is done. Immediately cast a vote so + // that the task can be moved to ALLOCATED state as + // soon as possible. + allocatedTasks = append(allocatedTasks, t) + } + continue + } + + err := a.allocateTask(ctx, t) + if err == nil { + allocatedTasks = append(allocatedTasks, t) + } else if err != errNoChanges { + log.G(ctx).WithError(err).Errorf("failed allocating task %s during init", t.ID) + nc.unallocatedTasks[t.ID] = t + } + } + + if _, err := a.store.Batch(func(batch *store.Batch) error { + for _, t := range allocatedTasks { + if err := a.commitAllocatedTask(ctx, batch, t); err != nil { + log.G(ctx).WithError(err).Errorf("failed committing allocation of task %s during init", t.ID) } } return nil }); err != nil { - return err + log.G(ctx).WithError(err).Error("failed committing allocation of tasks during init") } return nil @@ -298,6 +334,12 @@ func (a *Allocator) doNetworkAlloc(ctx context.Context, ev events.Event) { log.G(ctx).WithError(err).Errorf("Failed allocation for network %s", n.ID) break } + + if _, err := a.store.Batch(func(batch *store.Batch) error { + return a.commitAllocatedNetwork(ctx, batch, n) + }); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to commit allocation for network %s", n.ID) + } case state.EventDeleteNetwork: n := v.Network.Copy() @@ -319,6 +361,12 @@ func (a *Allocator) doNetworkAlloc(ctx context.Context, ev events.Event) { log.G(ctx).WithError(err).Errorf("Failed allocation for service %s", s.ID) break } + + if _, err := a.store.Batch(func(batch *store.Batch) error { + return a.commitAllocatedService(ctx, batch, s) + }); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to commit allocation for service %s", s.ID) + } case state.EventUpdateService: s := v.Service.Copy() @@ -330,6 +378,12 @@ func (a *Allocator) doNetworkAlloc(ctx context.Context, ev events.Event) { log.G(ctx).WithError(err).Errorf("Failed allocation during update of service %s", s.ID) break } + + if _, err := a.store.Batch(func(batch *store.Batch) error { + return a.commitAllocatedService(ctx, batch, s) + }); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to commit allocation during update for service %s", s.ID) + } case state.EventDeleteService: s := v.Service.Copy() @@ -387,6 +441,13 @@ func (a *Allocator) doNodeAlloc(ctx context.Context, ev events.Event) { node.Attachment.Network = nc.ingressNetwork.Copy() if err := a.allocateNode(ctx, node); err != nil { log.G(ctx).WithError(err).Errorf("Failed to allocate network resources for node %s", node.ID) + return + } + + if _, err := a.store.Batch(func(batch *store.Batch) error { + return a.commitAllocatedNode(ctx, batch, node) + }); err != nil { + log.G(ctx).WithError(err).Errorf("Failed to commit allocation of network resources for node %s", node.ID) } } } @@ -428,6 +489,28 @@ func taskUpdateEndpoint(t *api.Task, endpoint *api.Endpoint) { t.Endpoint = endpoint.Copy() } +func isIngressNetworkNeeded(s *api.Service) bool { + if s == nil { + return false + } + + if s.Spec.Endpoint == nil { + return false + } + + for _, p := range s.Spec.Endpoint.Ports { + // The service to which this task belongs is trying to + // expose ports with PublishMode as Ingress to the + // external world. Automatically attach the task to + // the ingress network. + if p.PublishMode == api.PublishModeIngress { + return true + } + } + + return false +} + func (a *Allocator) taskCreateNetworkAttachments(t *api.Task, s *api.Service) { // If task network attachments have already been filled in no // need to do anything else. @@ -436,11 +519,7 @@ func (a *Allocator) taskCreateNetworkAttachments(t *api.Task, s *api.Service) { } var networks []*api.NetworkAttachment - - // The service to which this task belongs is trying to expose - // ports to the external world. Automatically attach the task - // to the ingress network. - if s != nil && s.Spec.Endpoint != nil && len(s.Spec.Endpoint.Ports) != 0 { + if isIngressNetworkNeeded(s) { networks = append(networks, &api.NetworkAttachment{Network: a.netCtx.ingressNetwork}) } @@ -503,7 +582,7 @@ func (a *Allocator) doTaskAlloc(ctx context.Context, ev events.Event) { // If we are already in allocated state, there is // absolutely nothing else to do. - if t.Status.State >= api.TaskStateAllocated { + if t.Status.State >= api.TaskStatePending { delete(nc.unallocatedTasks, t.ID) return } @@ -537,31 +616,22 @@ func (a *Allocator) doTaskAlloc(ctx context.Context, ev events.Event) { } func (a *Allocator) allocateNode(ctx context.Context, node *api.Node) error { - nc := a.netCtx - - if err := nc.nwkAllocator.AllocateNode(node); err != nil { - return err - } - - if err := a.store.Update(func(tx store.Tx) error { - for { - err := store.UpdateNode(tx, node) - if err != nil && err != store.ErrSequenceConflict { - return errors.Wrapf(err, "failed updating state in store transaction for node %s", node.ID) - } + return a.netCtx.nwkAllocator.AllocateNode(node) +} - if err == store.ErrSequenceConflict { - storeNode := store.GetNode(tx, node.ID) - storeNode.Attachment = node.Attachment.Copy() - node = storeNode - continue - } +func (a *Allocator) commitAllocatedNode(ctx context.Context, batch *store.Batch, node *api.Node) error { + if err := batch.Update(func(tx store.Tx) error { + err := store.UpdateNode(tx, node) - break + if err == store.ErrSequenceConflict { + storeNode := store.GetNode(tx, node.ID) + storeNode.Attachment = node.Attachment.Copy() + err = store.UpdateNode(tx, storeNode) } - return nil + + return errors.Wrapf(err, "failed updating state in store transaction for node %s", node.ID) }); err != nil { - if err := nc.nwkAllocator.DeallocateNode(node); err != nil { + if err := a.netCtx.nwkAllocator.DeallocateNode(node); err != nil { log.G(ctx).WithError(err).Errorf("failed rolling back allocation of node %s", node.ID) } @@ -586,7 +656,7 @@ func (a *Allocator) allocateService(ctx context.Context, s *api.Service) error { // The service is trying to expose ports to the external // world. Automatically attach the service to the ingress // network only if it is not already done. - if len(s.Spec.Endpoint.Ports) != 0 { + if isIngressNetworkNeeded(s) { var found bool for _, vip := range s.Endpoint.VirtualIPs { if vip.NetworkID == nc.ingressNetwork.ID { @@ -616,7 +686,7 @@ func (a *Allocator) allocateService(ctx context.Context, s *api.Service) error { // If the service doesn't expose ports any more and if we have // any lingering virtual IP references for ingress network // clean them up here. - if s.Spec.Endpoint == nil || len(s.Spec.Endpoint.Ports) == 0 { + if !isIngressNetworkNeeded(s) { if s.Endpoint != nil { for i, vip := range s.Endpoint.VirtualIPs { if vip.NetworkID == nc.ingressNetwork.ID { @@ -628,27 +698,22 @@ func (a *Allocator) allocateService(ctx context.Context, s *api.Service) error { } } } + return nil +} - if err := a.store.Update(func(tx store.Tx) error { - for { - err := store.UpdateService(tx, s) - - if err != nil && err != store.ErrSequenceConflict { - return errors.Wrapf(err, "failed updating state in store transaction for service %s", s.ID) - } +func (a *Allocator) commitAllocatedService(ctx context.Context, batch *store.Batch, s *api.Service) error { + if err := batch.Update(func(tx store.Tx) error { + err := store.UpdateService(tx, s) - if err == store.ErrSequenceConflict { - storeService := store.GetService(tx, s.ID) - storeService.Endpoint = s.Endpoint - s = storeService - continue - } - - break + if err == store.ErrSequenceConflict { + storeService := store.GetService(tx, s.ID) + storeService.Endpoint = s.Endpoint + err = store.UpdateService(tx, storeService) } - return nil + + return errors.Wrapf(err, "failed updating state in store transaction for service %s", s.ID) }); err != nil { - if err := nc.nwkAllocator.ServiceDeallocate(s); err != nil { + if err := a.netCtx.nwkAllocator.ServiceDeallocate(s); err != nil { log.G(ctx).WithError(err).Errorf("failed rolling back allocation of service %s", s.ID) } @@ -666,13 +731,17 @@ func (a *Allocator) allocateNetwork(ctx context.Context, n *api.Network) error { return errors.Wrapf(err, "failed during network allocation for network %s", n.ID) } - if err := a.store.Update(func(tx store.Tx) error { + return nil +} + +func (a *Allocator) commitAllocatedNetwork(ctx context.Context, batch *store.Batch, n *api.Network) error { + if err := batch.Update(func(tx store.Tx) error { if err := store.UpdateNetwork(tx, n); err != nil { return errors.Wrapf(err, "failed updating state in store transaction for network %s", n.ID) } return nil }); err != nil { - if err := nc.nwkAllocator.Deallocate(n); err != nil { + if err := a.netCtx.nwkAllocator.Deallocate(n); err != nil { log.G(ctx).WithError(err).Errorf("failed rolling back allocation of network %s", n.ID) } @@ -682,15 +751,8 @@ func (a *Allocator) allocateNetwork(ctx context.Context, n *api.Network) error { return nil } -func (a *Allocator) allocateTask(ctx context.Context, tx store.Tx, t *api.Task) (*api.Task, error) { +func (a *Allocator) allocateTask(ctx context.Context, t *api.Task) (err error) { taskUpdated := false - - // Get the latest task state from the store before updating. - storeT := store.GetTask(tx, t.ID) - if storeT == nil { - return nil, fmt.Errorf("could not find task %s while trying to update network allocation", t.ID) - } - nc := a.netCtx // We might be here even if a task allocation has already @@ -698,163 +760,195 @@ func (a *Allocator) allocateTask(ctx context.Context, tx store.Tx, t *api.Task) // cases skip allocation and go straight ahead to updating the // store. if !nc.nwkAllocator.IsTaskAllocated(t) { - if t.ServiceID != "" { - s := store.GetService(tx, t.ServiceID) - if s == nil { - return nil, fmt.Errorf("could not find service %s", t.ServiceID) - } + a.store.View(func(tx store.ReadTx) { + if t.ServiceID != "" { + s := store.GetService(tx, t.ServiceID) + if s == nil { + err = fmt.Errorf("could not find service %s", t.ServiceID) + return + } + + if !nc.nwkAllocator.IsServiceAllocated(s) { + err = fmt.Errorf("service %s to which this task %s belongs has pending allocations", s.ID, t.ID) + return + } - if !nc.nwkAllocator.IsServiceAllocated(s) { - return nil, fmt.Errorf("service %s to which this task %s belongs has pending allocations", s.ID, t.ID) + if s.Endpoint != nil { + taskUpdateEndpoint(t, s.Endpoint) + taskUpdated = true + } } - taskUpdateEndpoint(t, s.Endpoint) - } + for _, na := range t.Networks { + n := store.GetNetwork(tx, na.Network.ID) + if n == nil { + err = fmt.Errorf("failed to retrieve network %s while allocating task %s", na.Network.ID, t.ID) + return + } - for _, na := range t.Networks { - n := store.GetNetwork(tx, na.Network.ID) - if n == nil { - return nil, fmt.Errorf("failed to retrieve network %s while allocating task %s", na.Network.ID, t.ID) - } + if !nc.nwkAllocator.IsAllocated(n) { + err = fmt.Errorf("network %s attached to task %s not allocated yet", n.ID, t.ID) + return + } - if !nc.nwkAllocator.IsAllocated(n) { - return nil, fmt.Errorf("network %s attached to task %s not allocated yet", n.ID, t.ID) + na.Network = n } - na.Network = n - } + if err = nc.nwkAllocator.AllocateTask(t); err != nil { + err = errors.Wrapf(err, "failed during networktask allocation for task %s", t.ID) + return + } + if nc.nwkAllocator.IsTaskAllocated(t) { + taskUpdated = true + } + }) - if err := nc.nwkAllocator.AllocateTask(t); err != nil { - return nil, errors.Wrapf(err, "failed during networktask allocation for task %s", t.ID) - } - if nc.nwkAllocator.IsTaskAllocated(t) { - taskUpdateNetworks(storeT, t.Networks) - taskUpdateEndpoint(storeT, t.Endpoint) - taskUpdated = true + if err != nil { + return err } } // Update the network allocations and moving to - // ALLOCATED state on top of the latest store state. + // PENDING state on top of the latest store state. if a.taskAllocateVote(networkVoter, t.ID) { - if storeT.Status.State < api.TaskStateAllocated { - updateTaskStatus(storeT, api.TaskStateAllocated, "allocated") + if t.Status.State < api.TaskStatePending { + updateTaskStatus(t, api.TaskStatePending, allocatedStatusMessage) taskUpdated = true } } - if taskUpdated { - if err := store.UpdateTask(tx, storeT); err != nil { - return nil, errors.Wrapf(err, "failed updating state in store transaction for task %s", storeT.ID) - } + if !taskUpdated { + return errNoChanges } - return storeT, nil + return nil +} + +func (a *Allocator) commitAllocatedTask(ctx context.Context, batch *store.Batch, t *api.Task) error { + return batch.Update(func(tx store.Tx) error { + err := store.UpdateTask(tx, t) + + if err == store.ErrSequenceConflict { + storeTask := store.GetTask(tx, t.ID) + taskUpdateNetworks(storeTask, t.Networks) + taskUpdateEndpoint(storeTask, t.Endpoint) + if storeTask.Status.State < api.TaskStatePending { + storeTask.Status = t.Status + } + err = store.UpdateTask(tx, storeTask) + } + + return errors.Wrapf(err, "failed updating state in store transaction for task %s", t.ID) + }) } func (a *Allocator) procUnallocatedNetworks(ctx context.Context) { nc := a.netCtx + var allocatedNetworks []*api.Network for _, n := range nc.unallocatedNetworks { if !nc.nwkAllocator.IsAllocated(n) { if err := a.allocateNetwork(ctx, n); err != nil { - log.G(ctx).Debugf("Failed allocation of unallocated network %s: %v", n.ID, err) + log.G(ctx).WithError(err).Debugf("Failed allocation of unallocated network %s", n.ID) + continue + } + allocatedNetworks = append(allocatedNetworks, n) + } + } + + if len(allocatedNetworks) == 0 { + return + } + + committed, err := a.store.Batch(func(batch *store.Batch) error { + for _, n := range allocatedNetworks { + if err := a.commitAllocatedNetwork(ctx, batch, n); err != nil { + log.G(ctx).WithError(err).Debugf("Failed to commit allocation of unallocated network %s", n.ID) continue } } + return nil + }) + if err != nil { + log.G(ctx).WithError(err).Error("Failed to commit allocation of unallocated networks") + } + + for _, n := range allocatedNetworks[:committed] { delete(nc.unallocatedNetworks, n.ID) } } func (a *Allocator) procUnallocatedServices(ctx context.Context) { nc := a.netCtx + var allocatedServices []*api.Service for _, s := range nc.unallocatedServices { if !nc.nwkAllocator.IsServiceAllocated(s) { if err := a.allocateService(ctx, s); err != nil { - log.G(ctx).Debugf("Failed allocation of unallocated service %s: %v", s.ID, err) + log.G(ctx).WithError(err).Debugf("Failed allocation of unallocated service %s", s.ID) continue } + allocatedServices = append(allocatedServices, s) } - - delete(nc.unallocatedServices, s.ID) } -} -func (a *Allocator) procUnallocatedTasksNetwork(ctx context.Context) { - nc := a.netCtx - tasks := make([]*api.Task, 0, len(nc.unallocatedTasks)) + if len(allocatedServices) == 0 { + return + } committed, err := a.store.Batch(func(batch *store.Batch) error { - for _, t := range nc.unallocatedTasks { - var allocatedT *api.Task - err := batch.Update(func(tx store.Tx) error { - var err error - allocatedT, err = a.allocateTask(ctx, tx, t) - return err - }) - - if err != nil { - log.G(ctx).WithError(err).Error("task allocation failure") + for _, s := range allocatedServices { + if err := a.commitAllocatedService(ctx, batch, s); err != nil { + log.G(ctx).WithError(err).Debugf("Failed to commit allocation of unallocated service %s", s.ID) continue } - - tasks = append(tasks, allocatedT) } - return nil }) if err != nil { - log.G(ctx).WithError(err).Error("failed a store batch operation while processing unallocated tasks") + log.G(ctx).WithError(err).Error("Failed to commit allocation of unallocated services") } - var retryCnt int - for len(tasks) != 0 { - var err error + for _, s := range allocatedServices[:committed] { + delete(nc.unallocatedServices, s.ID) + } +} - for _, t := range tasks[:committed] { - delete(nc.unallocatedTasks, t.ID) - } +func (a *Allocator) procUnallocatedTasksNetwork(ctx context.Context) { + nc := a.netCtx + allocatedTasks := make([]*api.Task, 0, len(nc.unallocatedTasks)) - tasks = tasks[committed:] - if len(tasks) == 0 { - break + for _, t := range nc.unallocatedTasks { + if err := a.allocateTask(ctx, t); err == nil { + allocatedTasks = append(allocatedTasks, t) + } else if err != errNoChanges { + log.G(ctx).WithError(err).Error("task allocation failure") } + } - updatedTasks := make([]*api.Task, 0, len(tasks)) - committed, err = a.store.Batch(func(batch *store.Batch) error { - for _, t := range tasks { - err := batch.Update(func(tx store.Tx) error { - return store.UpdateTask(tx, t) - }) + if len(allocatedTasks) == 0 { + return + } - if err != nil { - log.G(ctx).WithError(err).Error("allocated task store update failure") - continue - } + committed, err := a.store.Batch(func(batch *store.Batch) error { + for _, t := range allocatedTasks { + err := a.commitAllocatedTask(ctx, batch, t) - updatedTasks = append(updatedTasks, t) + if err != nil { + log.G(ctx).WithError(err).Error("task allocation commit failure") + continue } - - return nil - }) - if err != nil { - log.G(ctx).WithError(err).Error("failed a store batch operation while processing unallocated tasks") } - tasks = updatedTasks + return nil + }) - select { - case <-ctx.Done(): - return - default: - } + if err != nil { + log.G(ctx).WithError(err).Error("failed a store batch operation while processing unallocated tasks") + } - retryCnt++ - if retryCnt >= 3 { - log.G(ctx).Error("failed to complete batch update of allocated tasks after 3 retries") - break - } + for _, t := range allocatedTasks[:committed] { + delete(nc.unallocatedTasks, t.ID) } } diff --git a/vendor/src/github.com/docker/swarmkit/manager/allocator/networkallocator/portallocator.go b/vendor/src/github.com/docker/swarmkit/manager/allocator/networkallocator/portallocator.go index cbc12575f102c..21546d72b2bda 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/allocator/networkallocator/portallocator.go +++ b/vendor/src/github.com/docker/swarmkit/manager/allocator/networkallocator/portallocator.go @@ -128,8 +128,12 @@ func (pa *portAllocator) serviceAllocatePorts(s *api.Service) (err error) { for _, portConfig := range portConfigs { // Make a copy of port config to create runtime state portState := portConfig.Copy() - if err = pa.portSpaces[portState.Protocol].allocate(portState); err != nil { - return + + // Do an actual allocation only if the PublishMode is Ingress + if portConfig.PublishMode == api.PublishModeIngress { + if err = pa.portSpaces[portState.Protocol].allocate(portState); err != nil { + return + } } if s.Endpoint == nil { @@ -148,6 +152,12 @@ func (pa *portAllocator) serviceDeallocatePorts(s *api.Service) { } for _, portState := range s.Endpoint.Ports { + // Do an actual free only if the PublishMode is + // Ingress + if portState.PublishMode != api.PublishModeIngress { + continue + } + pa.portSpaces[portState.Protocol].free(portState) } @@ -177,6 +187,11 @@ func (pa *portAllocator) isPortsAllocated(s *api.Service) bool { } for i, portConfig := range s.Spec.Endpoint.Ports { + // Ignore ports which are not PublishModeIngress + if portConfig.PublishMode != api.PublishModeIngress { + continue + } + // The port configuration slice and port state slice // are expected to be in the same order. portState := s.Endpoint.Ports[i] diff --git a/vendor/src/github.com/docker/swarmkit/manager/constraint/constraint.go b/vendor/src/github.com/docker/swarmkit/manager/constraint/constraint.go index acd4245c6155a..ae636cb10945a 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/constraint/constraint.go +++ b/vendor/src/github.com/docker/swarmkit/manager/constraint/constraint.go @@ -125,6 +125,26 @@ func NodeMatches(constraints []Constraint, n *api.Node) bool { if !constraint.Match(n.Spec.Role.String()) { return false } + case strings.EqualFold(constraint.key, "node.platform.os"): + if n.Description == nil || n.Description.Platform == nil { + if !constraint.Match("") { + return false + } + continue + } + if !constraint.Match(n.Description.Platform.OS) { + return false + } + case strings.EqualFold(constraint.key, "node.platform.arch"): + if n.Description == nil || n.Description.Platform == nil { + if !constraint.Match("") { + return false + } + continue + } + if !constraint.Match(n.Description.Platform.Architecture) { + return false + } // node labels constraint in form like 'node.labels.key==value' case len(constraint.key) > len(nodeLabelPrefix) && strings.EqualFold(constraint.key[:len(nodeLabelPrefix)], nodeLabelPrefix): diff --git a/vendor/src/github.com/docker/swarmkit/manager/controlapi/cluster.go b/vendor/src/github.com/docker/swarmkit/manager/controlapi/cluster.go index d3654ca72a4b8..fd3cb3df9947c 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/controlapi/cluster.go +++ b/vendor/src/github.com/docker/swarmkit/manager/controlapi/cluster.go @@ -2,6 +2,7 @@ package controlapi import ( "strings" + "time" "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/ca" @@ -12,6 +13,12 @@ import ( "google.golang.org/grpc/codes" ) +const ( + // expiredCertGrace is the amount of time to keep a node in the + // blacklist beyond its certificate expiration timestamp. + expiredCertGrace = 24 * time.Hour * 7 +) + func validateClusterSpec(spec *api.ClusterSpec) error { if spec == nil { return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error()) @@ -98,6 +105,8 @@ func (s *Server) UpdateCluster(ctx context.Context, request *api.UpdateClusterRe cluster.Meta.Version = *request.ClusterVersion cluster.Spec = *request.Spec.Copy() + expireBlacklistedCerts(cluster) + if request.Rotation.RotateWorkerToken { cluster.RootCA.JoinTokens.Worker = ca.GenerateJoinToken(s.rootCA) } @@ -202,7 +211,7 @@ func redactClusters(clusters []*api.Cluster) []*api.Cluster { CACertHash: cluster.RootCA.CACertHash, JoinTokens: cluster.RootCA.JoinTokens, }, - RemovedNodes: cluster.RemovedNodes, + BlacklistedCertificates: cluster.BlacklistedCertificates, } redactedClusters = append(redactedClusters, newCluster) @@ -210,3 +219,18 @@ func redactClusters(clusters []*api.Cluster) []*api.Cluster { return redactedClusters } + +func expireBlacklistedCerts(cluster *api.Cluster) { + nowMinusGrace := time.Now().Add(-expiredCertGrace) + + for cn, blacklistedCert := range cluster.BlacklistedCertificates { + if blacklistedCert.Expiry == nil { + continue + } + + expiry, err := ptypes.Timestamp(blacklistedCert.Expiry) + if err == nil && nowMinusGrace.After(expiry) { + delete(cluster.BlacklistedCertificates, cn) + } + } +} diff --git a/vendor/src/github.com/docker/swarmkit/manager/controlapi/node.go b/vendor/src/github.com/docker/swarmkit/manager/controlapi/node.go index 44e62b32222fd..629dd40142ea6 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/controlapi/node.go +++ b/vendor/src/github.com/docker/swarmkit/manager/controlapi/node.go @@ -301,7 +301,7 @@ func (s *Server) RemoveNode(ctx context.Context, request *api.RemoveNodeRequest) } cluster := clusters[0] - removedNode := &api.RemovedNode{ID: node.ID} + blacklistedCert := &api.BlacklistedCertificate{} // Set an expiry time for this RemovedNode if a certificate // exists and can be parsed. @@ -312,13 +312,18 @@ func (s *Server) RemoveNode(ctx context.Context, request *api.RemoveNodeRequest) if err == nil && !X509Cert.NotAfter.IsZero() { expiry, err := ptypes.TimestampProto(X509Cert.NotAfter) if err == nil { - removedNode.Expiry = expiry + blacklistedCert.Expiry = expiry } } } } - cluster.RemovedNodes = append(cluster.RemovedNodes, removedNode) + if cluster.BlacklistedCertificates == nil { + cluster.BlacklistedCertificates = make(map[string]*api.BlacklistedCertificate) + } + cluster.BlacklistedCertificates[node.ID] = blacklistedCert + + expireBlacklistedCerts(cluster) if err := store.UpdateCluster(tx, cluster); err != nil { return err diff --git a/vendor/src/github.com/docker/swarmkit/manager/controlapi/secret.go b/vendor/src/github.com/docker/swarmkit/manager/controlapi/secret.go index a1164619ae995..ba0b86d5bb646 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/controlapi/secret.go +++ b/vendor/src/github.com/docker/swarmkit/manager/controlapi/secret.go @@ -48,9 +48,50 @@ func (s *Server) GetSecret(ctx context.Context, request *api.GetSecretRequest) ( return nil, grpc.Errorf(codes.NotFound, "secret %s not found", request.SecretID) } + secret.Spec.Data = nil // clean the actual secret data so it's never returned return &api.GetSecretResponse{Secret: secret}, nil } +// UpdateSecret updates a Secret referenced by SecretID with the given SecretSpec. +// - Returns `NotFound` if the Secret is not found. +// - Returns `InvalidArgument` if the SecretSpec is malformed or anything other than Labels is changed +// - Returns an error if the update fails. +func (s *Server) UpdateSecret(ctx context.Context, request *api.UpdateSecretRequest) (*api.UpdateSecretResponse, error) { + if request.SecretID == "" || request.SecretVersion == nil { + return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error()) + } + + var secret *api.Secret + err := s.store.Update(func(tx store.Tx) error { + secret = store.GetSecret(tx, request.SecretID) + if secret == nil { + return nil + } + + if secret.Spec.Annotations.Name != request.Spec.Annotations.Name || request.Spec.Data != nil { + return grpc.Errorf(codes.InvalidArgument, "only updates to Labels are allowed") + } + + // We only allow updating Labels + secret.Meta.Version = *request.SecretVersion + secret.Spec.Annotations.Labels = request.Spec.Annotations.Labels + + return store.UpdateSecret(tx, secret) + }) + if err != nil { + return nil, err + } + if secret == nil { + return nil, grpc.Errorf(codes.NotFound, "secret %s not found", request.SecretID) + } + + // WARN: we should never return the actual secret data here. We need to redact the private fields first. + secret.Spec.Data = nil + return &api.UpdateSecretResponse{ + Secret: secret, + }, nil +} + // ListSecrets returns a `ListSecretResponse` with a list all non-internal `Secret`s being // managed, or all secrets matching any name in `ListSecretsRequest.Names`, any // name prefix in `ListSecretsRequest.NamePrefixes`, any id in diff --git a/vendor/src/github.com/docker/swarmkit/manager/controlapi/service.go b/vendor/src/github.com/docker/swarmkit/manager/controlapi/service.go index d484ced37e66f..5b7d82a5b13a1 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/controlapi/service.go +++ b/vendor/src/github.com/docker/swarmkit/manager/controlapi/service.go @@ -3,6 +3,7 @@ package controlapi import ( "errors" "reflect" + "regexp" "strconv" "github.com/docker/distribution/reference" @@ -18,9 +19,13 @@ import ( var ( errNetworkUpdateNotSupported = errors.New("changing network in service is not supported") + errRenameNotSupported = errors.New("renaming services is not supported") errModeChangeNotAllowed = errors.New("service mode change is not allowed") ) +// Regexp pattern for hostname to conform RFC 1123 +var hostnamePattern = regexp.MustCompile("^(([[:alnum:]]|[[:alnum:]][[:alnum:]\\-]*[[:alnum:]])\\.)*([[:alnum:]]|[[:alnum:]][[:alnum:]\\-]*[[:alnum:]])$") + func validateResources(r *api.Resources) error { if r == nil { return nil @@ -102,6 +107,43 @@ func validateUpdate(uc *api.UpdateConfig) error { return nil } +func validateContainerSpec(container *api.ContainerSpec) error { + if container == nil { + return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: missing in service spec") + } + + if err := validateHostname(container.Hostname); err != nil { + return err + } + + if container.Image == "" { + return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: image reference must be provided") + } + + if _, err := reference.ParseNamed(container.Image); err != nil { + return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: %q is not a valid repository/tag", container.Image) + } + + mountMap := make(map[string]bool) + for _, mount := range container.Mounts { + if _, exists := mountMap[mount.Target]; exists { + return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: duplicate mount point: %s", mount.Target) + } + mountMap[mount.Target] = true + } + + return nil +} + +func validateHostname(hostname string) error { + if hostname != "" { + if len(hostname) > 63 || !hostnamePattern.MatchString(hostname) { + return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: %s is not valid hostname", hostname) + } + } + return nil +} + func validateTask(taskSpec api.TaskSpec) error { if err := validateResourceRequirements(taskSpec.Resources); err != nil { return err @@ -124,25 +166,8 @@ func validateTask(taskSpec api.TaskSpec) error { return grpc.Errorf(codes.Unimplemented, "RuntimeSpec: unimplemented runtime in service spec") } - container := taskSpec.GetContainer() - if container == nil { - return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: missing in service spec") - } - - if container.Image == "" { - return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: image reference must be provided") - } - - if _, err := reference.ParseNamed(container.Image); err != nil { - return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: %q is not a valid repository/tag", container.Image) - } - - mountMap := make(map[string]bool) - for _, mount := range container.Mounts { - if _, exists := mountMap[mount.Target]; exists { - return grpc.Errorf(codes.InvalidArgument, "ContainerSpec: duplicate mount point: %s", mount.Target) - } - mountMap[mount.Target] = true + if err := validateContainerSpec(taskSpec.GetContainer()); err != nil { + return err } return nil @@ -279,6 +304,25 @@ func (s *Server) checkPortConflicts(spec *api.ServiceSpec, serviceID string) err return nil } +// checkSecretConflicts finds if the passed in spec has secrets with conflicting targets. +func (s *Server) checkSecretConflicts(spec *api.ServiceSpec) error { + container := spec.Task.GetContainer() + if container == nil { + return nil + } + + existingTargets := make(map[string]string) + for _, secretRef := range container.Secrets { + if prevSecretName, ok := existingTargets[secretRef.Target]; ok { + return grpc.Errorf(codes.InvalidArgument, "secret references '%s' and '%s' have a conflicting target: '%s'", prevSecretName, secretRef.SecretName, secretRef.Target) + } + + existingTargets[secretRef.Target] = secretRef.SecretName + } + + return nil +} + // CreateService creates and return a Service based on the provided ServiceSpec. // - Returns `InvalidArgument` if the ServiceSpec is malformed. // - Returns `Unimplemented` if the ServiceSpec references unimplemented features. @@ -297,6 +341,10 @@ func (s *Server) CreateService(ctx context.Context, request *api.CreateServiceRe return nil, err } + if err := s.checkSecretConflicts(request.Spec); err != nil { + return nil, err + } + // TODO(aluzzardi): Consider using `Name` as a primary key to handle // duplicate creations. See #65 service := &api.Service{ @@ -364,6 +412,10 @@ func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRe } } + if err := s.checkSecretConflicts(request.Spec); err != nil { + return nil, err + } + err := s.store.Update(func(tx store.Tx) error { service = store.GetService(tx, request.ServiceID) if service == nil { @@ -390,6 +442,11 @@ func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRe if reflect.TypeOf(service.Spec.Mode) != reflect.TypeOf(request.Spec.Mode) { return errModeChangeNotAllowed } + + if service.Spec.Annotations.Name != request.Spec.Annotations.Name { + return errRenameNotSupported + } + service.Meta.Version = *request.ServiceVersion service.PreviousSpec = service.Spec.Copy() service.Spec = *request.Spec.Copy() diff --git a/vendor/src/github.com/docker/swarmkit/manager/controlapi/task.go b/vendor/src/github.com/docker/swarmkit/manager/controlapi/task.go index 10863a4fbe8fc..9a9db596e1b98 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/controlapi/task.go +++ b/vendor/src/github.com/docker/swarmkit/manager/controlapi/task.go @@ -2,6 +2,7 @@ package controlapi import ( "github.com/docker/swarmkit/api" + "github.com/docker/swarmkit/api/naming" "github.com/docker/swarmkit/manager/state/store" "golang.org/x/net/context" "google.golang.org/grpc" @@ -104,10 +105,10 @@ func (s *Server) ListTasks(ctx context.Context, request *api.ListTasksRequest) ( if request.Filters != nil { tasks = filterTasks(tasks, func(e *api.Task) bool { - return filterContains(store.TaskName(e), request.Filters.Names) + return filterContains(naming.Task(e), request.Filters.Names) }, func(e *api.Task) bool { - return filterContainsPrefix(store.TaskName(e), request.Filters.NamePrefixes) + return filterContainsPrefix(naming.Task(e), request.Filters.NamePrefixes) }, func(e *api.Task) bool { return filterContainsPrefix(e.ID, request.Filters.IDPrefixes) diff --git a/vendor/src/github.com/docker/swarmkit/manager/manager.go b/vendor/src/github.com/docker/swarmkit/manager/manager.go index f329a30831cfa..749d66bd78143 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/manager.go +++ b/vendor/src/github.com/docker/swarmkit/manager/manager.go @@ -7,6 +7,7 @@ import ( "net" "os" "path/filepath" + "runtime" "sync" "syscall" "time" @@ -21,12 +22,16 @@ import ( "github.com/docker/swarmkit/manager/dispatcher" "github.com/docker/swarmkit/manager/health" "github.com/docker/swarmkit/manager/keymanager" - "github.com/docker/swarmkit/manager/orchestrator" + "github.com/docker/swarmkit/manager/orchestrator/constraintenforcer" + "github.com/docker/swarmkit/manager/orchestrator/global" + "github.com/docker/swarmkit/manager/orchestrator/replicated" + "github.com/docker/swarmkit/manager/orchestrator/taskreaper" "github.com/docker/swarmkit/manager/resourceapi" "github.com/docker/swarmkit/manager/scheduler" "github.com/docker/swarmkit/manager/state/raft" "github.com/docker/swarmkit/manager/state/store" "github.com/docker/swarmkit/protobuf/ptypes" + "github.com/docker/swarmkit/xnet" "github.com/pkg/errors" "golang.org/x/net/context" "google.golang.org/grpc" @@ -82,10 +87,10 @@ type Manager struct { caserver *ca.Server dispatcher *dispatcher.Dispatcher - replicatedOrchestrator *orchestrator.ReplicatedOrchestrator - globalOrchestrator *orchestrator.GlobalOrchestrator - taskReaper *orchestrator.TaskReaper - constraintEnforcer *orchestrator.ConstraintEnforcer + replicatedOrchestrator *replicated.Orchestrator + globalOrchestrator *global.Orchestrator + taskReaper *taskreaper.TaskReaper + constraintEnforcer *constraintenforcer.ConstraintEnforcer scheduler *scheduler.Scheduler allocator *allocator.Allocator keyManager *keymanager.KeyManager @@ -128,11 +133,13 @@ func New(config *Config) (*Manager, error) { // externally-reachable address. tcpAddr := config.AdvertiseAddr + var tcpAddrPort string if tcpAddr == "" { // Otherwise, we know we are joining an existing swarm. Use a // wildcard address to trigger remote autodetection of our // address. - _, tcpAddrPort, err := net.SplitHostPort(config.ProtoAddr["tcp"]) + var err error + _, tcpAddrPort, err = net.SplitHostPort(config.ProtoAddr["tcp"]) if err != nil { return nil, fmt.Errorf("missing or invalid listen address %s", config.ProtoAddr["tcp"]) } @@ -143,12 +150,15 @@ func New(config *Config) (*Manager, error) { tcpAddr = net.JoinHostPort("0.0.0.0", tcpAddrPort) } - err := os.MkdirAll(filepath.Dir(config.ProtoAddr["unix"]), 0700) - if err != nil { - return nil, errors.Wrap(err, "failed to create socket directory") + // don't create a socket directory if we're on windows. we used named pipe + if runtime.GOOS != "windows" { + err := os.MkdirAll(filepath.Dir(config.ProtoAddr["unix"]), 0700) + if err != nil { + return nil, errors.Wrap(err, "failed to create socket directory") + } } - err = os.MkdirAll(config.StateDir, 0700) + err := os.MkdirAll(config.StateDir, 0700) if err != nil { return nil, errors.Wrap(err, "failed to create state directory") } @@ -166,7 +176,13 @@ func New(config *Config) (*Manager, error) { listeners = make(map[string]net.Listener) for proto, addr := range config.ProtoAddr { - l, err := net.Listen(proto, addr) + var l net.Listener + var err error + if proto == "unix" { + l, err = xnet.ListenLocal(addr) + } else { + l, err = net.Listen(proto, addr) + } // A unix socket may fail to bind if the file already // exists. Try replacing the file. @@ -179,14 +195,14 @@ func New(config *Config) (*Manager, error) { } if proto == "unix" && unwrappedErr == syscall.EADDRINUSE { os.Remove(addr) - l, err = net.Listen(proto, addr) + l, err = xnet.ListenLocal(addr) if err != nil { return nil, err } } else if err != nil { return nil, err } - if proto == "tcp" { + if proto == "tcp" && tcpAddrPort == "0" { // in case of 0 port tcpAddr = l.Addr().String() } @@ -263,9 +279,9 @@ func (m *Manager) Run(parent context.Context) error { authorize := func(ctx context.Context, roles []string) error { var ( - removedNodes []*api.RemovedNode - clusters []*api.Cluster - err error + blacklistedCerts map[string]*api.BlacklistedCertificate + clusters []*api.Cluster + err error ) m.raftNode.MemoryStore().View(func(readTx store.ReadTx) { @@ -276,11 +292,11 @@ func (m *Manager) Run(parent context.Context) error { // Not having a cluster object yet means we can't check // the blacklist. if err == nil && len(clusters) == 1 { - removedNodes = clusters[0].RemovedNodes + blacklistedCerts = clusters[0].BlacklistedCertificates } // Authorize the remote roles, ensure they can only be forwarded by managers - _, err = ca.AuthorizeForwardedRoleAndOrg(ctx, roles, []string{ca.ManagerRole}, m.config.SecurityConfig.ClientTLSCreds.Organization(), removedNodes) + _, err = ca.AuthorizeForwardedRoleAndOrg(ctx, roles, []string{ca.ManagerRole}, m.config.SecurityConfig.ClientTLSCreds.Organization(), blacklistedCerts) return err } @@ -651,10 +667,10 @@ func (m *Manager) becomeLeader(ctx context.Context) { log.G(ctx).WithError(err).Error("root key-encrypting-key rotation failed") } - m.replicatedOrchestrator = orchestrator.NewReplicatedOrchestrator(s) - m.constraintEnforcer = orchestrator.NewConstraintEnforcer(s) - m.globalOrchestrator = orchestrator.NewGlobalOrchestrator(s) - m.taskReaper = orchestrator.NewTaskReaper(s) + m.replicatedOrchestrator = replicated.NewReplicatedOrchestrator(s) + m.constraintEnforcer = constraintenforcer.New(s) + m.globalOrchestrator = global.NewGlobalOrchestrator(s) + m.taskReaper = taskreaper.New(s) m.scheduler = scheduler.New(s) m.keyManager = keymanager.New(s, keymanager.DefaultConfig()) @@ -706,21 +722,21 @@ func (m *Manager) becomeLeader(ctx context.Context) { } }(m.scheduler) - go func(constraintEnforcer *orchestrator.ConstraintEnforcer) { + go func(constraintEnforcer *constraintenforcer.ConstraintEnforcer) { constraintEnforcer.Run() }(m.constraintEnforcer) - go func(taskReaper *orchestrator.TaskReaper) { + go func(taskReaper *taskreaper.TaskReaper) { taskReaper.Run() }(m.taskReaper) - go func(orchestrator *orchestrator.ReplicatedOrchestrator) { + go func(orchestrator *replicated.Orchestrator) { if err := orchestrator.Run(ctx); err != nil { log.G(ctx).WithError(err).Error("replicated orchestrator exited with an error") } }(m.replicatedOrchestrator) - go func(globalOrchestrator *orchestrator.GlobalOrchestrator) { + go func(globalOrchestrator *global.Orchestrator) { if err := globalOrchestrator.Run(ctx); err != nil { log.G(ctx).WithError(err).Error("global orchestrator exited with an error") } diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/constraint_enforcer.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/constraintenforcer/constraint_enforcer.go similarity index 96% rename from vendor/src/github.com/docker/swarmkit/manager/orchestrator/constraint_enforcer.go rename to vendor/src/github.com/docker/swarmkit/manager/orchestrator/constraintenforcer/constraint_enforcer.go index 77d522f9cca51..1a84b05d7682a 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/constraint_enforcer.go +++ b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/constraintenforcer/constraint_enforcer.go @@ -1,4 +1,4 @@ -package orchestrator +package constraintenforcer import ( "github.com/docker/swarmkit/api" @@ -16,8 +16,8 @@ type ConstraintEnforcer struct { doneChan chan struct{} } -// NewConstraintEnforcer creates a new ConstraintEnforcer. -func NewConstraintEnforcer(store *store.MemoryStore) *ConstraintEnforcer { +// New creates a new ConstraintEnforcer. +func New(store *store.MemoryStore) *ConstraintEnforcer { return &ConstraintEnforcer{ store: store, stopChan: make(chan struct{}), diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/global.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/global/global.go similarity index 85% rename from vendor/src/github.com/docker/swarmkit/manager/orchestrator/global.go rename to vendor/src/github.com/docker/swarmkit/manager/orchestrator/global/global.go index d45bc86ac6fe3..9252d6a831457 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/global.go +++ b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/global/global.go @@ -1,9 +1,12 @@ -package orchestrator +package global import ( "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/log" "github.com/docker/swarmkit/manager/constraint" + "github.com/docker/swarmkit/manager/orchestrator" + "github.com/docker/swarmkit/manager/orchestrator/restart" + "github.com/docker/swarmkit/manager/orchestrator/update" "github.com/docker/swarmkit/manager/state" "github.com/docker/swarmkit/manager/state/store" "golang.org/x/net/context" @@ -16,9 +19,9 @@ type globalService struct { constraints []constraint.Constraint } -// GlobalOrchestrator runs a reconciliation loop to create and destroy -// tasks as necessary for global services. -type GlobalOrchestrator struct { +// Orchestrator runs a reconciliation loop to create and destroy tasks as +// necessary for global services. +type Orchestrator struct { store *store.MemoryStore // nodes is the set of non-drained nodes in the cluster, indexed by node ID nodes map[string]*api.Node @@ -30,17 +33,17 @@ type GlobalOrchestrator struct { // doneChan is closed when the state machine terminates. doneChan chan struct{} - updater *UpdateSupervisor - restarts *RestartSupervisor + updater *update.Supervisor + restarts *restart.Supervisor cluster *api.Cluster // local instance of the cluster } -// NewGlobalOrchestrator creates a new GlobalOrchestrator -func NewGlobalOrchestrator(store *store.MemoryStore) *GlobalOrchestrator { - restartSupervisor := NewRestartSupervisor(store) - updater := NewUpdateSupervisor(store, restartSupervisor) - return &GlobalOrchestrator{ +// NewGlobalOrchestrator creates a new global Orchestrator +func NewGlobalOrchestrator(store *store.MemoryStore) *Orchestrator { + restartSupervisor := restart.NewSupervisor(store) + updater := update.NewSupervisor(store, restartSupervisor) + return &Orchestrator{ store: store, nodes: make(map[string]*api.Node), globalServices: make(map[string]globalService), @@ -51,8 +54,8 @@ func NewGlobalOrchestrator(store *store.MemoryStore) *GlobalOrchestrator { } } -// Run contains the GlobalOrchestrator event loop -func (g *GlobalOrchestrator) Run(ctx context.Context) error { +// Run contains the global orchestrator event loop +func (g *Orchestrator) Run(ctx context.Context) error { defer close(g.doneChan) // Watch changes to services and tasks @@ -98,7 +101,7 @@ func (g *GlobalOrchestrator) Run(ctx context.Context) error { var reconcileServiceIDs []string for _, s := range existingServices { - if isGlobalService(s) { + if orchestrator.IsGlobalService(s) { g.updateService(s) reconcileServiceIDs = append(reconcileServiceIDs, s.ID) } @@ -113,22 +116,22 @@ func (g *GlobalOrchestrator) Run(ctx context.Context) error { case state.EventUpdateCluster: g.cluster = v.Cluster case state.EventCreateService: - if !isGlobalService(v.Service) { + if !orchestrator.IsGlobalService(v.Service) { continue } g.updateService(v.Service) g.reconcileServices(ctx, []string{v.Service.ID}) case state.EventUpdateService: - if !isGlobalService(v.Service) { + if !orchestrator.IsGlobalService(v.Service) { continue } g.updateService(v.Service) g.reconcileServices(ctx, []string{v.Service.ID}) case state.EventDeleteService: - if !isGlobalService(v.Service) { + if !orchestrator.IsGlobalService(v.Service) { continue } - deleteServiceTasks(ctx, g.store, v.Service) + orchestrator.DeleteServiceTasks(ctx, g.store, v.Service) // delete the service from service map delete(g.globalServices, v.Service.ID) g.restarts.ClearServiceHistory(v.Service.ID) @@ -172,14 +175,14 @@ func (g *GlobalOrchestrator) Run(ctx context.Context) error { } // Stop stops the orchestrator. -func (g *GlobalOrchestrator) Stop() { +func (g *Orchestrator) Stop() { close(g.stopChan) <-g.doneChan g.updater.CancelAll() g.restarts.CancelAll() } -func (g *GlobalOrchestrator) removeTasksFromNode(ctx context.Context, node *api.Node) { +func (g *Orchestrator) removeTasksFromNode(ctx context.Context, node *api.Node) { var ( tasks []*api.Task err error @@ -194,7 +197,7 @@ func (g *GlobalOrchestrator) removeTasksFromNode(ctx context.Context, node *api. _, err = g.store.Batch(func(batch *store.Batch) error { for _, t := range tasks { - // GlobalOrchestrator only removes tasks from globalServices + // Global orchestrator only removes tasks from globalServices if _, exists := g.globalServices[t.ServiceID]; exists { g.removeTask(ctx, batch, t) } @@ -206,7 +209,7 @@ func (g *GlobalOrchestrator) removeTasksFromNode(ctx context.Context, node *api. } } -func (g *GlobalOrchestrator) reconcileServices(ctx context.Context, serviceIDs []string) { +func (g *Orchestrator) reconcileServices(ctx context.Context, serviceIDs []string) { nodeCompleted := make(map[string]map[string]struct{}) nodeTasks := make(map[string]map[string][]*api.Task) @@ -229,7 +232,7 @@ func (g *GlobalOrchestrator) reconcileServices(ctx context.Context, serviceIDs [ nodeTasks[serviceID][t.NodeID] = append(nodeTasks[serviceID][t.NodeID], t) } else { // for finished tasks, check restartPolicy - if isTaskCompleted(t, restartCondition(t)) { + if isTaskCompleted(t, orchestrator.RestartCondition(t)) { nodeCompleted[serviceID][t.NodeID] = struct{}{} } } @@ -238,7 +241,7 @@ func (g *GlobalOrchestrator) reconcileServices(ctx context.Context, serviceIDs [ }) _, err := g.store.Batch(func(batch *store.Batch) error { - var updateTasks []slot + var updateTasks []orchestrator.Slot for _, serviceID := range serviceIDs { if _, exists := nodeTasks[serviceID]; !exists { continue @@ -290,7 +293,7 @@ func (g *GlobalOrchestrator) reconcileServices(ctx context.Context, serviceIDs [ } // updateNode updates g.nodes based on the current node value -func (g *GlobalOrchestrator) updateNode(node *api.Node) { +func (g *Orchestrator) updateNode(node *api.Node) { if node.Spec.Availability == api.NodeAvailabilityDrain { delete(g.nodes, node.ID) } else { @@ -299,7 +302,7 @@ func (g *GlobalOrchestrator) updateNode(node *api.Node) { } // updateService updates g.globalServices based on the current service value -func (g *GlobalOrchestrator) updateService(service *api.Service) { +func (g *Orchestrator) updateService(service *api.Service) { var constraints []constraint.Constraint if service.Spec.Task.Placement != nil && len(service.Spec.Task.Placement.Constraints) != 0 { @@ -313,7 +316,7 @@ func (g *GlobalOrchestrator) updateService(service *api.Service) { } // reconcileOneNode checks all global services on one node -func (g *GlobalOrchestrator) reconcileOneNode(ctx context.Context, node *api.Node) { +func (g *Orchestrator) reconcileOneNode(ctx context.Context, node *api.Node) { if node.Spec.Availability == api.NodeAvailabilityDrain { log.G(ctx).Debugf("global orchestrator: node %s in drain state, removing tasks from it", node.ID) g.removeTasksFromNode(ctx, node) @@ -328,7 +331,7 @@ func (g *GlobalOrchestrator) reconcileOneNode(ctx context.Context, node *api.Nod } // reconcileServicesOneNode checks the specified services on one node -func (g *GlobalOrchestrator) reconcileServicesOneNode(ctx context.Context, serviceIDs []string, nodeID string) { +func (g *Orchestrator) reconcileServicesOneNode(ctx context.Context, serviceIDs []string, nodeID string) { node, exists := g.nodes[nodeID] if !exists { return @@ -360,7 +363,7 @@ func (g *GlobalOrchestrator) reconcileServicesOneNode(ctx context.Context, servi if isTaskRunning(t) { tasks[serviceID] = append(tasks[serviceID], t) } else { - if isTaskCompleted(t, restartCondition(t)) { + if isTaskCompleted(t, orchestrator.RestartCondition(t)) { completed[serviceID] = true } } @@ -413,7 +416,7 @@ func (g *GlobalOrchestrator) reconcileServicesOneNode(ctx context.Context, servi ) for _, t := range tasks[serviceID] { - if isTaskDirty(service.Service, t) { + if orchestrator.IsTaskDirty(service.Service, t) { dirtyTasks = append(dirtyTasks, t) } else { cleanTasks = append(cleanTasks, t) @@ -438,7 +441,7 @@ func (g *GlobalOrchestrator) reconcileServicesOneNode(ctx context.Context, servi // restartTask calls the restart supervisor's Restart function, which // sets a task's desired state to shutdown and restarts it if the restart // policy calls for it to be restarted. -func (g *GlobalOrchestrator) restartTask(ctx context.Context, taskID string, serviceID string) { +func (g *Orchestrator) restartTask(ctx context.Context, taskID string, serviceID string) { err := g.store.Update(func(tx store.Tx) error { t := store.GetTask(tx, taskID) if t == nil || t.DesiredState > api.TaskStateRunning { @@ -455,7 +458,7 @@ func (g *GlobalOrchestrator) restartTask(ctx context.Context, taskID string, ser } } -func (g *GlobalOrchestrator) removeTask(ctx context.Context, batch *store.Batch, t *api.Task) { +func (g *Orchestrator) removeTask(ctx context.Context, batch *store.Batch, t *api.Task) { // set existing task DesiredState to TaskStateShutdown // TODO(aaronl): optimistic update? err := batch.Update(func(tx store.Tx) error { @@ -471,8 +474,8 @@ func (g *GlobalOrchestrator) removeTask(ctx context.Context, batch *store.Batch, } } -func (g *GlobalOrchestrator) addTask(ctx context.Context, batch *store.Batch, service *api.Service, nodeID string) { - task := newTask(g.cluster, service, 0, nodeID) +func (g *Orchestrator) addTask(ctx context.Context, batch *store.Batch, service *api.Service, nodeID string) { + task := orchestrator.NewTask(g.cluster, service, 0, nodeID) err := batch.Update(func(tx store.Tx) error { return store.CreateTask(tx, task) @@ -482,7 +485,7 @@ func (g *GlobalOrchestrator) addTask(ctx context.Context, batch *store.Batch, se } } -func (g *GlobalOrchestrator) removeTasks(ctx context.Context, batch *store.Batch, tasks []*api.Task) { +func (g *Orchestrator) removeTasks(ctx context.Context, batch *store.Batch, tasks []*api.Task) { for _, t := range tasks { g.removeTask(ctx, batch, t) } @@ -503,11 +506,3 @@ func isTaskCompleted(t *api.Task, restartPolicy api.RestartPolicy_RestartConditi func isTaskTerminated(t *api.Task) bool { return t != nil && t.Status.State > api.TaskStateRunning } - -func isGlobalService(service *api.Service) bool { - if service == nil { - return false - } - _, ok := service.Spec.GetMode().(*api.ServiceSpec_Global) - return ok -} diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated.go deleted file mode 100644 index 90e032cbfd263..0000000000000 --- a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated.go +++ /dev/null @@ -1,203 +0,0 @@ -package orchestrator - -import ( - "time" - - "github.com/docker/swarmkit/api" - "github.com/docker/swarmkit/identity" - "github.com/docker/swarmkit/log" - "github.com/docker/swarmkit/manager/state" - "github.com/docker/swarmkit/manager/state/store" - "github.com/docker/swarmkit/protobuf/ptypes" - "golang.org/x/net/context" -) - -// A ReplicatedOrchestrator runs a reconciliation loop to create and destroy -// tasks as necessary for the replicated services. -type ReplicatedOrchestrator struct { - store *store.MemoryStore - - reconcileServices map[string]*api.Service - restartTasks map[string]struct{} - - // stopChan signals to the state machine to stop running. - stopChan chan struct{} - // doneChan is closed when the state machine terminates. - doneChan chan struct{} - - updater *UpdateSupervisor - restarts *RestartSupervisor - - cluster *api.Cluster // local cluster instance -} - -// NewReplicatedOrchestrator creates a new ReplicatedOrchestrator. -func NewReplicatedOrchestrator(store *store.MemoryStore) *ReplicatedOrchestrator { - restartSupervisor := NewRestartSupervisor(store) - updater := NewUpdateSupervisor(store, restartSupervisor) - return &ReplicatedOrchestrator{ - store: store, - stopChan: make(chan struct{}), - doneChan: make(chan struct{}), - reconcileServices: make(map[string]*api.Service), - restartTasks: make(map[string]struct{}), - updater: updater, - restarts: restartSupervisor, - } -} - -// Run contains the orchestrator event loop. It runs until Stop is called. -func (r *ReplicatedOrchestrator) Run(ctx context.Context) error { - defer close(r.doneChan) - - // Watch changes to services and tasks - queue := r.store.WatchQueue() - watcher, cancel := queue.Watch() - defer cancel() - - // Balance existing services and drain initial tasks attached to invalid - // nodes - var err error - r.store.View(func(readTx store.ReadTx) { - if err = r.initTasks(ctx, readTx); err != nil { - return - } - - if err = r.initServices(readTx); err != nil { - return - } - - if err = r.initCluster(readTx); err != nil { - return - } - }) - if err != nil { - return err - } - - r.tick(ctx) - - for { - select { - case event := <-watcher: - // TODO(stevvooe): Use ctx to limit running time of operation. - r.handleTaskEvent(ctx, event) - r.handleServiceEvent(ctx, event) - switch v := event.(type) { - case state.EventCommit: - r.tick(ctx) - case state.EventUpdateCluster: - r.cluster = v.Cluster - } - case <-r.stopChan: - return nil - } - } -} - -// Stop stops the orchestrator. -func (r *ReplicatedOrchestrator) Stop() { - close(r.stopChan) - <-r.doneChan - r.updater.CancelAll() - r.restarts.CancelAll() -} - -func (r *ReplicatedOrchestrator) tick(ctx context.Context) { - // tickTasks must be called first, so we respond to task-level changes - // before performing service reconcillation. - r.tickTasks(ctx) - r.tickServices(ctx) -} - -func newTask(cluster *api.Cluster, service *api.Service, slot uint64, nodeID string) *api.Task { - var logDriver *api.Driver - if service.Spec.Task.LogDriver != nil { - // use the log driver specific to the task, if we have it. - logDriver = service.Spec.Task.LogDriver - } else if cluster != nil { - // pick up the cluster default, if available. - logDriver = cluster.Spec.TaskDefaults.LogDriver // nil is okay here. - } - - taskID := identity.NewID() - task := api.Task{ - ID: taskID, - ServiceAnnotations: service.Spec.Annotations, - Spec: service.Spec.Task, - ServiceID: service.ID, - Slot: slot, - Status: api.TaskStatus{ - State: api.TaskStateNew, - Timestamp: ptypes.MustTimestampProto(time.Now()), - Message: "created", - }, - Endpoint: &api.Endpoint{ - Spec: service.Spec.Endpoint.Copy(), - }, - DesiredState: api.TaskStateRunning, - LogDriver: logDriver, - } - - // In global mode we also set the NodeID - if nodeID != "" { - task.NodeID = nodeID - } - - // Assign name based on task name schema - name := store.TaskName(&task) - task.Annotations = api.Annotations{Name: name} - - return &task -} - -// isReplicatedService checks if a service is a replicated service -func isReplicatedService(service *api.Service) bool { - // service nil validation is required as there are scenarios - // where service is removed from store - if service == nil { - return false - } - _, ok := service.Spec.GetMode().(*api.ServiceSpec_Replicated) - return ok -} - -func deleteServiceTasks(ctx context.Context, s *store.MemoryStore, service *api.Service) { - var ( - tasks []*api.Task - err error - ) - s.View(func(tx store.ReadTx) { - tasks, err = store.FindTasks(tx, store.ByServiceID(service.ID)) - }) - if err != nil { - log.G(ctx).WithError(err).Errorf("failed to list tasks") - return - } - - _, err = s.Batch(func(batch *store.Batch) error { - for _, t := range tasks { - err := batch.Update(func(tx store.Tx) error { - if err := store.DeleteTask(tx, t.ID); err != nil { - log.G(ctx).WithError(err).Errorf("failed to delete task") - } - return nil - }) - if err != nil { - return err - } - } - return nil - }) - if err != nil { - log.G(ctx).WithError(err).Errorf("task search transaction failed") - } -} - -func restartCondition(task *api.Task) api.RestartPolicy_RestartCondition { - restartCondition := api.RestartOnAny - if task.Spec.Restart != nil { - restartCondition = task.Spec.Restart.Condition - } - return restartCondition -} diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated/replicated.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated/replicated.go new file mode 100644 index 0000000000000..b7ecd3c371466 --- /dev/null +++ b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated/replicated.go @@ -0,0 +1,108 @@ +package replicated + +import ( + "github.com/docker/swarmkit/api" + "github.com/docker/swarmkit/manager/orchestrator/restart" + "github.com/docker/swarmkit/manager/orchestrator/update" + "github.com/docker/swarmkit/manager/state" + "github.com/docker/swarmkit/manager/state/store" + "golang.org/x/net/context" +) + +// An Orchestrator runs a reconciliation loop to create and destroy +// tasks as necessary for the replicated services. +type Orchestrator struct { + store *store.MemoryStore + + reconcileServices map[string]*api.Service + restartTasks map[string]struct{} + + // stopChan signals to the state machine to stop running. + stopChan chan struct{} + // doneChan is closed when the state machine terminates. + doneChan chan struct{} + + updater *update.Supervisor + restarts *restart.Supervisor + + cluster *api.Cluster // local cluster instance +} + +// NewReplicatedOrchestrator creates a new replicated Orchestrator. +func NewReplicatedOrchestrator(store *store.MemoryStore) *Orchestrator { + restartSupervisor := restart.NewSupervisor(store) + updater := update.NewSupervisor(store, restartSupervisor) + return &Orchestrator{ + store: store, + stopChan: make(chan struct{}), + doneChan: make(chan struct{}), + reconcileServices: make(map[string]*api.Service), + restartTasks: make(map[string]struct{}), + updater: updater, + restarts: restartSupervisor, + } +} + +// Run contains the orchestrator event loop. It runs until Stop is called. +func (r *Orchestrator) Run(ctx context.Context) error { + defer close(r.doneChan) + + // Watch changes to services and tasks + queue := r.store.WatchQueue() + watcher, cancel := queue.Watch() + defer cancel() + + // Balance existing services and drain initial tasks attached to invalid + // nodes + var err error + r.store.View(func(readTx store.ReadTx) { + if err = r.initTasks(ctx, readTx); err != nil { + return + } + + if err = r.initServices(readTx); err != nil { + return + } + + if err = r.initCluster(readTx); err != nil { + return + } + }) + if err != nil { + return err + } + + r.tick(ctx) + + for { + select { + case event := <-watcher: + // TODO(stevvooe): Use ctx to limit running time of operation. + r.handleTaskEvent(ctx, event) + r.handleServiceEvent(ctx, event) + switch v := event.(type) { + case state.EventCommit: + r.tick(ctx) + case state.EventUpdateCluster: + r.cluster = v.Cluster + } + case <-r.stopChan: + return nil + } + } +} + +// Stop stops the orchestrator. +func (r *Orchestrator) Stop() { + close(r.stopChan) + <-r.doneChan + r.updater.CancelAll() + r.restarts.CancelAll() +} + +func (r *Orchestrator) tick(ctx context.Context) { + // tickTasks must be called first, so we respond to task-level changes + // before performing service reconcillation. + r.tickTasks(ctx) + r.tickServices(ctx) +} diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/services.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated/services.go similarity index 68% rename from vendor/src/github.com/docker/swarmkit/manager/orchestrator/services.go rename to vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated/services.go index 47d03f1cc4100..8046ed500265d 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/services.go +++ b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated/services.go @@ -1,4 +1,4 @@ -package orchestrator +package replicated import ( "sort" @@ -6,6 +6,7 @@ import ( "github.com/docker/go-events" "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/log" + "github.com/docker/swarmkit/manager/orchestrator" "github.com/docker/swarmkit/manager/state" "github.com/docker/swarmkit/manager/state/store" "golang.org/x/net/context" @@ -16,7 +17,7 @@ import ( // specifications. This is different from task-level orchestration, which // responds to changes in individual tasks (or nodes which run them). -func (r *ReplicatedOrchestrator) initCluster(readTx store.ReadTx) error { +func (r *Orchestrator) initCluster(readTx store.ReadTx) error { clusters, err := store.FindClusters(readTx, store.ByName("default")) if err != nil { return err @@ -31,41 +32,41 @@ func (r *ReplicatedOrchestrator) initCluster(readTx store.ReadTx) error { return nil } -func (r *ReplicatedOrchestrator) initServices(readTx store.ReadTx) error { +func (r *Orchestrator) initServices(readTx store.ReadTx) error { services, err := store.FindServices(readTx, store.All) if err != nil { return err } for _, s := range services { - if isReplicatedService(s) { + if orchestrator.IsReplicatedService(s) { r.reconcileServices[s.ID] = s } } return nil } -func (r *ReplicatedOrchestrator) handleServiceEvent(ctx context.Context, event events.Event) { +func (r *Orchestrator) handleServiceEvent(ctx context.Context, event events.Event) { switch v := event.(type) { case state.EventDeleteService: - if !isReplicatedService(v.Service) { + if !orchestrator.IsReplicatedService(v.Service) { return } - deleteServiceTasks(ctx, r.store, v.Service) + orchestrator.DeleteServiceTasks(ctx, r.store, v.Service) r.restarts.ClearServiceHistory(v.Service.ID) case state.EventCreateService: - if !isReplicatedService(v.Service) { + if !orchestrator.IsReplicatedService(v.Service) { return } r.reconcileServices[v.Service.ID] = v.Service case state.EventUpdateService: - if !isReplicatedService(v.Service) { + if !orchestrator.IsReplicatedService(v.Service) { return } r.reconcileServices[v.Service.ID] = v.Service } } -func (r *ReplicatedOrchestrator) tickServices(ctx context.Context) { +func (r *Orchestrator) tickServices(ctx context.Context) { if len(r.reconcileServices) > 0 { for _, s := range r.reconcileServices { r.reconcile(ctx, s) @@ -74,7 +75,7 @@ func (r *ReplicatedOrchestrator) tickServices(ctx context.Context) { } } -func (r *ReplicatedOrchestrator) resolveService(ctx context.Context, task *api.Task) *api.Service { +func (r *Orchestrator) resolveService(ctx context.Context, task *api.Task) *api.Service { if task.ServiceID == "" { return nil } @@ -85,8 +86,8 @@ func (r *ReplicatedOrchestrator) resolveService(ctx context.Context, task *api.T return service } -func (r *ReplicatedOrchestrator) reconcile(ctx context.Context, service *api.Service) { - runningSlots, deadSlots, err := getRunnableAndDeadSlots(r.store, service.ID) +func (r *Orchestrator) reconcile(ctx context.Context, service *api.Service) { + runningSlots, deadSlots, err := orchestrator.GetRunnableAndDeadSlots(r.store, service.ID) if err != nil { log.G(ctx).WithError(err).Errorf("reconcile failed finding tasks") return @@ -94,7 +95,7 @@ func (r *ReplicatedOrchestrator) reconcile(ctx context.Context, service *api.Ser numSlots := len(runningSlots) - slotsSlice := make([]slot, 0, numSlots) + slotsSlice := make([]orchestrator.Slot, 0, numSlots) for _, slot := range runningSlots { slotsSlice = append(slotsSlice, slot) } @@ -148,7 +149,7 @@ func (r *ReplicatedOrchestrator) reconcile(ctx context.Context, service *api.Ser sort.Sort(slotsWithIndices) - sortedSlots := make([]slot, 0, numSlots) + sortedSlots := make([]orchestrator.Slot, 0, numSlots) for _, slot := range slotsWithIndices { sortedSlots = append(sortedSlots, slot.slot) } @@ -176,7 +177,7 @@ func (r *ReplicatedOrchestrator) reconcile(ctx context.Context, service *api.Ser } } -func (r *ReplicatedOrchestrator) addTasks(ctx context.Context, batch *store.Batch, service *api.Service, runningSlots map[uint64]slot, deadSlots map[uint64]slot, count int) { +func (r *Orchestrator) addTasks(ctx context.Context, batch *store.Batch, service *api.Service, runningSlots map[uint64]orchestrator.Slot, deadSlots map[uint64]orchestrator.Slot, count int) { slot := uint64(0) for i := 0; i < count; i++ { // Find an slot number that is missing a running task @@ -189,7 +190,7 @@ func (r *ReplicatedOrchestrator) addTasks(ctx context.Context, batch *store.Batc delete(deadSlots, slot) err := batch.Update(func(tx store.Tx) error { - return store.CreateTask(tx, newTask(r.cluster, service, slot, "")) + return store.CreateTask(tx, orchestrator.NewTask(r.cluster, service, slot, "")) }) if err != nil { log.G(ctx).Errorf("Failed to create task: %v", err) @@ -197,7 +198,7 @@ func (r *ReplicatedOrchestrator) addTasks(ctx context.Context, batch *store.Batc } } -func (r *ReplicatedOrchestrator) deleteTasks(ctx context.Context, batch *store.Batch, slots []slot) { +func (r *Orchestrator) deleteTasks(ctx context.Context, batch *store.Batch, slots []orchestrator.Slot) { for _, slot := range slots { for _, t := range slot { r.deleteTask(ctx, batch, t) @@ -205,7 +206,7 @@ func (r *ReplicatedOrchestrator) deleteTasks(ctx context.Context, batch *store.B } } -func (r *ReplicatedOrchestrator) deleteTasksMap(ctx context.Context, batch *store.Batch, slots map[uint64]slot) { +func (r *Orchestrator) deleteTasksMap(ctx context.Context, batch *store.Batch, slots map[uint64]orchestrator.Slot) { for _, slot := range slots { for _, t := range slot { r.deleteTask(ctx, batch, t) @@ -213,7 +214,7 @@ func (r *ReplicatedOrchestrator) deleteTasksMap(ctx context.Context, batch *stor } } -func (r *ReplicatedOrchestrator) deleteTask(ctx context.Context, batch *store.Batch, t *api.Task) { +func (r *Orchestrator) deleteTask(ctx context.Context, batch *store.Batch, t *api.Task) { err := batch.Update(func(tx store.Tx) error { return store.DeleteTask(tx, t.ID) }) @@ -221,36 +222,3 @@ func (r *ReplicatedOrchestrator) deleteTask(ctx context.Context, batch *store.Ba log.G(ctx).WithError(err).Errorf("deleting task %s failed", t.ID) } } - -// getRunnableAndDeadSlots returns two maps of slots. The first contains slots -// that have at least one task with a desired state above NEW and lesser or -// equal to RUNNING. The second is for slots that only contain tasks with a -// desired state above RUNNING. -func getRunnableAndDeadSlots(s *store.MemoryStore, serviceID string) (map[uint64]slot, map[uint64]slot, error) { - var ( - tasks []*api.Task - err error - ) - s.View(func(tx store.ReadTx) { - tasks, err = store.FindTasks(tx, store.ByServiceID(serviceID)) - }) - if err != nil { - return nil, nil, err - } - - runningSlots := make(map[uint64]slot) - for _, t := range tasks { - if t.DesiredState <= api.TaskStateRunning { - runningSlots[t.Slot] = append(runningSlots[t.Slot], t) - } - } - - deadSlots := make(map[uint64]slot) - for _, t := range tasks { - if _, exists := runningSlots[t.Slot]; !exists { - deadSlots[t.Slot] = append(deadSlots[t.Slot], t) - } - } - - return runningSlots, deadSlots, nil -} diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated/slot.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated/slot.go new file mode 100644 index 0000000000000..1f1fd3eca413a --- /dev/null +++ b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated/slot.go @@ -0,0 +1,55 @@ +package replicated + +import ( + "github.com/docker/swarmkit/api" + "github.com/docker/swarmkit/manager/orchestrator" +) + +type slotsByRunningState []orchestrator.Slot + +func (is slotsByRunningState) Len() int { return len(is) } +func (is slotsByRunningState) Swap(i, j int) { is[i], is[j] = is[j], is[i] } + +func (is slotsByRunningState) Less(i, j int) bool { + iRunning := false + jRunning := false + + for _, ii := range is[i] { + if ii.Status.State == api.TaskStateRunning { + iRunning = true + break + } + } + for _, ij := range is[j] { + if ij.Status.State == api.TaskStateRunning { + jRunning = true + break + } + } + + return iRunning && !jRunning +} + +type slotWithIndex struct { + slot orchestrator.Slot + + // index is a counter that counts this task as the nth instance of + // the service on its node. This is used for sorting the tasks so that + // when scaling down we leave tasks more evenly balanced. + index int +} + +type slotsByIndex []slotWithIndex + +func (is slotsByIndex) Len() int { return len(is) } +func (is slotsByIndex) Swap(i, j int) { is[i], is[j] = is[j], is[i] } + +func (is slotsByIndex) Less(i, j int) bool { + if is[i].index < 0 && is[j].index >= 0 { + return false + } + if is[j].index < 0 && is[i].index >= 0 { + return true + } + return is[i].index < is[j].index +} diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/tasks.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated/tasks.go similarity index 84% rename from vendor/src/github.com/docker/swarmkit/manager/orchestrator/tasks.go rename to vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated/tasks.go index e313d5eda88b7..7b8b44261576c 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/tasks.go +++ b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/replicated/tasks.go @@ -1,4 +1,4 @@ -package orchestrator +package replicated import ( "time" @@ -6,6 +6,7 @@ import ( "github.com/docker/go-events" "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/log" + "github.com/docker/swarmkit/manager/orchestrator" "github.com/docker/swarmkit/manager/state" "github.com/docker/swarmkit/manager/state/store" "github.com/docker/swarmkit/protobuf/ptypes" @@ -23,7 +24,7 @@ func invalidNode(n *api.Node) bool { n.Spec.Availability == api.NodeAvailabilityDrain } -func (r *ReplicatedOrchestrator) initTasks(ctx context.Context, readTx store.ReadTx) error { +func (r *Orchestrator) initTasks(ctx context.Context, readTx store.ReadTx) error { tasks, err := store.FindTasks(readTx, store.All) if err != nil { return err @@ -56,16 +57,16 @@ func (r *ReplicatedOrchestrator) initTasks(ctx context.Context, readTx store.Rea continue } // TODO(aluzzardi): This is shady. We should have a more generic condition. - if t.DesiredState != api.TaskStateReady || !isReplicatedService(service) { + if t.DesiredState != api.TaskStateReady || !orchestrator.IsReplicatedService(service) { continue } - restartDelay := defaultRestartDelay + restartDelay := orchestrator.DefaultRestartDelay if t.Spec.Restart != nil && t.Spec.Restart.Delay != nil { var err error restartDelay, err = ptypes.Duration(t.Spec.Restart.Delay) if err != nil { log.G(ctx).WithError(err).Error("invalid restart delay") - restartDelay = defaultRestartDelay + restartDelay = orchestrator.DefaultRestartDelay } } if restartDelay != 0 { @@ -107,7 +108,7 @@ func (r *ReplicatedOrchestrator) initTasks(ctx context.Context, readTx store.Rea return err } -func (r *ReplicatedOrchestrator) handleTaskEvent(ctx context.Context, event events.Event) { +func (r *Orchestrator) handleTaskEvent(ctx context.Context, event events.Event) { switch v := event.(type) { case state.EventDeleteNode: r.restartTasksByNodeID(ctx, v.Node.ID) @@ -118,7 +119,7 @@ func (r *ReplicatedOrchestrator) handleTaskEvent(ctx context.Context, event even case state.EventDeleteTask: if v.Task.DesiredState <= api.TaskStateRunning { service := r.resolveService(ctx, v.Task) - if !isReplicatedService(service) { + if !orchestrator.IsReplicatedService(service) { return } r.reconcileServices[service.ID] = service @@ -131,7 +132,7 @@ func (r *ReplicatedOrchestrator) handleTaskEvent(ctx context.Context, event even } } -func (r *ReplicatedOrchestrator) tickTasks(ctx context.Context) { +func (r *Orchestrator) tickTasks(ctx context.Context) { if len(r.restartTasks) > 0 { _, err := r.store.Batch(func(batch *store.Batch) error { for taskID := range r.restartTasks { @@ -144,7 +145,7 @@ func (r *ReplicatedOrchestrator) tickTasks(ctx context.Context) { } service := store.GetService(tx, t.ServiceID) - if !isReplicatedService(service) { + if !orchestrator.IsReplicatedService(service) { return nil } @@ -156,7 +157,7 @@ func (r *ReplicatedOrchestrator) tickTasks(ctx context.Context) { return nil }) if err != nil { - log.G(ctx).WithError(err).Errorf("ReplicatedOrchestrator task reaping transaction failed") + log.G(ctx).WithError(err).Errorf("Orchestrator task reaping transaction failed") } } return nil @@ -170,7 +171,7 @@ func (r *ReplicatedOrchestrator) tickTasks(ctx context.Context) { } } -func (r *ReplicatedOrchestrator) restartTasksByNodeID(ctx context.Context, nodeID string) { +func (r *Orchestrator) restartTasksByNodeID(ctx context.Context, nodeID string) { var err error r.store.View(func(tx store.ReadTx) { var tasks []*api.Task @@ -184,7 +185,7 @@ func (r *ReplicatedOrchestrator) restartTasksByNodeID(ctx context.Context, nodeI continue } service := store.GetService(tx, t.ServiceID) - if isReplicatedService(service) { + if orchestrator.IsReplicatedService(service) { r.restartTasks[t.ID] = struct{}{} } } @@ -194,7 +195,7 @@ func (r *ReplicatedOrchestrator) restartTasksByNodeID(ctx context.Context, nodeI } } -func (r *ReplicatedOrchestrator) handleNodeChange(ctx context.Context, n *api.Node) { +func (r *Orchestrator) handleNodeChange(ctx context.Context, n *api.Node) { if !invalidNode(n) { return } @@ -202,7 +203,7 @@ func (r *ReplicatedOrchestrator) handleNodeChange(ctx context.Context, n *api.No r.restartTasksByNodeID(ctx, n.ID) } -func (r *ReplicatedOrchestrator) handleTaskChange(ctx context.Context, t *api.Task) { +func (r *Orchestrator) handleTaskChange(ctx context.Context, t *api.Task) { // If we already set the desired state past TaskStateRunning, there is no // further action necessary. if t.DesiredState > api.TaskStateRunning { @@ -222,7 +223,7 @@ func (r *ReplicatedOrchestrator) handleTaskChange(ctx context.Context, t *api.Ta } }) - if !isReplicatedService(service) { + if !orchestrator.IsReplicatedService(service) { return } diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/restart.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/restart/restart.go similarity index 85% rename from vendor/src/github.com/docker/swarmkit/manager/orchestrator/restart.go rename to vendor/src/github.com/docker/swarmkit/manager/orchestrator/restart/restart.go index 7f0aaedb6ed4d..f7552105a02f6 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/restart.go +++ b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/restart/restart.go @@ -1,4 +1,4 @@ -package orchestrator +package restart import ( "container/list" @@ -9,6 +9,7 @@ import ( "github.com/docker/go-events" "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/log" + "github.com/docker/swarmkit/manager/orchestrator" "github.com/docker/swarmkit/manager/state" "github.com/docker/swarmkit/manager/state/store" "github.com/docker/swarmkit/protobuf/ptypes" @@ -16,7 +17,6 @@ import ( ) const defaultOldTaskTimeout = time.Minute -const defaultRestartDelay = 5 * time.Second type restartedInstance struct { timestamp time.Time @@ -41,29 +41,35 @@ type delayedStart struct { waiter bool } -// RestartSupervisor initiates and manages restarts. It's responsible for +type instanceTuple struct { + instance uint64 // unset for global tasks + serviceID string + nodeID string // unset for replicated tasks +} + +// Supervisor initiates and manages restarts. It's responsible for // delaying restarts when applicable. -type RestartSupervisor struct { +type Supervisor struct { mu sync.Mutex store *store.MemoryStore delays map[string]*delayedStart history map[instanceTuple]*instanceRestartInfo historyByService map[string]map[instanceTuple]struct{} - taskTimeout time.Duration + TaskTimeout time.Duration } -// NewRestartSupervisor creates a new RestartSupervisor. -func NewRestartSupervisor(store *store.MemoryStore) *RestartSupervisor { - return &RestartSupervisor{ +// NewSupervisor creates a new RestartSupervisor. +func NewSupervisor(store *store.MemoryStore) *Supervisor { + return &Supervisor{ store: store, delays: make(map[string]*delayedStart), history: make(map[instanceTuple]*instanceRestartInfo), historyByService: make(map[string]map[instanceTuple]struct{}), - taskTimeout: defaultOldTaskTimeout, + TaskTimeout: defaultOldTaskTimeout, } } -func (r *RestartSupervisor) waitRestart(ctx context.Context, oldDelay *delayedStart, cluster *api.Cluster, taskID string) { +func (r *Supervisor) waitRestart(ctx context.Context, oldDelay *delayedStart, cluster *api.Cluster, taskID string) { // Wait for the last restart delay to elapse. select { case <-oldDelay.doneCh: @@ -94,7 +100,7 @@ func (r *RestartSupervisor) waitRestart(ctx context.Context, oldDelay *delayedSt // Restart initiates a new task to replace t if appropriate under the service's // restart policy. -func (r *RestartSupervisor) Restart(ctx context.Context, tx store.Tx, cluster *api.Cluster, service *api.Service, t api.Task) error { +func (r *Supervisor) Restart(ctx context.Context, tx store.Tx, cluster *api.Cluster, service *api.Service, t api.Task) error { // TODO(aluzzardi): This function should not depend on `service`. // Is the old task still in the process of restarting? If so, wait for @@ -132,10 +138,10 @@ func (r *RestartSupervisor) Restart(ctx context.Context, tx store.Tx, cluster *a var restartTask *api.Task - if isReplicatedService(service) { - restartTask = newTask(cluster, service, t.Slot, "") - } else if isGlobalService(service) { - restartTask = newTask(cluster, service, 0, t.NodeID) + if orchestrator.IsReplicatedService(service) { + restartTask = orchestrator.NewTask(cluster, service, t.Slot, "") + } else if orchestrator.IsGlobalService(service) { + restartTask = orchestrator.NewTask(cluster, service, 0, t.NodeID) } else { log.G(ctx).Error("service not supported by restart supervisor") return nil @@ -153,10 +159,10 @@ func (r *RestartSupervisor) Restart(ctx context.Context, tx store.Tx, cluster *a restartDelay, err = ptypes.Duration(t.Spec.Restart.Delay) if err != nil { log.G(ctx).WithError(err).Error("invalid restart delay; using default") - restartDelay = defaultRestartDelay + restartDelay = orchestrator.DefaultRestartDelay } } else { - restartDelay = defaultRestartDelay + restartDelay = orchestrator.DefaultRestartDelay } } @@ -179,10 +185,10 @@ func (r *RestartSupervisor) Restart(ctx context.Context, tx store.Tx, cluster *a return nil } -func (r *RestartSupervisor) shouldRestart(ctx context.Context, t *api.Task, service *api.Service) bool { +func (r *Supervisor) shouldRestart(ctx context.Context, t *api.Task, service *api.Service) bool { // TODO(aluzzardi): This function should not depend on `service`. - condition := restartCondition(t) + condition := orchestrator.RestartCondition(t) if condition != api.RestartOnAny && (condition != api.RestartOnFailure || t.Status.State == api.TaskStateCompleted) { @@ -200,7 +206,7 @@ func (r *RestartSupervisor) shouldRestart(ctx context.Context, t *api.Task, serv // Instance is not meaningful for "global" tasks, so they need to be // indexed by NodeID. - if isGlobalService(service) { + if orchestrator.IsGlobalService(service) { instanceTuple.nodeID = t.NodeID } @@ -246,7 +252,7 @@ func (r *RestartSupervisor) shouldRestart(ctx context.Context, t *api.Task, serv return numRestarts < t.Spec.Restart.MaxAttempts } -func (r *RestartSupervisor) recordRestartHistory(restartTask *api.Task) { +func (r *Supervisor) recordRestartHistory(restartTask *api.Task) { if restartTask.Spec.Restart == nil || restartTask.Spec.Restart.MaxAttempts == 0 { // No limit on the number of restarts, so no need to record // history. @@ -292,7 +298,7 @@ func (r *RestartSupervisor) recordRestartHistory(restartTask *api.Task) { // It must be called during an Update transaction to ensure that it does not // miss events. The purpose of the store.Tx argument is to avoid accidental // calls outside an Update transaction. -func (r *RestartSupervisor) DelayStart(ctx context.Context, _ store.Tx, oldTask *api.Task, newTaskID string, delay time.Duration, waitStop bool) <-chan struct{} { +func (r *Supervisor) DelayStart(ctx context.Context, _ store.Tx, oldTask *api.Task, newTaskID string, delay time.Duration, waitStop bool) <-chan struct{} { ctx, cancel := context.WithCancel(context.Background()) doneCh := make(chan struct{}) @@ -345,7 +351,7 @@ func (r *RestartSupervisor) DelayStart(ctx context.Context, _ store.Tx, oldTask close(doneCh) }() - oldTaskTimer := time.NewTimer(r.taskTimeout) + oldTaskTimer := time.NewTimer(r.TaskTimeout) defer oldTaskTimer.Stop() // Wait for the delay to elapse, if one is specified. @@ -383,7 +389,7 @@ func (r *RestartSupervisor) DelayStart(ctx context.Context, _ store.Tx, oldTask // StartNow moves the task into the RUNNING state so it will proceed to start // up. -func (r *RestartSupervisor) StartNow(tx store.Tx, taskID string) error { +func (r *Supervisor) StartNow(tx store.Tx, taskID string) error { t := store.GetTask(tx, taskID) if t == nil || t.DesiredState >= api.TaskStateRunning { return nil @@ -393,7 +399,7 @@ func (r *RestartSupervisor) StartNow(tx store.Tx, taskID string) error { } // Cancel cancels a pending restart. -func (r *RestartSupervisor) Cancel(taskID string) { +func (r *Supervisor) Cancel(taskID string) { r.mu.Lock() delay, ok := r.delays[taskID] r.mu.Unlock() @@ -408,7 +414,7 @@ func (r *RestartSupervisor) Cancel(taskID string) { // CancelAll aborts all pending restarts and waits for any instances of // StartNow that have already triggered to complete. -func (r *RestartSupervisor) CancelAll() { +func (r *Supervisor) CancelAll() { var cancelled []delayedStart r.mu.Lock() @@ -423,7 +429,7 @@ func (r *RestartSupervisor) CancelAll() { } // ClearServiceHistory forgets restart history related to a given service ID. -func (r *RestartSupervisor) ClearServiceHistory(serviceID string) { +func (r *Supervisor) ClearServiceHistory(serviceID string) { r.mu.Lock() defer r.mu.Unlock() diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/service.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/service.go new file mode 100644 index 0000000000000..a5e3f5c819143 --- /dev/null +++ b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/service.go @@ -0,0 +1,61 @@ +package orchestrator + +import ( + "github.com/docker/swarmkit/api" + "github.com/docker/swarmkit/log" + "github.com/docker/swarmkit/manager/state/store" + "golang.org/x/net/context" +) + +// IsReplicatedService checks if a service is a replicated service. +func IsReplicatedService(service *api.Service) bool { + // service nil validation is required as there are scenarios + // where service is removed from store + if service == nil { + return false + } + _, ok := service.Spec.GetMode().(*api.ServiceSpec_Replicated) + return ok +} + +// IsGlobalService checks if the service is a global service. +func IsGlobalService(service *api.Service) bool { + if service == nil { + return false + } + _, ok := service.Spec.GetMode().(*api.ServiceSpec_Global) + return ok +} + +// DeleteServiceTasks deletes the tasks associated with a service. +func DeleteServiceTasks(ctx context.Context, s *store.MemoryStore, service *api.Service) { + var ( + tasks []*api.Task + err error + ) + s.View(func(tx store.ReadTx) { + tasks, err = store.FindTasks(tx, store.ByServiceID(service.ID)) + }) + if err != nil { + log.G(ctx).WithError(err).Errorf("failed to list tasks") + return + } + + _, err = s.Batch(func(batch *store.Batch) error { + for _, t := range tasks { + err := batch.Update(func(tx store.Tx) error { + if err := store.DeleteTask(tx, t.ID); err != nil { + log.G(ctx).WithError(err).Errorf("failed to delete task") + } + return nil + }) + if err != nil { + return err + } + } + return nil + }) + if err != nil { + log.G(ctx).WithError(err).Errorf("task search transaction failed") + } +} diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/slot.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/slot.go index fca39e2a78a4b..ce347136babf7 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/slot.go +++ b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/slot.go @@ -2,60 +2,45 @@ package orchestrator import ( "github.com/docker/swarmkit/api" + "github.com/docker/swarmkit/manager/state/store" ) -// slot is a list of the running tasks occupying a certain slot. Generally this +// Slot is a list of the running tasks occupying a certain slot. Generally this // will only be one task, but some rolling update situations involve // temporarily having two running tasks in the same slot. Note that this use of // "slot" is more generic than the Slot number for replicated services - a node // is also considered a slot for global services. -type slot []*api.Task - -type slotsByRunningState []slot - -func (is slotsByRunningState) Len() int { return len(is) } -func (is slotsByRunningState) Swap(i, j int) { is[i], is[j] = is[j], is[i] } - -func (is slotsByRunningState) Less(i, j int) bool { - iRunning := false - jRunning := false +type Slot []*api.Task + +// GetRunnableAndDeadSlots returns two maps of slots. The first contains slots +// that have at least one task with a desired state above NEW and lesser or +// equal to RUNNING. The second is for slots that only contain tasks with a +// desired state above RUNNING. +func GetRunnableAndDeadSlots(s *store.MemoryStore, serviceID string) (map[uint64]Slot, map[uint64]Slot, error) { + var ( + tasks []*api.Task + err error + ) + s.View(func(tx store.ReadTx) { + tasks, err = store.FindTasks(tx, store.ByServiceID(serviceID)) + }) + if err != nil { + return nil, nil, err + } - for _, ii := range is[i] { - if ii.Status.State == api.TaskStateRunning { - iRunning = true - break + runningSlots := make(map[uint64]Slot) + for _, t := range tasks { + if t.DesiredState <= api.TaskStateRunning { + runningSlots[t.Slot] = append(runningSlots[t.Slot], t) } } - for _, ij := range is[j] { - if ij.Status.State == api.TaskStateRunning { - jRunning = true - break + + deadSlots := make(map[uint64]Slot) + for _, t := range tasks { + if _, exists := runningSlots[t.Slot]; !exists { + deadSlots[t.Slot] = append(deadSlots[t.Slot], t) } } - return iRunning && !jRunning -} - -type slotWithIndex struct { - slot slot - - // index is a counter that counts this task as the nth instance of - // the service on its node. This is used for sorting the tasks so that - // when scaling down we leave tasks more evenly balanced. - index int -} - -type slotsByIndex []slotWithIndex - -func (is slotsByIndex) Len() int { return len(is) } -func (is slotsByIndex) Swap(i, j int) { is[i], is[j] = is[j], is[i] } - -func (is slotsByIndex) Less(i, j int) bool { - if is[i].index < 0 && is[j].index >= 0 { - return false - } - if is[j].index < 0 && is[i].index >= 0 { - return true - } - return is[i].index < is[j].index + return runningSlots, deadSlots, nil } diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/task.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/task.go new file mode 100644 index 0000000000000..daf27c2aed0db --- /dev/null +++ b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/task.go @@ -0,0 +1,67 @@ +package orchestrator + +import ( + "reflect" + "time" + + "github.com/docker/swarmkit/api" + "github.com/docker/swarmkit/identity" + "github.com/docker/swarmkit/protobuf/ptypes" +) + +// DefaultRestartDelay is the restart delay value to use when none is +// specified. +const DefaultRestartDelay = 5 * time.Second + +// NewTask creates a new task. +func NewTask(cluster *api.Cluster, service *api.Service, slot uint64, nodeID string) *api.Task { + var logDriver *api.Driver + if service.Spec.Task.LogDriver != nil { + // use the log driver specific to the task, if we have it. + logDriver = service.Spec.Task.LogDriver + } else if cluster != nil { + // pick up the cluster default, if available. + logDriver = cluster.Spec.TaskDefaults.LogDriver // nil is okay here. + } + + taskID := identity.NewID() + task := api.Task{ + ID: taskID, + ServiceAnnotations: service.Spec.Annotations, + Spec: service.Spec.Task, + ServiceID: service.ID, + Slot: slot, + Status: api.TaskStatus{ + State: api.TaskStateNew, + Timestamp: ptypes.MustTimestampProto(time.Now()), + Message: "created", + }, + Endpoint: &api.Endpoint{ + Spec: service.Spec.Endpoint.Copy(), + }, + DesiredState: api.TaskStateRunning, + LogDriver: logDriver, + } + + // In global mode we also set the NodeID + if nodeID != "" { + task.NodeID = nodeID + } + + return &task +} + +// RestartCondition returns the restart condition to apply to this task. +func RestartCondition(task *api.Task) api.RestartPolicy_RestartCondition { + restartCondition := api.RestartOnAny + if task.Spec.Restart != nil { + restartCondition = task.Spec.Restart.Condition + } + return restartCondition +} + +// IsTaskDirty determines whether a task matches the given service's spec. +func IsTaskDirty(s *api.Service, t *api.Task) bool { + return !reflect.DeepEqual(s.Spec.Task, t.Spec) || + (t.Endpoint != nil && !reflect.DeepEqual(s.Spec.Endpoint, t.Endpoint.Spec)) +} diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/task_reaper.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/taskreaper/task_reaper.go similarity index 97% rename from vendor/src/github.com/docker/swarmkit/manager/orchestrator/task_reaper.go rename to vendor/src/github.com/docker/swarmkit/manager/orchestrator/taskreaper/task_reaper.go index ccd60ed62a619..4236d923c3bc3 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/task_reaper.go +++ b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/taskreaper/task_reaper.go @@ -1,4 +1,4 @@ -package orchestrator +package taskreaper import ( "sort" @@ -36,8 +36,8 @@ type TaskReaper struct { doneChan chan struct{} } -// NewTaskReaper creates a new TaskReaper. -func NewTaskReaper(store *store.MemoryStore) *TaskReaper { +// New creates a new TaskReaper. +func New(store *store.MemoryStore) *TaskReaper { watcher, cancel := state.Watch(store.WatchQueue(), state.EventCreateTask{}, state.EventUpdateCluster{}) return &TaskReaper{ diff --git a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/updater.go b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/update/updater.go similarity index 91% rename from vendor/src/github.com/docker/swarmkit/manager/orchestrator/updater.go rename to vendor/src/github.com/docker/swarmkit/manager/orchestrator/update/updater.go index e62b15c97a4b4..baea979c3598c 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/orchestrator/updater.go +++ b/vendor/src/github.com/docker/swarmkit/manager/orchestrator/update/updater.go @@ -1,4 +1,4 @@ -package orchestrator +package update import ( "errors" @@ -12,6 +12,8 @@ import ( "github.com/docker/go-events" "github.com/docker/swarmkit/api" "github.com/docker/swarmkit/log" + "github.com/docker/swarmkit/manager/orchestrator" + "github.com/docker/swarmkit/manager/orchestrator/restart" "github.com/docker/swarmkit/manager/state" "github.com/docker/swarmkit/manager/state/store" "github.com/docker/swarmkit/manager/state/watch" @@ -20,18 +22,18 @@ import ( const defaultMonitor = 30 * time.Second -// UpdateSupervisor supervises a set of updates. It's responsible for keeping track of updates, +// Supervisor supervises a set of updates. It's responsible for keeping track of updates, // shutting them down and replacing them. -type UpdateSupervisor struct { +type Supervisor struct { store *store.MemoryStore - restarts *RestartSupervisor + restarts *restart.Supervisor updates map[string]*Updater l sync.Mutex } -// NewUpdateSupervisor creates a new UpdateSupervisor. -func NewUpdateSupervisor(store *store.MemoryStore, restartSupervisor *RestartSupervisor) *UpdateSupervisor { - return &UpdateSupervisor{ +// NewSupervisor creates a new UpdateSupervisor. +func NewSupervisor(store *store.MemoryStore, restartSupervisor *restart.Supervisor) *Supervisor { + return &Supervisor{ store: store, updates: make(map[string]*Updater), restarts: restartSupervisor, @@ -45,7 +47,7 @@ func NewUpdateSupervisor(store *store.MemoryStore, restartSupervisor *RestartSup // and the new task was started before the old one was shut down. If an update // for that service was already in progress, it will be cancelled before the // new one starts. -func (u *UpdateSupervisor) Update(ctx context.Context, cluster *api.Cluster, service *api.Service, slots []slot) { +func (u *Supervisor) Update(ctx context.Context, cluster *api.Cluster, service *api.Service, slots []orchestrator.Slot) { u.l.Lock() defer u.l.Unlock() @@ -72,7 +74,7 @@ func (u *UpdateSupervisor) Update(ctx context.Context, cluster *api.Cluster, ser } // CancelAll cancels all current updates. -func (u *UpdateSupervisor) CancelAll() { +func (u *Supervisor) CancelAll() { u.l.Lock() defer u.l.Unlock() @@ -85,7 +87,7 @@ func (u *UpdateSupervisor) CancelAll() { type Updater struct { store *store.MemoryStore watchQueue *watch.Queue - restarts *RestartSupervisor + restarts *restart.Supervisor cluster *api.Cluster newService *api.Service @@ -100,7 +102,7 @@ type Updater struct { } // NewUpdater creates a new Updater. -func NewUpdater(store *store.MemoryStore, restartSupervisor *RestartSupervisor, cluster *api.Cluster, newService *api.Service) *Updater { +func NewUpdater(store *store.MemoryStore, restartSupervisor *restart.Supervisor, cluster *api.Cluster, newService *api.Service) *Updater { return &Updater{ store: store, watchQueue: store.WatchQueue(), @@ -120,7 +122,7 @@ func (u *Updater) Cancel() { } // Run starts the update and returns only once its complete or cancelled. -func (u *Updater) Run(ctx context.Context, slots []slot) { +func (u *Updater) Run(ctx context.Context, slots []orchestrator.Slot) { defer close(u.doneChan) service := u.newService @@ -132,7 +134,7 @@ func (u *Updater) Run(ctx context.Context, slots []slot) { return } - var dirtySlots []slot + var dirtySlots []orchestrator.Slot for _, slot := range slots { if u.isSlotDirty(slot) { dirtySlots = append(dirtySlots, slot) @@ -164,7 +166,7 @@ func (u *Updater) Run(ctx context.Context, slots []slot) { } // Start the workers. - slotQueue := make(chan slot) + slotQueue := make(chan orchestrator.Slot) wg := sync.WaitGroup{} wg.Add(parallelism) for i := 0; i < parallelism; i++ { @@ -300,7 +302,7 @@ slotsLoop: } } -func (u *Updater) worker(ctx context.Context, queue <-chan slot) { +func (u *Updater) worker(ctx context.Context, queue <-chan orchestrator.Slot) { for slot := range queue { // Do we have a task with the new spec in desired state = RUNNING? // If so, all we have to do to complete the update is remove the @@ -331,9 +333,9 @@ func (u *Updater) worker(ctx context.Context, queue <-chan slot) { log.G(ctx).WithError(err).Error("update failed") } } else { - updated := newTask(u.cluster, u.newService, slot[0].Slot, "") - if isGlobalService(u.newService) { - updated = newTask(u.cluster, u.newService, slot[0].Slot, slot[0].NodeID) + updated := orchestrator.NewTask(u.cluster, u.newService, slot[0].Slot, "") + if orchestrator.IsGlobalService(u.newService) { + updated = orchestrator.NewTask(u.cluster, u.newService, slot[0].Slot, slot[0].NodeID) } updated.DesiredState = api.TaskStateReady @@ -357,7 +359,7 @@ func (u *Updater) worker(ctx context.Context, queue <-chan slot) { } } -func (u *Updater) updateTask(ctx context.Context, slot slot, updated *api.Task) error { +func (u *Updater) updateTask(ctx context.Context, slot orchestrator.Slot, updated *api.Task) error { // Kick off the watch before even creating the updated task. This is in order to avoid missing any event. taskUpdates, cancel := state.Watch(u.watchQueue, state.EventUpdateTask{ Task: &api.Task{ID: updated.ID}, @@ -421,7 +423,7 @@ func (u *Updater) updateTask(ctx context.Context, slot slot, updated *api.Task) } } -func (u *Updater) useExistingTask(ctx context.Context, slot slot, existing *api.Task) error { +func (u *Updater) useExistingTask(ctx context.Context, slot orchestrator.Slot, existing *api.Task) error { var removeTasks []*api.Task for _, t := range slot { if t != existing { @@ -489,16 +491,11 @@ func (u *Updater) removeOldTasks(ctx context.Context, batch *store.Batch, remove return removedTask, nil } -func isTaskDirty(s *api.Service, t *api.Task) bool { - return !reflect.DeepEqual(s.Spec.Task, t.Spec) || - (t.Endpoint != nil && !reflect.DeepEqual(s.Spec.Endpoint, t.Endpoint.Spec)) -} - func (u *Updater) isTaskDirty(t *api.Task) bool { - return isTaskDirty(u.newService, t) + return orchestrator.IsTaskDirty(u.newService, t) } -func (u *Updater) isSlotDirty(slot slot) bool { +func (u *Updater) isSlotDirty(slot orchestrator.Slot) bool { return len(slot) > 1 || (len(slot) == 1 && u.isTaskDirty(slot[0])) } diff --git a/vendor/src/github.com/docker/swarmkit/manager/scheduler/nodeinfo.go b/vendor/src/github.com/docker/swarmkit/manager/scheduler/nodeinfo.go index 5f45fd658130d..89936a09ada3f 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/scheduler/nodeinfo.go +++ b/vendor/src/github.com/docker/swarmkit/manager/scheduler/nodeinfo.go @@ -1,6 +1,12 @@ package scheduler -import "github.com/docker/swarmkit/api" +import ( + "time" + + "github.com/docker/swarmkit/api" + "github.com/docker/swarmkit/log" + "golang.org/x/net/context" +) // NodeInfo contains a node and some additional metadata. type NodeInfo struct { @@ -9,6 +15,13 @@ type NodeInfo struct { DesiredRunningTasksCount int DesiredRunningTasksCountByService map[string]int AvailableResources api.Resources + + // recentFailures is a map from service ID to the timestamps of the + // most recent failures the node has experienced from replicas of that + // service. + // TODO(aaronl): When spec versioning is supported, this should track + // the version of the spec that failed. + recentFailures map[string][]time.Time } func newNodeInfo(n *api.Node, tasks map[string]*api.Task, availableResources api.Resources) NodeInfo { @@ -17,6 +30,7 @@ func newNodeInfo(n *api.Node, tasks map[string]*api.Task, availableResources api Tasks: make(map[string]*api.Task), DesiredRunningTasksCountByService: make(map[string]int), AvailableResources: availableResources, + recentFailures: make(map[string][]time.Time), } for _, t := range tasks { @@ -28,9 +42,6 @@ func newNodeInfo(n *api.Node, tasks map[string]*api.Task, availableResources api // addTask removes a task from nodeInfo if it's tracked there, and returns true // if nodeInfo was modified. func (nodeInfo *NodeInfo) removeTask(t *api.Task) bool { - if nodeInfo.Tasks == nil { - return false - } oldTask, ok := nodeInfo.Tasks[t.ID] if !ok { return false @@ -52,13 +63,6 @@ func (nodeInfo *NodeInfo) removeTask(t *api.Task) bool { // addTask adds or updates a task on nodeInfo, and returns true if nodeInfo was // modified. func (nodeInfo *NodeInfo) addTask(t *api.Task) bool { - if nodeInfo.Tasks == nil { - nodeInfo.Tasks = make(map[string]*api.Task) - } - if nodeInfo.DesiredRunningTasksCountByService == nil { - nodeInfo.DesiredRunningTasksCountByService = make(map[string]int) - } - oldTask, ok := nodeInfo.Tasks[t.ID] if ok { if t.DesiredState == api.TaskStateRunning && oldTask.DesiredState != api.TaskStateRunning { @@ -94,3 +98,35 @@ func taskReservations(spec api.TaskSpec) (reservations api.Resources) { } return } + +// taskFailed records a task failure from a given service. +func (nodeInfo *NodeInfo) taskFailed(ctx context.Context, serviceID string) { + expired := 0 + now := time.Now() + for _, timestamp := range nodeInfo.recentFailures[serviceID] { + if now.Sub(timestamp) < monitorFailures { + break + } + expired++ + } + + if len(nodeInfo.recentFailures[serviceID])-expired == maxFailures-1 { + log.G(ctx).Warnf("underweighting node %s for service %s because it experienced %d failures or rejections within %s", nodeInfo.ID, serviceID, maxFailures, monitorFailures.String()) + } + + nodeInfo.recentFailures[serviceID] = append(nodeInfo.recentFailures[serviceID][expired:], now) +} + +// countRecentFailures returns the number of times the service has failed on +// this node within the lookback window monitorFailures. +func (nodeInfo *NodeInfo) countRecentFailures(now time.Time, serviceID string) int { + recentFailureCount := len(nodeInfo.recentFailures[serviceID]) + for i := recentFailureCount - 1; i >= 0; i-- { + if now.Sub(nodeInfo.recentFailures[serviceID][i]) > monitorFailures { + recentFailureCount -= i + 1 + break + } + } + + return recentFailureCount +} diff --git a/vendor/src/github.com/docker/swarmkit/manager/scheduler/nodeset.go b/vendor/src/github.com/docker/swarmkit/manager/scheduler/nodeset.go index d47b9c6fbb218..89571ce535544 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/scheduler/nodeset.go +++ b/vendor/src/github.com/docker/swarmkit/manager/scheduler/nodeset.go @@ -3,6 +3,9 @@ package scheduler import ( "container/heap" "errors" + "time" + + "github.com/docker/swarmkit/api" ) var errNodeNotFound = errors.New("node not found in scheduler dataset") @@ -27,6 +30,16 @@ func (ns *nodeSet) nodeInfo(nodeID string) (NodeInfo, error) { // addOrUpdateNode sets the number of tasks for a given node. It adds the node // to the set if it wasn't already tracked. func (ns *nodeSet) addOrUpdateNode(n NodeInfo) { + if n.Tasks == nil { + n.Tasks = make(map[string]*api.Task) + } + if n.DesiredRunningTasksCountByService == nil { + n.DesiredRunningTasksCountByService = make(map[string]int) + } + if n.recentFailures == nil { + n.recentFailures = make(map[string][]time.Time) + } + ns.nodes[n.ID] = n } diff --git a/vendor/src/github.com/docker/swarmkit/manager/scheduler/scheduler.go b/vendor/src/github.com/docker/swarmkit/manager/scheduler/scheduler.go index c18a278d95c98..6959f3a728498 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/scheduler/scheduler.go +++ b/vendor/src/github.com/docker/swarmkit/manager/scheduler/scheduler.go @@ -12,6 +12,16 @@ import ( "golang.org/x/net/context" ) +const ( + // monitorFailures is the lookback period for counting failures of + // a task to determine if a node is faulty for a particular service. + monitorFailures = 5 * time.Minute + + // maxFailures is the number of failures within monitorFailures that + // triggers downweighting of a node in the sorting function. + maxFailures = 5 +) + type schedulingDecision struct { old *api.Task new *api.Task @@ -54,9 +64,9 @@ func (s *Scheduler) setupTasksList(tx store.ReadTx) error { tasksByNode := make(map[string]map[string]*api.Task) for _, t := range tasks { - // Ignore all tasks that have not reached ALLOCATED + // Ignore all tasks that have not reached PENDING // state and tasks that no longer consume resources. - if t.Status.State < api.TaskStateAllocated || t.Status.State > api.TaskStateRunning { + if t.Status.State < api.TaskStatePending || t.Status.State > api.TaskStateRunning { continue } @@ -66,7 +76,7 @@ func (s *Scheduler) setupTasksList(tx store.ReadTx) error { continue } // preassigned tasks need to validate resource requirement on corresponding node - if t.Status.State == api.TaskStateAllocated { + if t.Status.State == api.TaskStatePending { s.preassignedTasks[t.ID] = t continue } @@ -185,9 +195,9 @@ func (s *Scheduler) enqueue(t *api.Task) { } func (s *Scheduler) createTask(ctx context.Context, t *api.Task) int { - // Ignore all tasks that have not reached ALLOCATED + // Ignore all tasks that have not reached PENDING // state, and tasks that no longer consume resources. - if t.Status.State < api.TaskStateAllocated || t.Status.State > api.TaskStateRunning { + if t.Status.State < api.TaskStatePending || t.Status.State > api.TaskStateRunning { return 0 } @@ -198,7 +208,7 @@ func (s *Scheduler) createTask(ctx context.Context, t *api.Task) int { return 1 } - if t.Status.State == api.TaskStateAllocated { + if t.Status.State == api.TaskStatePending { s.preassignedTasks[t.ID] = t // preassigned tasks do not contribute to running tasks count return 0 @@ -213,9 +223,9 @@ func (s *Scheduler) createTask(ctx context.Context, t *api.Task) int { } func (s *Scheduler) updateTask(ctx context.Context, t *api.Task) int { - // Ignore all tasks that have not reached ALLOCATED + // Ignore all tasks that have not reached PENDING // state. - if t.Status.State < api.TaskStateAllocated { + if t.Status.State < api.TaskStatePending { return 0 } @@ -224,8 +234,17 @@ func (s *Scheduler) updateTask(ctx context.Context, t *api.Task) int { // Ignore all tasks that have not reached ALLOCATED // state, and tasks that no longer consume resources. if t.Status.State > api.TaskStateRunning { - if oldTask != nil { - s.deleteTask(ctx, oldTask) + if oldTask == nil { + return 1 + } + s.deleteTask(ctx, oldTask) + if t.Status.State != oldTask.Status.State && + (t.Status.State == api.TaskStateFailed || t.Status.State == api.TaskStateRejected) { + nodeInfo, err := s.nodeSet.nodeInfo(t.NodeID) + if err == nil { + nodeInfo.taskFailed(ctx, t.ServiceID) + s.nodeSet.updateNode(nodeInfo) + } } return 1 } @@ -240,7 +259,7 @@ func (s *Scheduler) updateTask(ctx context.Context, t *api.Task) int { return 1 } - if t.Status.State == api.TaskStateAllocated { + if t.Status.State == api.TaskStatePending { if oldTask != nil { s.deleteTask(ctx, oldTask) } @@ -481,7 +500,23 @@ func (s *Scheduler) scheduleTaskGroup(ctx context.Context, taskGroup map[string] s.pipeline.SetTask(t) + now := time.Now() + nodeLess := func(a *NodeInfo, b *NodeInfo) bool { + // If either node has at least maxFailures recent failures, + // that's the deciding factor. + recentFailuresA := a.countRecentFailures(now, t.ServiceID) + recentFailuresB := b.countRecentFailures(now, t.ServiceID) + + if recentFailuresA >= maxFailures || recentFailuresB >= maxFailures { + if recentFailuresA > recentFailuresB { + return false + } + if recentFailuresB > recentFailuresA { + return true + } + } + tasksByServiceA := a.DesiredRunningTasksCountByService[t.ServiceID] tasksByServiceB := b.DesiredRunningTasksCountByService[t.ServiceID] diff --git a/vendor/src/github.com/docker/swarmkit/manager/state/raft/raft.go b/vendor/src/github.com/docker/swarmkit/manager/state/raft/raft.go index 7112f25e687aa..362134827735e 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/state/raft/raft.go +++ b/vendor/src/github.com/docker/swarmkit/manager/state/raft/raft.go @@ -755,6 +755,9 @@ func (n *Node) Leave(ctx context.Context, req *api.LeaveRequest) (*api.LeaveResp return nil, err } + ctx, cancel := n.WithContext(ctx) + defer cancel() + fields := logrus.Fields{ "node.id": nodeInfo.NodeID, "method": "(*Node).Leave", @@ -765,20 +768,7 @@ func (n *Node) Leave(ctx context.Context, req *api.LeaveRequest) (*api.LeaveResp } log.G(ctx).WithFields(fields).Debug("") - // can't stop the raft node while an async RPC is in progress - n.stopMu.RLock() - defer n.stopMu.RUnlock() - - if !n.IsMember() { - return nil, ErrNoRaftMember - } - - if !n.isLeader() { - return nil, ErrLostLeadership - } - - err = n.RemoveMember(ctx, req.Node.RaftID) - if err != nil { + if err := n.removeMember(ctx, req.Node.RaftID); err != nil { return nil, err } @@ -791,12 +781,21 @@ func (n *Node) CanRemoveMember(id uint64) bool { return n.cluster.CanRemoveMember(n.Config.ID, id) } -// RemoveMember submits a configuration change to remove a member from the raft cluster -// after checking if the operation would not result in a loss of quorum. -func (n *Node) RemoveMember(ctx context.Context, id uint64) error { +func (n *Node) removeMember(ctx context.Context, id uint64) error { + // can't stop the raft node while an async RPC is in progress + n.stopMu.RLock() + defer n.stopMu.RUnlock() + + if !n.IsMember() { + return ErrNoRaftMember + } + + if !n.isLeader() { + return ErrLostLeadership + } + n.membershipLock.Lock() defer n.membershipLock.Unlock() - if n.cluster.CanRemoveMember(n.Config.ID, id) { cc := raftpb.ConfChange{ ID: id, @@ -804,15 +803,21 @@ func (n *Node) RemoveMember(ctx context.Context, id uint64) error { NodeID: id, Context: []byte(""), } - ctx, cancel := n.WithContext(ctx) err := n.configure(ctx, cc) - cancel() return err } return ErrCannotRemoveMember } +// RemoveMember submits a configuration change to remove a member from the raft cluster +// after checking if the operation would not result in a loss of quorum. +func (n *Node) RemoveMember(ctx context.Context, id uint64) error { + ctx, cancel := n.WithContext(ctx) + defer cancel() + return n.removeMember(ctx, id) +} + // ProcessRaftMessage calls 'Step' which advances the // raft state machine with the provided message on the // receiving node diff --git a/vendor/src/github.com/docker/swarmkit/manager/state/store/memory.go b/vendor/src/github.com/docker/swarmkit/manager/state/store/memory.go index 495a22e3cb9e7..6c071f29c7ed7 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/state/store/memory.go +++ b/vendor/src/github.com/docker/swarmkit/manager/state/store/memory.go @@ -240,7 +240,7 @@ func (s *MemoryStore) update(proposer state.Proposer, cb func(Tx) error) error { sa, err = tx.changelistStoreActions() if err == nil { - if sa != nil { + if len(sa) != 0 { err = proposer.ProposeValue(context.Background(), sa, func() { memDBTx.Commit() }) @@ -350,7 +350,7 @@ func (batch *Batch) commit() error { sa, batch.err = batch.tx.changelistStoreActions() if batch.err == nil { - if sa != nil { + if len(sa) != 0 { batch.err = batch.store.proposer.ProposeValue(context.Background(), sa, func() { batch.tx.memDBTx.Commit() }) diff --git a/vendor/src/github.com/docker/swarmkit/manager/state/store/tasks.go b/vendor/src/github.com/docker/swarmkit/manager/state/store/tasks.go index e3727b02475b1..7aea406bd7744 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/state/store/tasks.go +++ b/vendor/src/github.com/docker/swarmkit/manager/state/store/tasks.go @@ -1,11 +1,11 @@ package store import ( - "fmt" "strconv" "strings" "github.com/docker/swarmkit/api" + "github.com/docker/swarmkit/api/naming" "github.com/docker/swarmkit/manager/state" memdb "github.com/hashicorp/go-memdb" ) @@ -112,26 +112,6 @@ func init() { }) } -// TaskName returns the task name from Annotations.Name, -// and, in case Annotations.Name is missing, fallback -// to construct the name from othere information. -func TaskName(t *api.Task) string { - name := t.Annotations.Name - if name == "" { - // If Task name is not assigned then calculated name is used like before. - // This might be removed in the future. - // We use the following scheme for Task name: - // Name := .. (replicated mode) - // := .. (global mode) - if t.Slot != 0 { - name = fmt.Sprintf("%v.%v.%v", t.ServiceAnnotations.Name, t.Slot, t.ID) - } else { - name = fmt.Sprintf("%v.%v.%v", t.ServiceAnnotations.Name, t.NodeID, t.ID) - } - } - return name -} - type taskEntry struct { *api.Task } @@ -245,7 +225,7 @@ func (ti taskIndexerByName) FromObject(obj interface{}) (bool, []byte, error) { panic("unexpected type passed to FromObject") } - name := TaskName(t.Task) + name := naming.Task(t.Task) // Add the null character as a terminator return true, []byte(strings.ToLower(name) + "\x00"), nil diff --git a/vendor/src/github.com/docker/swarmkit/manager/state/watch.go b/vendor/src/github.com/docker/swarmkit/manager/state/watch.go index cf1f29b5e14d9..882ee365b279a 100644 --- a/vendor/src/github.com/docker/swarmkit/manager/state/watch.go +++ b/vendor/src/github.com/docker/swarmkit/manager/state/watch.go @@ -563,12 +563,17 @@ func Watch(queue *watch.Queue, specifiers ...Event) (eventq chan events.Event, c if len(specifiers) == 0 { return queue.Watch() } - return queue.CallbackWatch(events.MatcherFunc(func(event events.Event) bool { + return queue.CallbackWatch(Matcher(specifiers...)) +} + +// Matcher returns an events.Matcher that matches the specifiers with OR logic. +func Matcher(specifiers ...Event) events.MatcherFunc { + return events.MatcherFunc(func(event events.Event) bool { for _, s := range specifiers { if s.matches(event) { return true } } return false - })) + }) } diff --git a/vendor/src/github.com/docker/swarmkit/node/node.go b/vendor/src/github.com/docker/swarmkit/node/node.go index 0367edabad000..c2b52e4579544 100644 --- a/vendor/src/github.com/docker/swarmkit/node/node.go +++ b/vendor/src/github.com/docker/swarmkit/node/node.go @@ -22,6 +22,7 @@ import ( "github.com/docker/swarmkit/log" "github.com/docker/swarmkit/manager" "github.com/docker/swarmkit/remotes" + "github.com/docker/swarmkit/xnet" "github.com/pkg/errors" "golang.org/x/net/context" "google.golang.org/grpc" @@ -104,7 +105,7 @@ type Node struct { err error agent *agent.Agent manager *manager.Manager - roleChangeReq chan api.NodeRole // used to send role updates from the dispatcher api on promotion/demotion + notifyNodeChange chan *api.Node // used to send role updates from the dispatcher api on promotion/demotion } // RemoteAPIAddr returns address on which remote manager api listens. @@ -148,7 +149,7 @@ func New(c *Config) (*Node, error) { closed: make(chan struct{}), ready: make(chan struct{}), certificateRequested: make(chan struct{}), - roleChangeReq: make(chan api.NodeRole, 1), + notifyNodeChange: make(chan *api.Node, 1), } n.roleCond = sync.NewCond(n.RLocker()) n.connCond = sync.NewCond(n.RLocker()) @@ -248,16 +249,29 @@ func (n *Node) run(ctx context.Context) (err error) { } forceCertRenewal := make(chan struct{}) + renewCert := func() { + select { + case forceCertRenewal <- struct{}{}: + case <-ctx.Done(): + } + } + go func() { for { select { case <-ctx.Done(): return - case apirole := <-n.roleChangeReq: + case node := <-n.notifyNodeChange: + // If the server is sending us a ForceRenewal State, renew + if node.Certificate.Status.State == api.IssuanceStateRotate { + renewCert() + continue + } n.Lock() + // If we got a role change, renew lastRole := n.role role := ca.WorkerRole - if apirole == api.NodeRoleManager { + if node.Spec.Role == api.NodeRoleManager { role = ca.ManagerRole } if lastRole == role { @@ -270,11 +284,7 @@ func (n *Node) run(ctx context.Context) (err error) { n.roleCond.Broadcast() } n.Unlock() - select { - case forceCertRenewal <- struct{}{}: - case <-ctx.Done(): - return - } + renewCert() } } }() @@ -380,7 +390,7 @@ func (n *Node) runAgent(ctx context.Context, db *bolt.DB, creds credentials.Tran Managers: n.remotes, Executor: n.config.Executor, DB: db, - NotifyRoleChange: n.roleChangeReq, + NotifyNodeChange: n.notifyNodeChange, Credentials: creds, }) if err != nil { @@ -550,7 +560,7 @@ func (n *Node) initManagerConnection(ctx context.Context, ready chan<- struct{}) addr := n.config.ListenControlAPI opts = append(opts, grpc.WithDialer( func(addr string, timeout time.Duration) (net.Conn, error) { - return net.DialTimeout("unix", addr, timeout) + return xnet.DialTimeoutLocal(addr, timeout) })) conn, err := grpc.Dial(addr, opts...) if err != nil { diff --git a/vendor/src/github.com/docker/swarmkit/protobuf/plugin/gen.go b/vendor/src/github.com/docker/swarmkit/protobuf/plugin/gen.go index b68b83798a25c..1552a2f01b07f 100644 --- a/vendor/src/github.com/docker/swarmkit/protobuf/plugin/gen.go +++ b/vendor/src/github.com/docker/swarmkit/protobuf/plugin/gen.go @@ -1,3 +1,3 @@ package plugin -//go:generate protoc -I.:/usr/local --gogoswarm_out=import_path=github.com/docker/swarmkit/protobuf/plugin,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor:. plugin.proto +//go:generate protoc -I.:../../vendor/github.com/gogo/protobuf/protobuf --gogoswarm_out=import_path=github.com/docker/swarmkit/protobuf/plugin,Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor:. plugin.proto diff --git a/vendor/src/github.com/docker/swarmkit/xnet/xnet_unix.go b/vendor/src/github.com/docker/swarmkit/xnet/xnet_unix.go new file mode 100644 index 0000000000000..7dc7732345e00 --- /dev/null +++ b/vendor/src/github.com/docker/swarmkit/xnet/xnet_unix.go @@ -0,0 +1,20 @@ +// +build !windows + +package xnet + +import ( + "net" + "time" +) + +// ListenLocal opens a local socket for control communication +func ListenLocal(socket string) (net.Listener, error) { + // on unix it's just a unix socket + return net.Listen("unix", socket) +} + +// DialTimeoutLocal is a DialTimeout function for local sockets +func DialTimeoutLocal(socket string, timeout time.Duration) (net.Conn, error) { + // on unix, we dial a unix socket + return net.DialTimeout("unix", socket, timeout) +} diff --git a/vendor/src/github.com/docker/swarmkit/xnet/xnet_windows.go b/vendor/src/github.com/docker/swarmkit/xnet/xnet_windows.go new file mode 100644 index 0000000000000..3f975144464a5 --- /dev/null +++ b/vendor/src/github.com/docker/swarmkit/xnet/xnet_windows.go @@ -0,0 +1,22 @@ +// +build windows + +package xnet + +import ( + "net" + "time" + + "github.com/Microsoft/go-winio" +) + +// ListenLocal opens a local socket for control communication +func ListenLocal(socket string) (net.Listener, error) { + // on windows, our socket is actually a named pipe + return winio.ListenPipe(socket, nil) +} + +// DialTimeoutLocal is a DialTimeout function for local sockets +func DialTimeoutLocal(socket string, timeout time.Duration) (net.Conn, error) { + // On windows, we dial a named pipe + return winio.DialPipe(socket, &timeout) +} diff --git a/vendor/src/github.com/mitchellh/mapstructure/.travis.yml b/vendor/src/github.com/mitchellh/mapstructure/.travis.yml new file mode 100644 index 0000000000000..7f3fe9a9699db --- /dev/null +++ b/vendor/src/github.com/mitchellh/mapstructure/.travis.yml @@ -0,0 +1,7 @@ +language: go + +go: + - 1.4 + +script: + - go test diff --git a/vendor/src/github.com/mitchellh/mapstructure/LICENSE b/vendor/src/github.com/mitchellh/mapstructure/LICENSE new file mode 100644 index 0000000000000..f9c841a51e0d1 --- /dev/null +++ b/vendor/src/github.com/mitchellh/mapstructure/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Mitchell Hashimoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/src/github.com/mitchellh/mapstructure/README.md b/vendor/src/github.com/mitchellh/mapstructure/README.md new file mode 100644 index 0000000000000..659d6885fc7ec --- /dev/null +++ b/vendor/src/github.com/mitchellh/mapstructure/README.md @@ -0,0 +1,46 @@ +# mapstructure + +mapstructure is a Go library for decoding generic map values to structures +and vice versa, while providing helpful error handling. + +This library is most useful when decoding values from some data stream (JSON, +Gob, etc.) where you don't _quite_ know the structure of the underlying data +until you read a part of it. You can therefore read a `map[string]interface{}` +and use this library to decode it into the proper underlying native Go +structure. + +## Installation + +Standard `go get`: + +``` +$ go get github.com/mitchellh/mapstructure +``` + +## Usage & Example + +For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/mapstructure). + +The `Decode` function has examples associated with it there. + +## But Why?! + +Go offers fantastic standard libraries for decoding formats such as JSON. +The standard method is to have a struct pre-created, and populate that struct +from the bytes of the encoded format. This is great, but the problem is if +you have configuration or an encoding that changes slightly depending on +specific fields. For example, consider this JSON: + +```json +{ + "type": "person", + "name": "Mitchell" +} +``` + +Perhaps we can't populate a specific structure without first reading +the "type" field from the JSON. We could always do two passes over the +decoding of the JSON (reading the "type" first, and the rest later). +However, it is much simpler to just decode this into a `map[string]interface{}` +structure, read the "type" key, then use something like this library +to decode it into the proper structure. diff --git a/vendor/src/github.com/mitchellh/mapstructure/decode_hooks.go b/vendor/src/github.com/mitchellh/mapstructure/decode_hooks.go new file mode 100644 index 0000000000000..115ae67c11573 --- /dev/null +++ b/vendor/src/github.com/mitchellh/mapstructure/decode_hooks.go @@ -0,0 +1,154 @@ +package mapstructure + +import ( + "errors" + "reflect" + "strconv" + "strings" + "time" +) + +// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns +// it into the proper DecodeHookFunc type, such as DecodeHookFuncType. +func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { + // Create variables here so we can reference them with the reflect pkg + var f1 DecodeHookFuncType + var f2 DecodeHookFuncKind + + // Fill in the variables into this interface and the rest is done + // automatically using the reflect package. + potential := []interface{}{f1, f2} + + v := reflect.ValueOf(h) + vt := v.Type() + for _, raw := range potential { + pt := reflect.ValueOf(raw).Type() + if vt.ConvertibleTo(pt) { + return v.Convert(pt).Interface() + } + } + + return nil +} + +// DecodeHookExec executes the given decode hook. This should be used +// since it'll naturally degrade to the older backwards compatible DecodeHookFunc +// that took reflect.Kind instead of reflect.Type. +func DecodeHookExec( + raw DecodeHookFunc, + from reflect.Type, to reflect.Type, + data interface{}) (interface{}, error) { + // Build our arguments that reflect expects + argVals := make([]reflect.Value, 3) + argVals[0] = reflect.ValueOf(from) + argVals[1] = reflect.ValueOf(to) + argVals[2] = reflect.ValueOf(data) + + switch f := typedDecodeHook(raw).(type) { + case DecodeHookFuncType: + return f(from, to, data) + case DecodeHookFuncKind: + return f(from.Kind(), to.Kind(), data) + default: + return nil, errors.New("invalid decode hook signature") + } +} + +// ComposeDecodeHookFunc creates a single DecodeHookFunc that +// automatically composes multiple DecodeHookFuncs. +// +// The composed funcs are called in order, with the result of the +// previous transformation. +func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + var err error + for _, f1 := range fs { + data, err = DecodeHookExec(f1, f, t, data) + if err != nil { + return nil, err + } + + // Modify the from kind to be correct with the new data + f = nil + if val := reflect.ValueOf(data); val.IsValid() { + f = val.Type() + } + } + + return data, nil + } +} + +// StringToSliceHookFunc returns a DecodeHookFunc that converts +// string to []string by splitting on the given sep. +func StringToSliceHookFunc(sep string) DecodeHookFunc { + return func( + f reflect.Kind, + t reflect.Kind, + data interface{}) (interface{}, error) { + if f != reflect.String || t != reflect.Slice { + return data, nil + } + + raw := data.(string) + if raw == "" { + return []string{}, nil + } + + return strings.Split(raw, sep), nil + } +} + +// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts +// strings to time.Duration. +func StringToTimeDurationHookFunc() DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(time.Duration(5)) { + return data, nil + } + + // Convert it by parsing + return time.ParseDuration(data.(string)) + } +} + +func WeaklyTypedHook( + f reflect.Kind, + t reflect.Kind, + data interface{}) (interface{}, error) { + dataVal := reflect.ValueOf(data) + switch t { + case reflect.String: + switch f { + case reflect.Bool: + if dataVal.Bool() { + return "1", nil + } else { + return "0", nil + } + case reflect.Float32: + return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil + case reflect.Int: + return strconv.FormatInt(dataVal.Int(), 10), nil + case reflect.Slice: + dataType := dataVal.Type() + elemKind := dataType.Elem().Kind() + if elemKind == reflect.Uint8 { + return string(dataVal.Interface().([]uint8)), nil + } + case reflect.Uint: + return strconv.FormatUint(dataVal.Uint(), 10), nil + } + } + + return data, nil +} diff --git a/vendor/src/github.com/mitchellh/mapstructure/decode_hooks_test.go b/vendor/src/github.com/mitchellh/mapstructure/decode_hooks_test.go new file mode 100644 index 0000000000000..53289afcfbf67 --- /dev/null +++ b/vendor/src/github.com/mitchellh/mapstructure/decode_hooks_test.go @@ -0,0 +1,229 @@ +package mapstructure + +import ( + "errors" + "reflect" + "testing" + "time" +) + +func TestComposeDecodeHookFunc(t *testing.T) { + f1 := func( + f reflect.Kind, + t reflect.Kind, + data interface{}) (interface{}, error) { + return data.(string) + "foo", nil + } + + f2 := func( + f reflect.Kind, + t reflect.Kind, + data interface{}) (interface{}, error) { + return data.(string) + "bar", nil + } + + f := ComposeDecodeHookFunc(f1, f2) + + result, err := DecodeHookExec( + f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), "") + if err != nil { + t.Fatalf("bad: %s", err) + } + if result.(string) != "foobar" { + t.Fatalf("bad: %#v", result) + } +} + +func TestComposeDecodeHookFunc_err(t *testing.T) { + f1 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) { + return nil, errors.New("foo") + } + + f2 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) { + panic("NOPE") + } + + f := ComposeDecodeHookFunc(f1, f2) + + _, err := DecodeHookExec( + f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), 42) + if err.Error() != "foo" { + t.Fatalf("bad: %s", err) + } +} + +func TestComposeDecodeHookFunc_kinds(t *testing.T) { + var f2From reflect.Kind + + f1 := func( + f reflect.Kind, + t reflect.Kind, + data interface{}) (interface{}, error) { + return int(42), nil + } + + f2 := func( + f reflect.Kind, + t reflect.Kind, + data interface{}) (interface{}, error) { + f2From = f + return data, nil + } + + f := ComposeDecodeHookFunc(f1, f2) + + _, err := DecodeHookExec( + f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), "") + if err != nil { + t.Fatalf("bad: %s", err) + } + if f2From != reflect.Int { + t.Fatalf("bad: %#v", f2From) + } +} + +func TestStringToSliceHookFunc(t *testing.T) { + f := StringToSliceHookFunc(",") + + strType := reflect.TypeOf("") + sliceType := reflect.TypeOf([]byte("")) + cases := []struct { + f, t reflect.Type + data interface{} + result interface{} + err bool + }{ + {sliceType, sliceType, 42, 42, false}, + {strType, strType, 42, 42, false}, + { + strType, + sliceType, + "foo,bar,baz", + []string{"foo", "bar", "baz"}, + false, + }, + { + strType, + sliceType, + "", + []string{}, + false, + }, + } + + for i, tc := range cases { + actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data) + if tc.err != (err != nil) { + t.Fatalf("case %d: expected err %#v", i, tc.err) + } + if !reflect.DeepEqual(actual, tc.result) { + t.Fatalf( + "case %d: expected %#v, got %#v", + i, tc.result, actual) + } + } +} + +func TestStringToTimeDurationHookFunc(t *testing.T) { + f := StringToTimeDurationHookFunc() + + strType := reflect.TypeOf("") + timeType := reflect.TypeOf(time.Duration(5)) + cases := []struct { + f, t reflect.Type + data interface{} + result interface{} + err bool + }{ + {strType, timeType, "5s", 5 * time.Second, false}, + {strType, timeType, "5", time.Duration(0), true}, + {strType, strType, "5", "5", false}, + } + + for i, tc := range cases { + actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data) + if tc.err != (err != nil) { + t.Fatalf("case %d: expected err %#v", i, tc.err) + } + if !reflect.DeepEqual(actual, tc.result) { + t.Fatalf( + "case %d: expected %#v, got %#v", + i, tc.result, actual) + } + } +} + +func TestWeaklyTypedHook(t *testing.T) { + var f DecodeHookFunc = WeaklyTypedHook + + boolType := reflect.TypeOf(true) + strType := reflect.TypeOf("") + sliceType := reflect.TypeOf([]byte("")) + cases := []struct { + f, t reflect.Type + data interface{} + result interface{} + err bool + }{ + // TO STRING + { + boolType, + strType, + false, + "0", + false, + }, + + { + boolType, + strType, + true, + "1", + false, + }, + + { + reflect.TypeOf(float32(1)), + strType, + float32(7), + "7", + false, + }, + + { + reflect.TypeOf(int(1)), + strType, + int(7), + "7", + false, + }, + + { + sliceType, + strType, + []uint8("foo"), + "foo", + false, + }, + + { + reflect.TypeOf(uint(1)), + strType, + uint(7), + "7", + false, + }, + } + + for i, tc := range cases { + actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data) + if tc.err != (err != nil) { + t.Fatalf("case %d: expected err %#v", i, tc.err) + } + if !reflect.DeepEqual(actual, tc.result) { + t.Fatalf( + "case %d: expected %#v, got %#v", + i, tc.result, actual) + } + } +} diff --git a/vendor/src/github.com/mitchellh/mapstructure/error.go b/vendor/src/github.com/mitchellh/mapstructure/error.go new file mode 100644 index 0000000000000..47a99e5af3f1b --- /dev/null +++ b/vendor/src/github.com/mitchellh/mapstructure/error.go @@ -0,0 +1,50 @@ +package mapstructure + +import ( + "errors" + "fmt" + "sort" + "strings" +) + +// Error implements the error interface and can represents multiple +// errors that occur in the course of a single decode. +type Error struct { + Errors []string +} + +func (e *Error) Error() string { + points := make([]string, len(e.Errors)) + for i, err := range e.Errors { + points[i] = fmt.Sprintf("* %s", err) + } + + sort.Strings(points) + return fmt.Sprintf( + "%d error(s) decoding:\n\n%s", + len(e.Errors), strings.Join(points, "\n")) +} + +// WrappedErrors implements the errwrap.Wrapper interface to make this +// return value more useful with the errwrap and go-multierror libraries. +func (e *Error) WrappedErrors() []error { + if e == nil { + return nil + } + + result := make([]error, len(e.Errors)) + for i, e := range e.Errors { + result[i] = errors.New(e) + } + + return result +} + +func appendErrors(errors []string, err error) []string { + switch e := err.(type) { + case *Error: + return append(errors, e.Errors...) + default: + return append(errors, e.Error()) + } +} diff --git a/vendor/src/github.com/mitchellh/mapstructure/mapstructure.go b/vendor/src/github.com/mitchellh/mapstructure/mapstructure.go new file mode 100644 index 0000000000000..b0ab89b6310f7 --- /dev/null +++ b/vendor/src/github.com/mitchellh/mapstructure/mapstructure.go @@ -0,0 +1,782 @@ +// The mapstructure package exposes functionality to convert an +// abitrary map[string]interface{} into a native Go structure. +// +// The Go structure can be arbitrarily complex, containing slices, +// other structs, etc. and the decoder will properly decode nested +// maps and so on into the proper structures in the native Go struct. +// See the examples to see what the decoder is capable of. +package mapstructure + +import ( + "encoding/json" + "errors" + "fmt" + "reflect" + "sort" + "strconv" + "strings" +) + +// DecodeHookFunc is the callback function that can be used for +// data transformations. See "DecodeHook" in the DecoderConfig +// struct. +// +// The type should be DecodeHookFuncType or DecodeHookFuncKind. +// Either is accepted. Types are a superset of Kinds (Types can return +// Kinds) and are generally a richer thing to use, but Kinds are simpler +// if you only need those. +// +// The reason DecodeHookFunc is multi-typed is for backwards compatibility: +// we started with Kinds and then realized Types were the better solution, +// but have a promise to not break backwards compat so we now support +// both. +type DecodeHookFunc interface{} + +type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error) +type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) + +// DecoderConfig is the configuration that is used to create a new decoder +// and allows customization of various aspects of decoding. +type DecoderConfig struct { + // DecodeHook, if set, will be called before any decoding and any + // type conversion (if WeaklyTypedInput is on). This lets you modify + // the values before they're set down onto the resulting struct. + // + // If an error is returned, the entire decode will fail with that + // error. + DecodeHook DecodeHookFunc + + // If ErrorUnused is true, then it is an error for there to exist + // keys in the original map that were unused in the decoding process + // (extra keys). + ErrorUnused bool + + // ZeroFields, if set to true, will zero fields before writing them. + // For example, a map will be emptied before decoded values are put in + // it. If this is false, a map will be merged. + ZeroFields bool + + // If WeaklyTypedInput is true, the decoder will make the following + // "weak" conversions: + // + // - bools to string (true = "1", false = "0") + // - numbers to string (base 10) + // - bools to int/uint (true = 1, false = 0) + // - strings to int/uint (base implied by prefix) + // - int to bool (true if value != 0) + // - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F, + // FALSE, false, False. Anything else is an error) + // - empty array = empty map and vice versa + // - negative numbers to overflowed uint values (base 10) + // - slice of maps to a merged map + // + WeaklyTypedInput bool + + // Metadata is the struct that will contain extra metadata about + // the decoding. If this is nil, then no metadata will be tracked. + Metadata *Metadata + + // Result is a pointer to the struct that will contain the decoded + // value. + Result interface{} + + // The tag name that mapstructure reads for field names. This + // defaults to "mapstructure" + TagName string +} + +// A Decoder takes a raw interface value and turns it into structured +// data, keeping track of rich error information along the way in case +// anything goes wrong. Unlike the basic top-level Decode method, you can +// more finely control how the Decoder behaves using the DecoderConfig +// structure. The top-level Decode method is just a convenience that sets +// up the most basic Decoder. +type Decoder struct { + config *DecoderConfig +} + +// Metadata contains information about decoding a structure that +// is tedious or difficult to get otherwise. +type Metadata struct { + // Keys are the keys of the structure which were successfully decoded + Keys []string + + // Unused is a slice of keys that were found in the raw value but + // weren't decoded since there was no matching field in the result interface + Unused []string +} + +// Decode takes a map and uses reflection to convert it into the +// given Go native structure. val must be a pointer to a struct. +func Decode(m interface{}, rawVal interface{}) error { + config := &DecoderConfig{ + Metadata: nil, + Result: rawVal, + } + + decoder, err := NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(m) +} + +// WeakDecode is the same as Decode but is shorthand to enable +// WeaklyTypedInput. See DecoderConfig for more info. +func WeakDecode(input, output interface{}) error { + config := &DecoderConfig{ + Metadata: nil, + Result: output, + WeaklyTypedInput: true, + } + + decoder, err := NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +// NewDecoder returns a new decoder for the given configuration. Once +// a decoder has been returned, the same configuration must not be used +// again. +func NewDecoder(config *DecoderConfig) (*Decoder, error) { + val := reflect.ValueOf(config.Result) + if val.Kind() != reflect.Ptr { + return nil, errors.New("result must be a pointer") + } + + val = val.Elem() + if !val.CanAddr() { + return nil, errors.New("result must be addressable (a pointer)") + } + + if config.Metadata != nil { + if config.Metadata.Keys == nil { + config.Metadata.Keys = make([]string, 0) + } + + if config.Metadata.Unused == nil { + config.Metadata.Unused = make([]string, 0) + } + } + + if config.TagName == "" { + config.TagName = "mapstructure" + } + + result := &Decoder{ + config: config, + } + + return result, nil +} + +// Decode decodes the given raw interface to the target pointer specified +// by the configuration. +func (d *Decoder) Decode(raw interface{}) error { + return d.decode("", raw, reflect.ValueOf(d.config.Result).Elem()) +} + +// Decodes an unknown data type into a specific reflection value. +func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error { + if data == nil { + // If the data is nil, then we don't set anything. + return nil + } + + dataVal := reflect.ValueOf(data) + if !dataVal.IsValid() { + // If the data value is invalid, then we just set the value + // to be the zero value. + val.Set(reflect.Zero(val.Type())) + return nil + } + + if d.config.DecodeHook != nil { + // We have a DecodeHook, so let's pre-process the data. + var err error + data, err = DecodeHookExec( + d.config.DecodeHook, + dataVal.Type(), val.Type(), data) + if err != nil { + return err + } + } + + var err error + dataKind := getKind(val) + switch dataKind { + case reflect.Bool: + err = d.decodeBool(name, data, val) + case reflect.Interface: + err = d.decodeBasic(name, data, val) + case reflect.String: + err = d.decodeString(name, data, val) + case reflect.Int: + err = d.decodeInt(name, data, val) + case reflect.Uint: + err = d.decodeUint(name, data, val) + case reflect.Float32: + err = d.decodeFloat(name, data, val) + case reflect.Struct: + err = d.decodeStruct(name, data, val) + case reflect.Map: + err = d.decodeMap(name, data, val) + case reflect.Ptr: + err = d.decodePtr(name, data, val) + case reflect.Slice: + err = d.decodeSlice(name, data, val) + default: + // If we reached this point then we weren't able to decode it + return fmt.Errorf("%s: unsupported type: %s", name, dataKind) + } + + // If we reached here, then we successfully decoded SOMETHING, so + // mark the key as used if we're tracking metadata. + if d.config.Metadata != nil && name != "" { + d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) + } + + return err +} + +// This decodes a basic type (bool, int, string, etc.) and sets the +// value to "data" of that type. +func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.ValueOf(data) + if !dataVal.IsValid() { + dataVal = reflect.Zero(val.Type()) + } + + dataValType := dataVal.Type() + if !dataValType.AssignableTo(val.Type()) { + return fmt.Errorf( + "'%s' expected type '%s', got '%s'", + name, val.Type(), dataValType) + } + + val.Set(dataVal) + return nil +} + +func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.ValueOf(data) + dataKind := getKind(dataVal) + + converted := true + switch { + case dataKind == reflect.String: + val.SetString(dataVal.String()) + case dataKind == reflect.Bool && d.config.WeaklyTypedInput: + if dataVal.Bool() { + val.SetString("1") + } else { + val.SetString("0") + } + case dataKind == reflect.Int && d.config.WeaklyTypedInput: + val.SetString(strconv.FormatInt(dataVal.Int(), 10)) + case dataKind == reflect.Uint && d.config.WeaklyTypedInput: + val.SetString(strconv.FormatUint(dataVal.Uint(), 10)) + case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: + val.SetString(strconv.FormatFloat(dataVal.Float(), 'f', -1, 64)) + case dataKind == reflect.Slice && d.config.WeaklyTypedInput: + dataType := dataVal.Type() + elemKind := dataType.Elem().Kind() + switch { + case elemKind == reflect.Uint8: + val.SetString(string(dataVal.Interface().([]uint8))) + default: + converted = false + } + default: + converted = false + } + + if !converted { + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s'", + name, val.Type(), dataVal.Type()) + } + + return nil +} + +func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.ValueOf(data) + dataKind := getKind(dataVal) + dataType := dataVal.Type() + + switch { + case dataKind == reflect.Int: + val.SetInt(dataVal.Int()) + case dataKind == reflect.Uint: + val.SetInt(int64(dataVal.Uint())) + case dataKind == reflect.Float32: + val.SetInt(int64(dataVal.Float())) + case dataKind == reflect.Bool && d.config.WeaklyTypedInput: + if dataVal.Bool() { + val.SetInt(1) + } else { + val.SetInt(0) + } + case dataKind == reflect.String && d.config.WeaklyTypedInput: + i, err := strconv.ParseInt(dataVal.String(), 0, val.Type().Bits()) + if err == nil { + val.SetInt(i) + } else { + return fmt.Errorf("cannot parse '%s' as int: %s", name, err) + } + case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": + jn := data.(json.Number) + i, err := jn.Int64() + if err != nil { + return fmt.Errorf( + "error decoding json.Number into %s: %s", name, err) + } + val.SetInt(i) + default: + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s'", + name, val.Type(), dataVal.Type()) + } + + return nil +} + +func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.ValueOf(data) + dataKind := getKind(dataVal) + + switch { + case dataKind == reflect.Int: + i := dataVal.Int() + if i < 0 && !d.config.WeaklyTypedInput { + return fmt.Errorf("cannot parse '%s', %d overflows uint", + name, i) + } + val.SetUint(uint64(i)) + case dataKind == reflect.Uint: + val.SetUint(dataVal.Uint()) + case dataKind == reflect.Float32: + f := dataVal.Float() + if f < 0 && !d.config.WeaklyTypedInput { + return fmt.Errorf("cannot parse '%s', %f overflows uint", + name, f) + } + val.SetUint(uint64(f)) + case dataKind == reflect.Bool && d.config.WeaklyTypedInput: + if dataVal.Bool() { + val.SetUint(1) + } else { + val.SetUint(0) + } + case dataKind == reflect.String && d.config.WeaklyTypedInput: + i, err := strconv.ParseUint(dataVal.String(), 0, val.Type().Bits()) + if err == nil { + val.SetUint(i) + } else { + return fmt.Errorf("cannot parse '%s' as uint: %s", name, err) + } + default: + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s'", + name, val.Type(), dataVal.Type()) + } + + return nil +} + +func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.ValueOf(data) + dataKind := getKind(dataVal) + + switch { + case dataKind == reflect.Bool: + val.SetBool(dataVal.Bool()) + case dataKind == reflect.Int && d.config.WeaklyTypedInput: + val.SetBool(dataVal.Int() != 0) + case dataKind == reflect.Uint && d.config.WeaklyTypedInput: + val.SetBool(dataVal.Uint() != 0) + case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: + val.SetBool(dataVal.Float() != 0) + case dataKind == reflect.String && d.config.WeaklyTypedInput: + b, err := strconv.ParseBool(dataVal.String()) + if err == nil { + val.SetBool(b) + } else if dataVal.String() == "" { + val.SetBool(false) + } else { + return fmt.Errorf("cannot parse '%s' as bool: %s", name, err) + } + default: + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s'", + name, val.Type(), dataVal.Type()) + } + + return nil +} + +func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.ValueOf(data) + dataKind := getKind(dataVal) + dataType := dataVal.Type() + + switch { + case dataKind == reflect.Int: + val.SetFloat(float64(dataVal.Int())) + case dataKind == reflect.Uint: + val.SetFloat(float64(dataVal.Uint())) + case dataKind == reflect.Float32: + val.SetFloat(float64(dataVal.Float())) + case dataKind == reflect.Bool && d.config.WeaklyTypedInput: + if dataVal.Bool() { + val.SetFloat(1) + } else { + val.SetFloat(0) + } + case dataKind == reflect.String && d.config.WeaklyTypedInput: + f, err := strconv.ParseFloat(dataVal.String(), val.Type().Bits()) + if err == nil { + val.SetFloat(f) + } else { + return fmt.Errorf("cannot parse '%s' as float: %s", name, err) + } + case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": + jn := data.(json.Number) + i, err := jn.Float64() + if err != nil { + return fmt.Errorf( + "error decoding json.Number into %s: %s", name, err) + } + val.SetFloat(i) + default: + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s'", + name, val.Type(), dataVal.Type()) + } + + return nil +} + +func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error { + valType := val.Type() + valKeyType := valType.Key() + valElemType := valType.Elem() + + // By default we overwrite keys in the current map + valMap := val + + // If the map is nil or we're purposely zeroing fields, make a new map + if valMap.IsNil() || d.config.ZeroFields { + // Make a new map to hold our result + mapType := reflect.MapOf(valKeyType, valElemType) + valMap = reflect.MakeMap(mapType) + } + + // Check input type + dataVal := reflect.Indirect(reflect.ValueOf(data)) + if dataVal.Kind() != reflect.Map { + // In weak mode, we accept a slice of maps as an input... + if d.config.WeaklyTypedInput { + switch dataVal.Kind() { + case reflect.Array, reflect.Slice: + // Special case for BC reasons (covered by tests) + if dataVal.Len() == 0 { + val.Set(valMap) + return nil + } + + for i := 0; i < dataVal.Len(); i++ { + err := d.decode( + fmt.Sprintf("%s[%d]", name, i), + dataVal.Index(i).Interface(), val) + if err != nil { + return err + } + } + + return nil + } + } + + return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) + } + + // Accumulate errors + errors := make([]string, 0) + + for _, k := range dataVal.MapKeys() { + fieldName := fmt.Sprintf("%s[%s]", name, k) + + // First decode the key into the proper type + currentKey := reflect.Indirect(reflect.New(valKeyType)) + if err := d.decode(fieldName, k.Interface(), currentKey); err != nil { + errors = appendErrors(errors, err) + continue + } + + // Next decode the data into the proper type + v := dataVal.MapIndex(k).Interface() + currentVal := reflect.Indirect(reflect.New(valElemType)) + if err := d.decode(fieldName, v, currentVal); err != nil { + errors = appendErrors(errors, err) + continue + } + + valMap.SetMapIndex(currentKey, currentVal) + } + + // Set the built up map to the value + val.Set(valMap) + + // If we had errors, return those + if len(errors) > 0 { + return &Error{errors} + } + + return nil +} + +func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error { + // Create an element of the concrete (non pointer) type and decode + // into that. Then set the value of the pointer to this type. + valType := val.Type() + valElemType := valType.Elem() + realVal := reflect.New(valElemType) + if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil { + return err + } + + val.Set(realVal) + return nil +} + +func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataValKind := dataVal.Kind() + valType := val.Type() + valElemType := valType.Elem() + sliceType := reflect.SliceOf(valElemType) + + // Check input type + if dataValKind != reflect.Array && dataValKind != reflect.Slice { + // Accept empty map instead of array/slice in weakly typed mode + if d.config.WeaklyTypedInput && dataVal.Kind() == reflect.Map && dataVal.Len() == 0 { + val.Set(reflect.MakeSlice(sliceType, 0, 0)) + return nil + } else { + return fmt.Errorf( + "'%s': source data must be an array or slice, got %s", name, dataValKind) + } + } + + // Make a new slice to hold our result, same size as the original data. + valSlice := reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) + + // Accumulate any errors + errors := make([]string, 0) + + for i := 0; i < dataVal.Len(); i++ { + currentData := dataVal.Index(i).Interface() + currentField := valSlice.Index(i) + + fieldName := fmt.Sprintf("%s[%d]", name, i) + if err := d.decode(fieldName, currentData, currentField); err != nil { + errors = appendErrors(errors, err) + } + } + + // Finally, set the value to the slice we built up + val.Set(valSlice) + + // If there were errors, we return those + if len(errors) > 0 { + return &Error{errors} + } + + return nil +} + +func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + + // If the type of the value to write to and the data match directly, + // then we just set it directly instead of recursing into the structure. + if dataVal.Type() == val.Type() { + val.Set(dataVal) + return nil + } + + dataValKind := dataVal.Kind() + if dataValKind != reflect.Map { + return fmt.Errorf("'%s' expected a map, got '%s'", name, dataValKind) + } + + dataValType := dataVal.Type() + if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface { + return fmt.Errorf( + "'%s' needs a map with string keys, has '%s' keys", + name, dataValType.Key().Kind()) + } + + dataValKeys := make(map[reflect.Value]struct{}) + dataValKeysUnused := make(map[interface{}]struct{}) + for _, dataValKey := range dataVal.MapKeys() { + dataValKeys[dataValKey] = struct{}{} + dataValKeysUnused[dataValKey.Interface()] = struct{}{} + } + + errors := make([]string, 0) + + // This slice will keep track of all the structs we'll be decoding. + // There can be more than one struct if there are embedded structs + // that are squashed. + structs := make([]reflect.Value, 1, 5) + structs[0] = val + + // Compile the list of all the fields that we're going to be decoding + // from all the structs. + fields := make(map[*reflect.StructField]reflect.Value) + for len(structs) > 0 { + structVal := structs[0] + structs = structs[1:] + + structType := structVal.Type() + + for i := 0; i < structType.NumField(); i++ { + fieldType := structType.Field(i) + fieldKind := fieldType.Type.Kind() + + // If "squash" is specified in the tag, we squash the field down. + squash := false + tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",") + for _, tag := range tagParts[1:] { + if tag == "squash" { + squash = true + break + } + } + + if squash { + if fieldKind != reflect.Struct { + errors = appendErrors(errors, + fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldKind)) + } else { + structs = append(structs, val.FieldByName(fieldType.Name)) + } + continue + } + + // Normal struct field, store it away + fields[&fieldType] = structVal.Field(i) + } + } + + for fieldType, field := range fields { + fieldName := fieldType.Name + + tagValue := fieldType.Tag.Get(d.config.TagName) + tagValue = strings.SplitN(tagValue, ",", 2)[0] + if tagValue != "" { + fieldName = tagValue + } + + rawMapKey := reflect.ValueOf(fieldName) + rawMapVal := dataVal.MapIndex(rawMapKey) + if !rawMapVal.IsValid() { + // Do a slower search by iterating over each key and + // doing case-insensitive search. + for dataValKey := range dataValKeys { + mK, ok := dataValKey.Interface().(string) + if !ok { + // Not a string key + continue + } + + if strings.EqualFold(mK, fieldName) { + rawMapKey = dataValKey + rawMapVal = dataVal.MapIndex(dataValKey) + break + } + } + + if !rawMapVal.IsValid() { + // There was no matching key in the map for the value in + // the struct. Just ignore. + continue + } + } + + // Delete the key we're using from the unused map so we stop tracking + delete(dataValKeysUnused, rawMapKey.Interface()) + + if !field.IsValid() { + // This should never happen + panic("field is not valid") + } + + // If we can't set the field, then it is unexported or something, + // and we just continue onwards. + if !field.CanSet() { + continue + } + + // If the name is empty string, then we're at the root, and we + // don't dot-join the fields. + if name != "" { + fieldName = fmt.Sprintf("%s.%s", name, fieldName) + } + + if err := d.decode(fieldName, rawMapVal.Interface(), field); err != nil { + errors = appendErrors(errors, err) + } + } + + if d.config.ErrorUnused && len(dataValKeysUnused) > 0 { + keys := make([]string, 0, len(dataValKeysUnused)) + for rawKey := range dataValKeysUnused { + keys = append(keys, rawKey.(string)) + } + sort.Strings(keys) + + err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", ")) + errors = appendErrors(errors, err) + } + + if len(errors) > 0 { + return &Error{errors} + } + + // Add the unused keys to the list of unused keys if we're tracking metadata + if d.config.Metadata != nil { + for rawKey := range dataValKeysUnused { + key := rawKey.(string) + if name != "" { + key = fmt.Sprintf("%s.%s", name, key) + } + + d.config.Metadata.Unused = append(d.config.Metadata.Unused, key) + } + } + + return nil +} + +func getKind(val reflect.Value) reflect.Kind { + kind := val.Kind() + + switch { + case kind >= reflect.Int && kind <= reflect.Int64: + return reflect.Int + case kind >= reflect.Uint && kind <= reflect.Uint64: + return reflect.Uint + case kind >= reflect.Float32 && kind <= reflect.Float64: + return reflect.Float32 + default: + return kind + } +} diff --git a/vendor/src/github.com/mitchellh/mapstructure/mapstructure_benchmark_test.go b/vendor/src/github.com/mitchellh/mapstructure/mapstructure_benchmark_test.go new file mode 100644 index 0000000000000..41d2a41f75469 --- /dev/null +++ b/vendor/src/github.com/mitchellh/mapstructure/mapstructure_benchmark_test.go @@ -0,0 +1,279 @@ +package mapstructure + +import ( + "encoding/json" + "testing" +) + +func Benchmark_Decode(b *testing.B) { + type Person struct { + Name string + Age int + Emails []string + Extra map[string]string + } + + input := map[string]interface{}{ + "name": "Mitchell", + "age": 91, + "emails": []string{"one", "two", "three"}, + "extra": map[string]string{ + "twitter": "mitchellh", + }, + } + + var result Person + for i := 0; i < b.N; i++ { + Decode(input, &result) + } +} + +// decodeViaJSON takes the map data and passes it through encoding/json to convert it into the +// given Go native structure pointed to by v. v must be a pointer to a struct. +func decodeViaJSON(data interface{}, v interface{}) error { + // Perform the task by simply marshalling the input into JSON, + // then unmarshalling it into target native Go struct. + b, err := json.Marshal(data) + if err != nil { + return err + } + return json.Unmarshal(b, v) +} + +func Benchmark_DecodeViaJSON(b *testing.B) { + type Person struct { + Name string + Age int + Emails []string + Extra map[string]string + } + + input := map[string]interface{}{ + "name": "Mitchell", + "age": 91, + "emails": []string{"one", "two", "three"}, + "extra": map[string]string{ + "twitter": "mitchellh", + }, + } + + var result Person + for i := 0; i < b.N; i++ { + decodeViaJSON(input, &result) + } +} + +func Benchmark_DecodeBasic(b *testing.B) { + input := map[string]interface{}{ + "vstring": "foo", + "vint": 42, + "Vuint": 42, + "vbool": true, + "Vfloat": 42.42, + "vsilent": true, + "vdata": 42, + } + + var result Basic + for i := 0; i < b.N; i++ { + Decode(input, &result) + } +} + +func Benchmark_DecodeEmbedded(b *testing.B) { + input := map[string]interface{}{ + "vstring": "foo", + "Basic": map[string]interface{}{ + "vstring": "innerfoo", + }, + "vunique": "bar", + } + + var result Embedded + for i := 0; i < b.N; i++ { + Decode(input, &result) + } +} + +func Benchmark_DecodeTypeConversion(b *testing.B) { + input := map[string]interface{}{ + "IntToFloat": 42, + "IntToUint": 42, + "IntToBool": 1, + "IntToString": 42, + "UintToInt": 42, + "UintToFloat": 42, + "UintToBool": 42, + "UintToString": 42, + "BoolToInt": true, + "BoolToUint": true, + "BoolToFloat": true, + "BoolToString": true, + "FloatToInt": 42.42, + "FloatToUint": 42.42, + "FloatToBool": 42.42, + "FloatToString": 42.42, + "StringToInt": "42", + "StringToUint": "42", + "StringToBool": "1", + "StringToFloat": "42.42", + "SliceToMap": []interface{}{}, + "MapToSlice": map[string]interface{}{}, + } + + var resultStrict TypeConversionResult + for i := 0; i < b.N; i++ { + Decode(input, &resultStrict) + } +} + +func Benchmark_DecodeMap(b *testing.B) { + input := map[string]interface{}{ + "vfoo": "foo", + "vother": map[interface{}]interface{}{ + "foo": "foo", + "bar": "bar", + }, + } + + var result Map + for i := 0; i < b.N; i++ { + Decode(input, &result) + } +} + +func Benchmark_DecodeMapOfStruct(b *testing.B) { + input := map[string]interface{}{ + "value": map[string]interface{}{ + "foo": map[string]string{"vstring": "one"}, + "bar": map[string]string{"vstring": "two"}, + }, + } + + var result MapOfStruct + for i := 0; i < b.N; i++ { + Decode(input, &result) + } +} + +func Benchmark_DecodeSlice(b *testing.B) { + input := map[string]interface{}{ + "vfoo": "foo", + "vbar": []string{"foo", "bar", "baz"}, + } + + var result Slice + for i := 0; i < b.N; i++ { + Decode(input, &result) + } +} + +func Benchmark_DecodeSliceOfStruct(b *testing.B) { + input := map[string]interface{}{ + "value": []map[string]interface{}{ + {"vstring": "one"}, + {"vstring": "two"}, + }, + } + + var result SliceOfStruct + for i := 0; i < b.N; i++ { + Decode(input, &result) + } +} + +func Benchmark_DecodeWeaklyTypedInput(b *testing.B) { + type Person struct { + Name string + Age int + Emails []string + } + + // This input can come from anywhere, but typically comes from + // something like decoding JSON, generated by a weakly typed language + // such as PHP. + input := map[string]interface{}{ + "name": 123, // number => string + "age": "42", // string => number + "emails": map[string]interface{}{}, // empty map => empty array + } + + var result Person + config := &DecoderConfig{ + WeaklyTypedInput: true, + Result: &result, + } + + decoder, err := NewDecoder(config) + if err != nil { + panic(err) + } + + for i := 0; i < b.N; i++ { + decoder.Decode(input) + } +} + +func Benchmark_DecodeMetadata(b *testing.B) { + type Person struct { + Name string + Age int + } + + input := map[string]interface{}{ + "name": "Mitchell", + "age": 91, + "email": "foo@bar.com", + } + + var md Metadata + var result Person + config := &DecoderConfig{ + Metadata: &md, + Result: &result, + } + + decoder, err := NewDecoder(config) + if err != nil { + panic(err) + } + + for i := 0; i < b.N; i++ { + decoder.Decode(input) + } +} + +func Benchmark_DecodeMetadataEmbedded(b *testing.B) { + input := map[string]interface{}{ + "vstring": "foo", + "vunique": "bar", + } + + var md Metadata + var result EmbeddedSquash + config := &DecoderConfig{ + Metadata: &md, + Result: &result, + } + + decoder, err := NewDecoder(config) + if err != nil { + b.Fatalf("err: %s", err) + } + + for i := 0; i < b.N; i++ { + decoder.Decode(input) + } +} + +func Benchmark_DecodeTagged(b *testing.B) { + input := map[string]interface{}{ + "foo": "bar", + "bar": "value", + } + + var result Tagged + for i := 0; i < b.N; i++ { + Decode(input, &result) + } +} diff --git a/vendor/src/github.com/mitchellh/mapstructure/mapstructure_bugs_test.go b/vendor/src/github.com/mitchellh/mapstructure/mapstructure_bugs_test.go new file mode 100644 index 0000000000000..7054f1ac9abc6 --- /dev/null +++ b/vendor/src/github.com/mitchellh/mapstructure/mapstructure_bugs_test.go @@ -0,0 +1,47 @@ +package mapstructure + +import "testing" + +// GH-1 +func TestDecode_NilValue(t *testing.T) { + input := map[string]interface{}{ + "vfoo": nil, + "vother": nil, + } + + var result Map + err := Decode(input, &result) + if err != nil { + t.Fatalf("should not error: %s", err) + } + + if result.Vfoo != "" { + t.Fatalf("value should be default: %s", result.Vfoo) + } + + if result.Vother != nil { + t.Fatalf("Vother should be nil: %s", result.Vother) + } +} + +// GH-10 +func TestDecode_mapInterfaceInterface(t *testing.T) { + input := map[interface{}]interface{}{ + "vfoo": nil, + "vother": nil, + } + + var result Map + err := Decode(input, &result) + if err != nil { + t.Fatalf("should not error: %s", err) + } + + if result.Vfoo != "" { + t.Fatalf("value should be default: %s", result.Vfoo) + } + + if result.Vother != nil { + t.Fatalf("Vother should be nil: %s", result.Vother) + } +} diff --git a/vendor/src/github.com/mitchellh/mapstructure/mapstructure_examples_test.go b/vendor/src/github.com/mitchellh/mapstructure/mapstructure_examples_test.go new file mode 100644 index 0000000000000..f17c214a8a95c --- /dev/null +++ b/vendor/src/github.com/mitchellh/mapstructure/mapstructure_examples_test.go @@ -0,0 +1,203 @@ +package mapstructure + +import ( + "fmt" +) + +func ExampleDecode() { + type Person struct { + Name string + Age int + Emails []string + Extra map[string]string + } + + // This input can come from anywhere, but typically comes from + // something like decoding JSON where we're not quite sure of the + // struct initially. + input := map[string]interface{}{ + "name": "Mitchell", + "age": 91, + "emails": []string{"one", "two", "three"}, + "extra": map[string]string{ + "twitter": "mitchellh", + }, + } + + var result Person + err := Decode(input, &result) + if err != nil { + panic(err) + } + + fmt.Printf("%#v", result) + // Output: + // mapstructure.Person{Name:"Mitchell", Age:91, Emails:[]string{"one", "two", "three"}, Extra:map[string]string{"twitter":"mitchellh"}} +} + +func ExampleDecode_errors() { + type Person struct { + Name string + Age int + Emails []string + Extra map[string]string + } + + // This input can come from anywhere, but typically comes from + // something like decoding JSON where we're not quite sure of the + // struct initially. + input := map[string]interface{}{ + "name": 123, + "age": "bad value", + "emails": []int{1, 2, 3}, + } + + var result Person + err := Decode(input, &result) + if err == nil { + panic("should have an error") + } + + fmt.Println(err.Error()) + // Output: + // 5 error(s) decoding: + // + // * 'Age' expected type 'int', got unconvertible type 'string' + // * 'Emails[0]' expected type 'string', got unconvertible type 'int' + // * 'Emails[1]' expected type 'string', got unconvertible type 'int' + // * 'Emails[2]' expected type 'string', got unconvertible type 'int' + // * 'Name' expected type 'string', got unconvertible type 'int' +} + +func ExampleDecode_metadata() { + type Person struct { + Name string + Age int + } + + // This input can come from anywhere, but typically comes from + // something like decoding JSON where we're not quite sure of the + // struct initially. + input := map[string]interface{}{ + "name": "Mitchell", + "age": 91, + "email": "foo@bar.com", + } + + // For metadata, we make a more advanced DecoderConfig so we can + // more finely configure the decoder that is used. In this case, we + // just tell the decoder we want to track metadata. + var md Metadata + var result Person + config := &DecoderConfig{ + Metadata: &md, + Result: &result, + } + + decoder, err := NewDecoder(config) + if err != nil { + panic(err) + } + + if err := decoder.Decode(input); err != nil { + panic(err) + } + + fmt.Printf("Unused keys: %#v", md.Unused) + // Output: + // Unused keys: []string{"email"} +} + +func ExampleDecode_weaklyTypedInput() { + type Person struct { + Name string + Age int + Emails []string + } + + // This input can come from anywhere, but typically comes from + // something like decoding JSON, generated by a weakly typed language + // such as PHP. + input := map[string]interface{}{ + "name": 123, // number => string + "age": "42", // string => number + "emails": map[string]interface{}{}, // empty map => empty array + } + + var result Person + config := &DecoderConfig{ + WeaklyTypedInput: true, + Result: &result, + } + + decoder, err := NewDecoder(config) + if err != nil { + panic(err) + } + + err = decoder.Decode(input) + if err != nil { + panic(err) + } + + fmt.Printf("%#v", result) + // Output: mapstructure.Person{Name:"123", Age:42, Emails:[]string{}} +} + +func ExampleDecode_tags() { + // Note that the mapstructure tags defined in the struct type + // can indicate which fields the values are mapped to. + type Person struct { + Name string `mapstructure:"person_name"` + Age int `mapstructure:"person_age"` + } + + input := map[string]interface{}{ + "person_name": "Mitchell", + "person_age": 91, + } + + var result Person + err := Decode(input, &result) + if err != nil { + panic(err) + } + + fmt.Printf("%#v", result) + // Output: + // mapstructure.Person{Name:"Mitchell", Age:91} +} + +func ExampleDecode_embeddedStruct() { + // Squashing multiple embedded structs is allowed using the squash tag. + // This is demonstrated by creating a composite struct of multiple types + // and decoding into it. In this case, a person can carry with it both + // a Family and a Location, as well as their own FirstName. + type Family struct { + LastName string + } + type Location struct { + City string + } + type Person struct { + Family `mapstructure:",squash"` + Location `mapstructure:",squash"` + FirstName string + } + + input := map[string]interface{}{ + "FirstName": "Mitchell", + "LastName": "Hashimoto", + "City": "San Francisco", + } + + var result Person + err := Decode(input, &result) + if err != nil { + panic(err) + } + + fmt.Printf("%s %s, %s", result.FirstName, result.LastName, result.City) + // Output: + // Mitchell Hashimoto, San Francisco +} diff --git a/vendor/src/github.com/mitchellh/mapstructure/mapstructure_test.go b/vendor/src/github.com/mitchellh/mapstructure/mapstructure_test.go new file mode 100644 index 0000000000000..f9495727ab35e --- /dev/null +++ b/vendor/src/github.com/mitchellh/mapstructure/mapstructure_test.go @@ -0,0 +1,1147 @@ +package mapstructure + +import ( + "encoding/json" + "io" + "reflect" + "sort" + "strings" + "testing" +) + +type Basic struct { + Vstring string + Vint int + Vuint uint + Vbool bool + Vfloat float64 + Vextra string + vsilent bool + Vdata interface{} + VjsonInt int + VjsonFloat float64 + VjsonNumber json.Number +} + +type BasicSquash struct { + Test Basic `mapstructure:",squash"` +} + +type Embedded struct { + Basic + Vunique string +} + +type EmbeddedPointer struct { + *Basic + Vunique string +} + +type EmbeddedSquash struct { + Basic `mapstructure:",squash"` + Vunique string +} + +type SliceAlias []string + +type EmbeddedSlice struct { + SliceAlias `mapstructure:"slice_alias"` + Vunique string +} + +type SquashOnNonStructType struct { + InvalidSquashType int `mapstructure:",squash"` +} + +type Map struct { + Vfoo string + Vother map[string]string +} + +type MapOfStruct struct { + Value map[string]Basic +} + +type Nested struct { + Vfoo string + Vbar Basic +} + +type NestedPointer struct { + Vfoo string + Vbar *Basic +} + +type NilInterface struct { + W io.Writer +} + +type Slice struct { + Vfoo string + Vbar []string +} + +type SliceOfStruct struct { + Value []Basic +} + +type Tagged struct { + Extra string `mapstructure:"bar,what,what"` + Value string `mapstructure:"foo"` +} + +type TypeConversionResult struct { + IntToFloat float32 + IntToUint uint + IntToBool bool + IntToString string + UintToInt int + UintToFloat float32 + UintToBool bool + UintToString string + BoolToInt int + BoolToUint uint + BoolToFloat float32 + BoolToString string + FloatToInt int + FloatToUint uint + FloatToBool bool + FloatToString string + SliceUint8ToString string + StringToInt int + StringToUint uint + StringToBool bool + StringToFloat float32 + SliceToMap map[string]interface{} + MapToSlice []interface{} +} + +func TestBasicTypes(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vstring": "foo", + "vint": 42, + "Vuint": 42, + "vbool": true, + "Vfloat": 42.42, + "vsilent": true, + "vdata": 42, + "vjsonInt": json.Number("1234"), + "vjsonFloat": json.Number("1234.5"), + "vjsonNumber": json.Number("1234.5"), + } + + var result Basic + err := Decode(input, &result) + if err != nil { + t.Errorf("got an err: %s", err.Error()) + t.FailNow() + } + + if result.Vstring != "foo" { + t.Errorf("vstring value should be 'foo': %#v", result.Vstring) + } + + if result.Vint != 42 { + t.Errorf("vint value should be 42: %#v", result.Vint) + } + + if result.Vuint != 42 { + t.Errorf("vuint value should be 42: %#v", result.Vuint) + } + + if result.Vbool != true { + t.Errorf("vbool value should be true: %#v", result.Vbool) + } + + if result.Vfloat != 42.42 { + t.Errorf("vfloat value should be 42.42: %#v", result.Vfloat) + } + + if result.Vextra != "" { + t.Errorf("vextra value should be empty: %#v", result.Vextra) + } + + if result.vsilent != false { + t.Error("vsilent should not be set, it is unexported") + } + + if result.Vdata != 42 { + t.Error("vdata should be valid") + } + + if result.VjsonInt != 1234 { + t.Errorf("vjsonint value should be 1234: %#v", result.VjsonInt) + } + + if result.VjsonFloat != 1234.5 { + t.Errorf("vjsonfloat value should be 1234.5: %#v", result.VjsonFloat) + } + + if !reflect.DeepEqual(result.VjsonNumber, json.Number("1234.5")) { + t.Errorf("vjsonnumber value should be '1234.5': %T, %#v", result.VjsonNumber, result.VjsonNumber) + } +} + +func TestBasic_IntWithFloat(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vint": float64(42), + } + + var result Basic + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err) + } +} + +func TestBasic_Merge(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vint": 42, + } + + var result Basic + result.Vuint = 100 + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err) + } + + expected := Basic{ + Vint: 42, + Vuint: 100, + } + if !reflect.DeepEqual(result, expected) { + t.Fatalf("bad: %#v", result) + } +} + +func TestDecode_BasicSquash(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vstring": "foo", + } + + var result BasicSquash + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + if result.Test.Vstring != "foo" { + t.Errorf("vstring value should be 'foo': %#v", result.Test.Vstring) + } +} + +func TestDecode_Embedded(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vstring": "foo", + "Basic": map[string]interface{}{ + "vstring": "innerfoo", + }, + "vunique": "bar", + } + + var result Embedded + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + if result.Vstring != "innerfoo" { + t.Errorf("vstring value should be 'innerfoo': %#v", result.Vstring) + } + + if result.Vunique != "bar" { + t.Errorf("vunique value should be 'bar': %#v", result.Vunique) + } +} + +func TestDecode_EmbeddedPointer(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vstring": "foo", + "Basic": map[string]interface{}{ + "vstring": "innerfoo", + }, + "vunique": "bar", + } + + var result EmbeddedPointer + err := Decode(input, &result) + if err != nil { + t.Fatalf("err: %s", err) + } + + expected := EmbeddedPointer{ + Basic: &Basic{ + Vstring: "innerfoo", + }, + Vunique: "bar", + } + if !reflect.DeepEqual(result, expected) { + t.Fatalf("bad: %#v", result) + } +} + +func TestDecode_EmbeddedSlice(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "slice_alias": []string{"foo", "bar"}, + "vunique": "bar", + } + + var result EmbeddedSlice + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + if !reflect.DeepEqual(result.SliceAlias, SliceAlias([]string{"foo", "bar"})) { + t.Errorf("slice value: %#v", result.SliceAlias) + } + + if result.Vunique != "bar" { + t.Errorf("vunique value should be 'bar': %#v", result.Vunique) + } +} + +func TestDecode_EmbeddedSquash(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vstring": "foo", + "vunique": "bar", + } + + var result EmbeddedSquash + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + if result.Vstring != "foo" { + t.Errorf("vstring value should be 'foo': %#v", result.Vstring) + } + + if result.Vunique != "bar" { + t.Errorf("vunique value should be 'bar': %#v", result.Vunique) + } +} + +func TestDecode_SquashOnNonStructType(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "InvalidSquashType": 42, + } + + var result SquashOnNonStructType + err := Decode(input, &result) + if err == nil { + t.Fatal("unexpected success decoding invalid squash field type") + } else if !strings.Contains(err.Error(), "unsupported type for squash") { + t.Fatalf("unexpected error message for invalid squash field type: %s", err) + } +} + +func TestDecode_DecodeHook(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vint": "WHAT", + } + + decodeHook := func(from reflect.Kind, to reflect.Kind, v interface{}) (interface{}, error) { + if from == reflect.String && to != reflect.String { + return 5, nil + } + + return v, nil + } + + var result Basic + config := &DecoderConfig{ + DecodeHook: decodeHook, + Result: &result, + } + + decoder, err := NewDecoder(config) + if err != nil { + t.Fatalf("err: %s", err) + } + + err = decoder.Decode(input) + if err != nil { + t.Fatalf("got an err: %s", err) + } + + if result.Vint != 5 { + t.Errorf("vint should be 5: %#v", result.Vint) + } +} + +func TestDecode_DecodeHookType(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vint": "WHAT", + } + + decodeHook := func(from reflect.Type, to reflect.Type, v interface{}) (interface{}, error) { + if from.Kind() == reflect.String && + to.Kind() != reflect.String { + return 5, nil + } + + return v, nil + } + + var result Basic + config := &DecoderConfig{ + DecodeHook: decodeHook, + Result: &result, + } + + decoder, err := NewDecoder(config) + if err != nil { + t.Fatalf("err: %s", err) + } + + err = decoder.Decode(input) + if err != nil { + t.Fatalf("got an err: %s", err) + } + + if result.Vint != 5 { + t.Errorf("vint should be 5: %#v", result.Vint) + } +} + +func TestDecode_Nil(t *testing.T) { + t.Parallel() + + var input interface{} = nil + result := Basic{ + Vstring: "foo", + } + + err := Decode(input, &result) + if err != nil { + t.Fatalf("err: %s", err) + } + + if result.Vstring != "foo" { + t.Fatalf("bad: %#v", result.Vstring) + } +} + +func TestDecode_NilInterfaceHook(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "w": "", + } + + decodeHook := func(f, t reflect.Type, v interface{}) (interface{}, error) { + if t.String() == "io.Writer" { + return nil, nil + } + + return v, nil + } + + var result NilInterface + config := &DecoderConfig{ + DecodeHook: decodeHook, + Result: &result, + } + + decoder, err := NewDecoder(config) + if err != nil { + t.Fatalf("err: %s", err) + } + + err = decoder.Decode(input) + if err != nil { + t.Fatalf("got an err: %s", err) + } + + if result.W != nil { + t.Errorf("W should be nil: %#v", result.W) + } +} + +func TestDecode_NonStruct(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "foo": "bar", + "bar": "baz", + } + + var result map[string]string + err := Decode(input, &result) + if err != nil { + t.Fatalf("err: %s", err) + } + + if result["foo"] != "bar" { + t.Fatal("foo is not bar") + } +} + +func TestDecode_StructMatch(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vbar": Basic{ + Vstring: "foo", + }, + } + + var result Nested + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + if result.Vbar.Vstring != "foo" { + t.Errorf("bad: %#v", result) + } +} + +func TestDecode_TypeConversion(t *testing.T) { + input := map[string]interface{}{ + "IntToFloat": 42, + "IntToUint": 42, + "IntToBool": 1, + "IntToString": 42, + "UintToInt": 42, + "UintToFloat": 42, + "UintToBool": 42, + "UintToString": 42, + "BoolToInt": true, + "BoolToUint": true, + "BoolToFloat": true, + "BoolToString": true, + "FloatToInt": 42.42, + "FloatToUint": 42.42, + "FloatToBool": 42.42, + "FloatToString": 42.42, + "SliceUint8ToString": []uint8("foo"), + "StringToInt": "42", + "StringToUint": "42", + "StringToBool": "1", + "StringToFloat": "42.42", + "SliceToMap": []interface{}{}, + "MapToSlice": map[string]interface{}{}, + } + + expectedResultStrict := TypeConversionResult{ + IntToFloat: 42.0, + IntToUint: 42, + UintToInt: 42, + UintToFloat: 42, + BoolToInt: 0, + BoolToUint: 0, + BoolToFloat: 0, + FloatToInt: 42, + FloatToUint: 42, + } + + expectedResultWeak := TypeConversionResult{ + IntToFloat: 42.0, + IntToUint: 42, + IntToBool: true, + IntToString: "42", + UintToInt: 42, + UintToFloat: 42, + UintToBool: true, + UintToString: "42", + BoolToInt: 1, + BoolToUint: 1, + BoolToFloat: 1, + BoolToString: "1", + FloatToInt: 42, + FloatToUint: 42, + FloatToBool: true, + FloatToString: "42.42", + SliceUint8ToString: "foo", + StringToInt: 42, + StringToUint: 42, + StringToBool: true, + StringToFloat: 42.42, + SliceToMap: map[string]interface{}{}, + MapToSlice: []interface{}{}, + } + + // Test strict type conversion + var resultStrict TypeConversionResult + err := Decode(input, &resultStrict) + if err == nil { + t.Errorf("should return an error") + } + if !reflect.DeepEqual(resultStrict, expectedResultStrict) { + t.Errorf("expected %v, got: %v", expectedResultStrict, resultStrict) + } + + // Test weak type conversion + var decoder *Decoder + var resultWeak TypeConversionResult + + config := &DecoderConfig{ + WeaklyTypedInput: true, + Result: &resultWeak, + } + + decoder, err = NewDecoder(config) + if err != nil { + t.Fatalf("err: %s", err) + } + + err = decoder.Decode(input) + if err != nil { + t.Fatalf("got an err: %s", err) + } + + if !reflect.DeepEqual(resultWeak, expectedResultWeak) { + t.Errorf("expected \n%#v, got: \n%#v", expectedResultWeak, resultWeak) + } +} + +func TestDecoder_ErrorUnused(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vstring": "hello", + "foo": "bar", + } + + var result Basic + config := &DecoderConfig{ + ErrorUnused: true, + Result: &result, + } + + decoder, err := NewDecoder(config) + if err != nil { + t.Fatalf("err: %s", err) + } + + err = decoder.Decode(input) + if err == nil { + t.Fatal("expected error") + } +} + +func TestMap(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vfoo": "foo", + "vother": map[interface{}]interface{}{ + "foo": "foo", + "bar": "bar", + }, + } + + var result Map + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an error: %s", err) + } + + if result.Vfoo != "foo" { + t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) + } + + if result.Vother == nil { + t.Fatal("vother should not be nil") + } + + if len(result.Vother) != 2 { + t.Error("vother should have two items") + } + + if result.Vother["foo"] != "foo" { + t.Errorf("'foo' key should be foo, got: %#v", result.Vother["foo"]) + } + + if result.Vother["bar"] != "bar" { + t.Errorf("'bar' key should be bar, got: %#v", result.Vother["bar"]) + } +} + +func TestMapMerge(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vfoo": "foo", + "vother": map[interface{}]interface{}{ + "foo": "foo", + "bar": "bar", + }, + } + + var result Map + result.Vother = map[string]string{"hello": "world"} + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an error: %s", err) + } + + if result.Vfoo != "foo" { + t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) + } + + expected := map[string]string{ + "foo": "foo", + "bar": "bar", + "hello": "world", + } + if !reflect.DeepEqual(result.Vother, expected) { + t.Errorf("bad: %#v", result.Vother) + } +} + +func TestMapOfStruct(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "value": map[string]interface{}{ + "foo": map[string]string{"vstring": "one"}, + "bar": map[string]string{"vstring": "two"}, + }, + } + + var result MapOfStruct + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err) + } + + if result.Value == nil { + t.Fatal("value should not be nil") + } + + if len(result.Value) != 2 { + t.Error("value should have two items") + } + + if result.Value["foo"].Vstring != "one" { + t.Errorf("foo value should be 'one', got: %s", result.Value["foo"].Vstring) + } + + if result.Value["bar"].Vstring != "two" { + t.Errorf("bar value should be 'two', got: %s", result.Value["bar"].Vstring) + } +} + +func TestNestedType(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vfoo": "foo", + "vbar": map[string]interface{}{ + "vstring": "foo", + "vint": 42, + "vbool": true, + }, + } + + var result Nested + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + if result.Vfoo != "foo" { + t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) + } + + if result.Vbar.Vstring != "foo" { + t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) + } + + if result.Vbar.Vint != 42 { + t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) + } + + if result.Vbar.Vbool != true { + t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) + } + + if result.Vbar.Vextra != "" { + t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) + } +} + +func TestNestedTypePointer(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vfoo": "foo", + "vbar": &map[string]interface{}{ + "vstring": "foo", + "vint": 42, + "vbool": true, + }, + } + + var result NestedPointer + err := Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + if result.Vfoo != "foo" { + t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo) + } + + if result.Vbar.Vstring != "foo" { + t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring) + } + + if result.Vbar.Vint != 42 { + t.Errorf("vint value should be 42: %#v", result.Vbar.Vint) + } + + if result.Vbar.Vbool != true { + t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool) + } + + if result.Vbar.Vextra != "" { + t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra) + } +} + +func TestSlice(t *testing.T) { + t.Parallel() + + inputStringSlice := map[string]interface{}{ + "vfoo": "foo", + "vbar": []string{"foo", "bar", "baz"}, + } + + inputStringSlicePointer := map[string]interface{}{ + "vfoo": "foo", + "vbar": &[]string{"foo", "bar", "baz"}, + } + + outputStringSlice := &Slice{ + "foo", + []string{"foo", "bar", "baz"}, + } + + testSliceInput(t, inputStringSlice, outputStringSlice) + testSliceInput(t, inputStringSlicePointer, outputStringSlice) +} + +func TestInvalidSlice(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vfoo": "foo", + "vbar": 42, + } + + result := Slice{} + err := Decode(input, &result) + if err == nil { + t.Errorf("expected failure") + } +} + +func TestSliceOfStruct(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "value": []map[string]interface{}{ + {"vstring": "one"}, + {"vstring": "two"}, + }, + } + + var result SliceOfStruct + err := Decode(input, &result) + if err != nil { + t.Fatalf("got unexpected error: %s", err) + } + + if len(result.Value) != 2 { + t.Fatalf("expected two values, got %d", len(result.Value)) + } + + if result.Value[0].Vstring != "one" { + t.Errorf("first value should be 'one', got: %s", result.Value[0].Vstring) + } + + if result.Value[1].Vstring != "two" { + t.Errorf("second value should be 'two', got: %s", result.Value[1].Vstring) + } +} + +func TestSliceToMap(t *testing.T) { + t.Parallel() + + input := []map[string]interface{}{ + { + "foo": "bar", + }, + { + "bar": "baz", + }, + } + + var result map[string]interface{} + err := WeakDecode(input, &result) + if err != nil { + t.Fatalf("got an error: %s", err) + } + + expected := map[string]interface{}{ + "foo": "bar", + "bar": "baz", + } + if !reflect.DeepEqual(result, expected) { + t.Errorf("bad: %#v", result) + } +} + +func TestInvalidType(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vstring": 42, + } + + var result Basic + err := Decode(input, &result) + if err == nil { + t.Fatal("error should exist") + } + + derr, ok := err.(*Error) + if !ok { + t.Fatalf("error should be kind of Error, instead: %#v", err) + } + + if derr.Errors[0] != "'Vstring' expected type 'string', got unconvertible type 'int'" { + t.Errorf("got unexpected error: %s", err) + } + + inputNegIntUint := map[string]interface{}{ + "vuint": -42, + } + + err = Decode(inputNegIntUint, &result) + if err == nil { + t.Fatal("error should exist") + } + + derr, ok = err.(*Error) + if !ok { + t.Fatalf("error should be kind of Error, instead: %#v", err) + } + + if derr.Errors[0] != "cannot parse 'Vuint', -42 overflows uint" { + t.Errorf("got unexpected error: %s", err) + } + + inputNegFloatUint := map[string]interface{}{ + "vuint": -42.0, + } + + err = Decode(inputNegFloatUint, &result) + if err == nil { + t.Fatal("error should exist") + } + + derr, ok = err.(*Error) + if !ok { + t.Fatalf("error should be kind of Error, instead: %#v", err) + } + + if derr.Errors[0] != "cannot parse 'Vuint', -42.000000 overflows uint" { + t.Errorf("got unexpected error: %s", err) + } +} + +func TestMetadata(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vfoo": "foo", + "vbar": map[string]interface{}{ + "vstring": "foo", + "Vuint": 42, + "foo": "bar", + }, + "bar": "nil", + } + + var md Metadata + var result Nested + config := &DecoderConfig{ + Metadata: &md, + Result: &result, + } + + decoder, err := NewDecoder(config) + if err != nil { + t.Fatalf("err: %s", err) + } + + err = decoder.Decode(input) + if err != nil { + t.Fatalf("err: %s", err.Error()) + } + + expectedKeys := []string{"Vbar", "Vbar.Vstring", "Vbar.Vuint", "Vfoo"} + sort.Strings(md.Keys) + if !reflect.DeepEqual(md.Keys, expectedKeys) { + t.Fatalf("bad keys: %#v", md.Keys) + } + + expectedUnused := []string{"Vbar.foo", "bar"} + if !reflect.DeepEqual(md.Unused, expectedUnused) { + t.Fatalf("bad unused: %#v", md.Unused) + } +} + +func TestMetadata_Embedded(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "vstring": "foo", + "vunique": "bar", + } + + var md Metadata + var result EmbeddedSquash + config := &DecoderConfig{ + Metadata: &md, + Result: &result, + } + + decoder, err := NewDecoder(config) + if err != nil { + t.Fatalf("err: %s", err) + } + + err = decoder.Decode(input) + if err != nil { + t.Fatalf("err: %s", err.Error()) + } + + expectedKeys := []string{"Vstring", "Vunique"} + + sort.Strings(md.Keys) + if !reflect.DeepEqual(md.Keys, expectedKeys) { + t.Fatalf("bad keys: %#v", md.Keys) + } + + expectedUnused := []string{} + if !reflect.DeepEqual(md.Unused, expectedUnused) { + t.Fatalf("bad unused: %#v", md.Unused) + } +} + +func TestNonPtrValue(t *testing.T) { + t.Parallel() + + err := Decode(map[string]interface{}{}, Basic{}) + if err == nil { + t.Fatal("error should exist") + } + + if err.Error() != "result must be a pointer" { + t.Errorf("got unexpected error: %s", err) + } +} + +func TestTagged(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "foo": "bar", + "bar": "value", + } + + var result Tagged + err := Decode(input, &result) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if result.Value != "bar" { + t.Errorf("value should be 'bar', got: %#v", result.Value) + } + + if result.Extra != "value" { + t.Errorf("extra should be 'value', got: %#v", result.Extra) + } +} + +func TestWeakDecode(t *testing.T) { + t.Parallel() + + input := map[string]interface{}{ + "foo": "4", + "bar": "value", + } + + var result struct { + Foo int + Bar string + } + + if err := WeakDecode(input, &result); err != nil { + t.Fatalf("err: %s", err) + } + if result.Foo != 4 { + t.Fatalf("bad: %#v", result) + } + if result.Bar != "value" { + t.Fatalf("bad: %#v", result) + } +} + +func testSliceInput(t *testing.T, input map[string]interface{}, expected *Slice) { + var result Slice + err := Decode(input, &result) + if err != nil { + t.Fatalf("got error: %s", err) + } + + if result.Vfoo != expected.Vfoo { + t.Errorf("Vfoo expected '%s', got '%s'", expected.Vfoo, result.Vfoo) + } + + if result.Vbar == nil { + t.Fatalf("Vbar a slice, got '%#v'", result.Vbar) + } + + if len(result.Vbar) != len(expected.Vbar) { + t.Errorf("Vbar length should be %d, got %d", len(expected.Vbar), len(result.Vbar)) + } + + for i, v := range result.Vbar { + if v != expected.Vbar[i] { + t.Errorf( + "Vbar[%d] should be '%#v', got '%#v'", + i, expected.Vbar[i], v) + } + } +}