vendor: github.com/compose-spec/compose-go v1.14.0

https: //github.com/compose-spec/compose-go/compare/v1.13.4...v1.14.0
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
pull/1866/head
CrazyMax 2 years ago
parent 7cef021a8a
commit 9a125afba0
No known key found for this signature in database
GPG Key ID: 3248E46B6BB8C7F7

@ -5,7 +5,7 @@ go 1.20
require ( require (
github.com/Masterminds/semver/v3 v3.2.0 github.com/Masterminds/semver/v3 v3.2.0
github.com/aws/aws-sdk-go-v2/config v1.18.16 github.com/aws/aws-sdk-go-v2/config v1.18.16
github.com/compose-spec/compose-go v1.13.4 github.com/compose-spec/compose-go v1.14.0
github.com/containerd/console v1.0.3 github.com/containerd/console v1.0.3
github.com/containerd/containerd v1.7.1 github.com/containerd/containerd v1.7.1
github.com/containerd/continuity v0.4.1 github.com/containerd/continuity v0.4.1
@ -38,7 +38,7 @@ require (
github.com/zclconf/go-cty v1.10.0 github.com/zclconf/go-cty v1.10.0
go.opentelemetry.io/otel v1.14.0 go.opentelemetry.io/otel v1.14.0
go.opentelemetry.io/otel/trace v1.14.0 go.opentelemetry.io/otel/trace v1.14.0
golang.org/x/sync v0.1.0 golang.org/x/sync v0.2.0
golang.org/x/term v0.6.0 golang.org/x/term v0.6.0
google.golang.org/grpc v1.53.0 google.golang.org/grpc v1.53.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1

@ -122,8 +122,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
github.com/compose-spec/compose-go v1.13.4 h1:O6xAsPqaY1s9KXteiO7wRCDTJLahv1XP/z/eUO9EfbI= github.com/compose-spec/compose-go v1.14.0 h1:/+tQxBEPIrfsi87Qh7/VjMzcJN3BRNER/RO71ku+u6E=
github.com/compose-spec/compose-go v1.13.4/go.mod h1:rsiZ8uaOHJYJemDBzTe9UBpaq5ZFVEOO4TxM2G3SJxk= github.com/compose-spec/compose-go v1.14.0/go.mod h1:m0o4G6MQDHjjz9rY7No9FpnNi+9sKic262rzrwuCqic=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
@ -641,8 +641,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

@ -255,9 +255,8 @@ func WithDotEnv(o *ProjectOptions) error {
return err return err
} }
for k, v := range envMap { for k, v := range envMap {
if _, set := o.Environment[k]; !set {
o.Environment[k] = v o.Environment[k] = v
if osVal, ok := os.LookupEnv(k); ok {
o.Environment[k] = osVal
} }
} }
return nil return nil
@ -304,15 +303,12 @@ func GetEnvFromFile(currentEnv map[string]string, workingDir string, filenames [
} }
env, err := dotenv.ParseWithLookup(bytes.NewReader(b), func(k string) (string, bool) { env, err := dotenv.ParseWithLookup(bytes.NewReader(b), func(k string) (string, bool) {
v, ok := envMap[k] v, ok := currentEnv[k]
if ok { if ok {
return v, true return v, true
} }
v, ok = currentEnv[k] v, ok = envMap[k]
if !ok { return v, ok
return "", false
}
return v, true
}) })
if err != nil { if err != nil {
return envMap, errors.Wrapf(err, "failed to read %s", dotEnvFile) return envMap, errors.Wrapf(err, "failed to read %s", dotEnvFile)
@ -461,8 +457,9 @@ func withNamePrecedenceLoad(absWorkingDir string, options *ProjectOptions) func(
func withConvertWindowsPaths(options *ProjectOptions) func(*loader.Options) { func withConvertWindowsPaths(options *ProjectOptions) func(*loader.Options) {
return func(o *loader.Options) { return func(o *loader.Options) {
if o.ResolvePaths {
o.ConvertWindowsPaths = utils.StringToBool(options.Environment["COMPOSE_CONVERT_WINDOWS_PATHS"]) o.ConvertWindowsPaths = utils.StringToBool(options.Environment["COMPOSE_CONVERT_WINDOWS_PATHS"])
o.ResolvePaths = true }
} }
} }

@ -162,10 +162,11 @@ func readFile(filename string, lookupFn LookupFn) (map[string]string, error) {
func expandVariables(value string, envMap map[string]string, lookupFn LookupFn) (string, error) { func expandVariables(value string, envMap map[string]string, lookupFn LookupFn) (string, error) {
retVal, err := template.Substitute(value, func(k string) (string, bool) { retVal, err := template.Substitute(value, func(k string) (string, bool) {
if v, ok := envMap[k]; ok { if v, ok := lookupFn(k); ok {
return v, ok return v, true
} }
return lookupFn(k) v, ok := envMap[k]
return v, ok
}) })
if err != nil { if err != nil {
return value, err return value, err

@ -18,9 +18,9 @@ package interpolation
import ( import (
"os" "os"
"strings"
"github.com/compose-spec/compose-go/template" "github.com/compose-spec/compose-go/template"
"github.com/compose-spec/compose-go/tree"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -29,7 +29,7 @@ type Options struct {
// LookupValue from a key // LookupValue from a key
LookupValue LookupValue LookupValue LookupValue
// TypeCastMapping maps key paths to functions to cast to a type // TypeCastMapping maps key paths to functions to cast to a type
TypeCastMapping map[Path]Cast TypeCastMapping map[tree.Path]Cast
// Substitution function to use // Substitution function to use
Substitute func(string, template.Mapping) (string, error) Substitute func(string, template.Mapping) (string, error)
} }
@ -49,7 +49,7 @@ func Interpolate(config map[string]interface{}, opts Options) (map[string]interf
opts.LookupValue = os.LookupEnv opts.LookupValue = os.LookupEnv
} }
if opts.TypeCastMapping == nil { if opts.TypeCastMapping == nil {
opts.TypeCastMapping = make(map[Path]Cast) opts.TypeCastMapping = make(map[tree.Path]Cast)
} }
if opts.Substitute == nil { if opts.Substitute == nil {
opts.Substitute = template.Substitute opts.Substitute = template.Substitute
@ -58,7 +58,7 @@ func Interpolate(config map[string]interface{}, opts Options) (map[string]interf
out := map[string]interface{}{} out := map[string]interface{}{}
for key, value := range config { for key, value := range config {
interpolatedValue, err := recursiveInterpolate(value, NewPath(key), opts) interpolatedValue, err := recursiveInterpolate(value, tree.NewPath(key), opts)
if err != nil { if err != nil {
return out, err return out, err
} }
@ -68,7 +68,7 @@ func Interpolate(config map[string]interface{}, opts Options) (map[string]interf
return out, nil return out, nil
} }
func recursiveInterpolate(value interface{}, path Path, opts Options) (interface{}, error) { func recursiveInterpolate(value interface{}, path tree.Path, opts Options) (interface{}, error) {
switch value := value.(type) { switch value := value.(type) {
case string: case string:
newValue, err := opts.Substitute(value, template.Mapping(opts.LookupValue)) newValue, err := opts.Substitute(value, template.Mapping(opts.LookupValue))
@ -96,7 +96,7 @@ func recursiveInterpolate(value interface{}, path Path, opts Options) (interface
case []interface{}: case []interface{}:
out := make([]interface{}, len(value)) out := make([]interface{}, len(value))
for i, elem := range value { for i, elem := range value {
interpolatedElem, err := recursiveInterpolate(elem, path.Next(PathMatchList), opts) interpolatedElem, err := recursiveInterpolate(elem, path.Next(tree.PathMatchList), opts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -109,7 +109,7 @@ func recursiveInterpolate(value interface{}, path Path, opts Options) (interface
} }
} }
func newPathError(path Path, err error) error { func newPathError(path tree.Path, err error) error {
switch err := err.(type) { switch err := err.(type) {
case nil: case nil:
return nil return nil
@ -122,54 +122,9 @@ func newPathError(path Path, err error) error {
} }
} }
const pathSeparator = "." func (o Options) getCasterForPath(path tree.Path) (Cast, bool) {
// PathMatchAll is a token used as part of a Path to match any key at that level
// in the nested structure
const PathMatchAll = "*"
// PathMatchList is a token used as part of a Path to match items in a list
const PathMatchList = "[]"
// Path is a dotted path of keys to a value in a nested mapping structure. A *
// section in a path will match any key in the mapping structure.
type Path string
// NewPath returns a new Path
func NewPath(items ...string) Path {
return Path(strings.Join(items, pathSeparator))
}
// Next returns a new path by append part to the current path
func (p Path) Next(part string) Path {
return Path(string(p) + pathSeparator + part)
}
func (p Path) parts() []string {
return strings.Split(string(p), pathSeparator)
}
func (p Path) matches(pattern Path) bool {
patternParts := pattern.parts()
parts := p.parts()
if len(patternParts) != len(parts) {
return false
}
for index, part := range parts {
switch patternParts[index] {
case PathMatchAll, part:
continue
default:
return false
}
}
return true
}
func (o Options) getCasterForPath(path Path) (Cast, bool) {
for pattern, caster := range o.TypeCastMapping { for pattern, caster := range o.TypeCastMapping {
if path.matches(pattern) { if path.Matches(pattern) {
return caster, true return caster, true
} }
} }

@ -8,6 +8,8 @@ services:
RUN echo "hello" > /world.txt RUN echo "hello" > /world.txt
foo: foo:
annotations:
- com.example.foo=bar
build: build:
context: ./dir context: ./dir
dockerfile: Dockerfile dockerfile: Dockerfile

@ -21,12 +21,13 @@ import (
"strings" "strings"
interp "github.com/compose-spec/compose-go/interpolation" interp "github.com/compose-spec/compose-go/interpolation"
"github.com/compose-spec/compose-go/tree"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var interpolateTypeCastMapping = map[interp.Path]interp.Cast{ var interpolateTypeCastMapping = map[tree.Path]interp.Cast{
servicePath("configs", interp.PathMatchList, "mode"): toInt, servicePath("configs", tree.PathMatchList, "mode"): toInt,
servicePath("cpu_count"): toInt64, servicePath("cpu_count"): toInt64,
servicePath("cpu_percent"): toFloat, servicePath("cpu_percent"): toFloat,
servicePath("cpu_period"): toInt64, servicePath("cpu_period"): toInt64,
@ -52,36 +53,36 @@ var interpolateTypeCastMapping = map[interp.Path]interp.Cast{
servicePath("oom_kill_disable"): toBoolean, servicePath("oom_kill_disable"): toBoolean,
servicePath("oom_score_adj"): toInt64, servicePath("oom_score_adj"): toInt64,
servicePath("pids_limit"): toInt64, servicePath("pids_limit"): toInt64,
servicePath("ports", interp.PathMatchList, "target"): toInt, servicePath("ports", tree.PathMatchList, "target"): toInt,
servicePath("privileged"): toBoolean, servicePath("privileged"): toBoolean,
servicePath("read_only"): toBoolean, servicePath("read_only"): toBoolean,
servicePath("scale"): toInt, servicePath("scale"): toInt,
servicePath("secrets", interp.PathMatchList, "mode"): toInt, servicePath("secrets", tree.PathMatchList, "mode"): toInt,
servicePath("shm_size"): toUnitBytes, servicePath("shm_size"): toUnitBytes,
servicePath("stdin_open"): toBoolean, servicePath("stdin_open"): toBoolean,
servicePath("stop_grace_period"): toDuration, servicePath("stop_grace_period"): toDuration,
servicePath("tty"): toBoolean, servicePath("tty"): toBoolean,
servicePath("ulimits", interp.PathMatchAll): toInt, servicePath("ulimits", tree.PathMatchAll): toInt,
servicePath("ulimits", interp.PathMatchAll, "hard"): toInt, servicePath("ulimits", tree.PathMatchAll, "hard"): toInt,
servicePath("ulimits", interp.PathMatchAll, "soft"): toInt, servicePath("ulimits", tree.PathMatchAll, "soft"): toInt,
servicePath("volumes", interp.PathMatchList, "read_only"): toBoolean, servicePath("volumes", tree.PathMatchList, "read_only"): toBoolean,
servicePath("volumes", interp.PathMatchList, "volume", "nocopy"): toBoolean, servicePath("volumes", tree.PathMatchList, "volume", "nocopy"): toBoolean,
servicePath("volumes", interp.PathMatchList, "tmpfs", "size"): toUnitBytes, servicePath("volumes", tree.PathMatchList, "tmpfs", "size"): toUnitBytes,
iPath("networks", interp.PathMatchAll, "external"): toBoolean, iPath("networks", tree.PathMatchAll, "external"): toBoolean,
iPath("networks", interp.PathMatchAll, "internal"): toBoolean, iPath("networks", tree.PathMatchAll, "internal"): toBoolean,
iPath("networks", interp.PathMatchAll, "attachable"): toBoolean, iPath("networks", tree.PathMatchAll, "attachable"): toBoolean,
iPath("networks", interp.PathMatchAll, "enable_ipv6"): toBoolean, iPath("networks", tree.PathMatchAll, "enable_ipv6"): toBoolean,
iPath("volumes", interp.PathMatchAll, "external"): toBoolean, iPath("volumes", tree.PathMatchAll, "external"): toBoolean,
iPath("secrets", interp.PathMatchAll, "external"): toBoolean, iPath("secrets", tree.PathMatchAll, "external"): toBoolean,
iPath("configs", interp.PathMatchAll, "external"): toBoolean, iPath("configs", tree.PathMatchAll, "external"): toBoolean,
} }
func iPath(parts ...string) interp.Path { func iPath(parts ...string) tree.Path {
return interp.NewPath(parts...) return tree.NewPath(parts...)
} }
func servicePath(parts ...string) interp.Path { func servicePath(parts ...string) tree.Path {
return iPath(append([]string{"services", interp.PathMatchAll}, parts...)...) return iPath(append([]string{"services", tree.PathMatchAll}, parts...)...)
} }
func toInt(value string) (interface{}, error) { func toInt(value string) (interface{}, error) {

@ -134,27 +134,43 @@ func WithProfiles(profiles []string) func(*Options) {
// ParseYAML reads the bytes from a file, parses the bytes into a mapping // ParseYAML reads the bytes from a file, parses the bytes into a mapping
// structure, and returns it. // structure, and returns it.
func ParseYAML(source []byte) (map[string]interface{}, error) { func ParseYAML(source []byte) (map[string]interface{}, error) {
m, _, err := parseYAML(source)
return m, err
}
// PostProcessor is used to tweak compose model based on metadata extracted during yaml Unmarshal phase
// that hardly can be implemented using go-yaml and mapstructure
type PostProcessor interface {
yaml.Unmarshaler
// Apply changes to compose model based on recorder metadata
Apply(config *types.Config) error
}
func parseYAML(source []byte) (map[string]interface{}, PostProcessor, error) {
var cfg interface{} var cfg interface{}
if err := yaml.Unmarshal(source, &cfg); err != nil { processor := ResetProcessor{target: &cfg}
return nil, err
if err := yaml.Unmarshal(source, &processor); err != nil {
return nil, nil, err
} }
stringMap, ok := cfg.(map[string]interface{}) stringMap, ok := cfg.(map[string]interface{})
if ok { if ok {
converted, err := convertToStringKeysRecursive(stringMap, "") converted, err := convertToStringKeysRecursive(stringMap, "")
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
return converted.(map[string]interface{}), nil return converted.(map[string]interface{}), &processor, nil
} }
cfgMap, ok := cfg.(map[interface{}]interface{}) cfgMap, ok := cfg.(map[interface{}]interface{})
if !ok { if !ok {
return nil, errors.Errorf("Top-level object must be a mapping") return nil, nil, errors.Errorf("Top-level object must be a mapping")
} }
converted, err := convertToStringKeysRecursive(cfgMap, "") converted, err := convertToStringKeysRecursive(cfgMap, "")
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
return converted.(map[string]interface{}), nil return converted.(map[string]interface{}), &processor, nil
} }
// Load reads a ConfigDetails and returns a fully loaded configuration // Load reads a ConfigDetails and returns a fully loaded configuration
@ -180,8 +196,9 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
return nil, err return nil, err
} }
var configs []*types.Config var model *types.Config
for i, file := range configDetails.ConfigFiles { for i, file := range configDetails.ConfigFiles {
var postProcessor PostProcessor
configDict := file.Config configDict := file.Config
if configDict == nil { if configDict == nil {
if len(file.Content) == 0 { if len(file.Content) == 0 {
@ -191,13 +208,14 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
} }
file.Content = content file.Content = content
} }
dict, err := parseConfig(file.Content, opts) dict, p, err := parseConfig(file.Content, opts)
if err != nil { if err != nil {
return nil, fmt.Errorf("parsing %s: %w", file.Filename, err) return nil, fmt.Errorf("parsing %s: %w", file.Filename, err)
} }
configDict = dict configDict = dict
file.Config = dict file.Config = dict
configDetails.ConfigFiles[i] = file configDetails.ConfigFiles[i] = file
postProcessor = p
} }
if !opts.SkipValidation { if !opts.SkipValidation {
@ -212,13 +230,23 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
if err != nil { if err != nil {
return nil, err return nil, err
} }
configs = append(configs, cfg)
}
model, err := merge(configs) if i == 0 {
model = cfg
continue
}
merged, err := merge([]*types.Config{model, cfg})
if err != nil { if err != nil {
return nil, err return nil, err
} }
if postProcessor != nil {
err = postProcessor.Apply(merged)
if err != nil {
return nil, err
}
}
model = merged
}
for _, s := range model.Services { for _, s := range model.Services {
var newEnvFiles types.StringList var newEnvFiles types.StringList
@ -266,8 +294,8 @@ func Load(configDetails types.ConfigDetails, options ...func(*Options)) (*types.
func InvalidProjectNameErr(v string) error { func InvalidProjectNameErr(v string) error {
return fmt.Errorf( return fmt.Errorf(
"%q is not a valid project name: it must contain only "+ "invalid project name %q: must consist only of lowercase alphanumeric characters, hyphens, and underscores as well as start with a letter or number",
"characters from [a-z0-9_-] and start with [a-z0-9]", v, v,
) )
} }
@ -343,15 +371,16 @@ func NormalizeProjectName(s string) string {
return strings.TrimLeft(s, "_-") return strings.TrimLeft(s, "_-")
} }
func parseConfig(b []byte, opts *Options) (map[string]interface{}, error) { func parseConfig(b []byte, opts *Options) (map[string]interface{}, PostProcessor, error) {
yml, err := ParseYAML(b) yml, postProcessor, err := parseYAML(b)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
if !opts.SkipInterpolation { if !opts.SkipInterpolation {
return interp.Interpolate(yml, *opts.Interpolate) interpolated, err := interp.Interpolate(yml, *opts.Interpolate)
return interpolated, postProcessor, err
} }
return yml, err return yml, postProcessor, err
} }
const extensions = "#extensions" // Using # prefix, we prevent risk to conflict with an actual yaml key const extensions = "#extensions" // Using # prefix, we prevent risk to conflict with an actual yaml key
@ -441,6 +470,7 @@ func Transform(source interface{}, target interface{}, additionalTransformers ..
createTransformHook(additionalTransformers...), createTransformHook(additionalTransformers...),
mapstructure.StringToTimeDurationHookFunc()), mapstructure.StringToTimeDurationHookFunc()),
Result: target, Result: target,
TagName: "yaml",
Metadata: &data, Metadata: &data,
} }
decoder, err := mapstructure.NewDecoder(config) decoder, err := mapstructure.NewDecoder(config)
@ -626,7 +656,7 @@ func loadServiceWithExtends(filename, name string, servicesDict map[string]inter
return nil, err return nil, err
} }
baseFile, err := parseConfig(b, opts) baseFile, _, err := parseConfig(b, opts)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -155,6 +155,8 @@ func Normalize(project *types.Project, resolvePaths bool) error {
return err return err
} }
inferImplicitDependencies(&s)
project.Services[i] = s project.Services[i] = s
} }
@ -171,6 +173,61 @@ func Normalize(project *types.Project, resolvePaths bool) error {
return nil return nil
} }
// IsServiceDependency check the relation set by ref refers to a service
func IsServiceDependency(ref string) (string, bool) {
if strings.HasPrefix(
ref,
types.ServicePrefix,
) {
return ref[len(types.ServicePrefix):], true
}
return "", false
}
func inferImplicitDependencies(service *types.ServiceConfig) {
var dependencies []string
maybeReferences := []string{
service.NetworkMode,
service.Ipc,
service.Pid,
service.Uts,
service.Cgroup,
}
for _, ref := range maybeReferences {
if dep, ok := IsServiceDependency(ref); ok {
dependencies = append(dependencies, dep)
}
}
for _, vol := range service.VolumesFrom {
spec := strings.Split(vol, ":")
if len(spec) == 0 {
continue
}
if spec[0] == "container" {
continue
}
dependencies = append(dependencies, spec[0])
}
for _, link := range service.Links {
dependencies = append(dependencies, strings.Split(link, ":")[0])
}
if len(dependencies) > 0 && service.DependsOn == nil {
service.DependsOn = make(types.DependsOnConfig)
}
for _, d := range dependencies {
if _, ok := service.DependsOn[d]; !ok {
service.DependsOn[d] = types.ServiceDependency{
Condition: types.ServiceConditionStarted,
}
}
}
}
// setIfMissing adds a ServiceDependency for service if not already defined // setIfMissing adds a ServiceDependency for service if not already defined
func setIfMissing(d types.DependsOnConfig, service string, dep types.ServiceDependency) types.DependsOnConfig { func setIfMissing(d types.DependsOnConfig, service string, dep types.ServiceDependency) types.DependsOnConfig {
if d == nil { if d == nil {

@ -0,0 +1,159 @@
/*
Copyright 2020 The Compose Specification Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package loader
import (
"fmt"
"reflect"
"strconv"
"strings"
"github.com/compose-spec/compose-go/tree"
"github.com/compose-spec/compose-go/types"
"gopkg.in/yaml.v3"
)
type ResetProcessor struct {
target interface{}
paths []tree.Path
}
// UnmarshalYAML implement yaml.Unmarshaler
func (p *ResetProcessor) UnmarshalYAML(value *yaml.Node) error {
resolved, err := p.resolveReset(value, tree.NewPath())
if err != nil {
return err
}
return resolved.Decode(p.target)
}
// resolveReset detects `!reset` tag being set on yaml nodes and record position in the yaml tree
func (p *ResetProcessor) resolveReset(node *yaml.Node, path tree.Path) (*yaml.Node, error) {
if node.Tag == "!reset" {
p.paths = append(p.paths, path)
}
switch node.Kind {
case yaml.SequenceNode:
var err error
for idx, v := range node.Content {
next := path.Next(strconv.Itoa(idx))
node.Content[idx], err = p.resolveReset(v, next)
if err != nil {
return nil, err
}
}
case yaml.MappingNode:
var err error
var key string
for idx, v := range node.Content {
if idx%2 == 0 {
key = v.Value
} else {
node.Content[idx], err = p.resolveReset(v, path.Next(key))
if err != nil {
return nil, err
}
}
}
}
return node, nil
}
// Apply finds the go attributes matching recorded paths and reset them to zero value
func (p *ResetProcessor) Apply(target *types.Config) error {
return p.applyNullOverrides(reflect.ValueOf(target), tree.NewPath())
}
// applyNullOverrides set val to Zero if it matches any of the recorded paths
func (p *ResetProcessor) applyNullOverrides(val reflect.Value, path tree.Path) error {
val = reflect.Indirect(val)
if !val.IsValid() {
return nil
}
typ := val.Type()
switch {
case path == "services":
// Project.Services is a slice in compose-go, but a mapping in yaml
for i := 0; i < val.Len(); i++ {
service := val.Index(i)
name := service.FieldByName("Name")
next := path.Next(name.String())
err := p.applyNullOverrides(service, next)
if err != nil {
return err
}
}
case typ.Kind() == reflect.Map:
iter := val.MapRange()
KEYS:
for iter.Next() {
k := iter.Key()
next := path.Next(k.String())
for _, pattern := range p.paths {
if next.Matches(pattern) {
val.SetMapIndex(k, reflect.Value{})
continue KEYS
}
}
return p.applyNullOverrides(iter.Value(), next)
}
case typ.Kind() == reflect.Slice:
ITER:
for i := 0; i < val.Len(); i++ {
next := path.Next(fmt.Sprintf("[%d]", i))
for _, pattern := range p.paths {
if next.Matches(pattern) {
continue ITER
}
}
// TODO(ndeloof) support removal from sequence
return p.applyNullOverrides(val.Index(i), next)
}
case typ.Kind() == reflect.Struct:
FIELDS:
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
name := field.Name
attr := strings.ToLower(name)
tag := field.Tag.Get("yaml")
tag = strings.Split(tag, ",")[0]
if tag != "" && tag != "-" {
attr = tag
}
next := path.Next(attr)
f := val.Field(i)
for _, pattern := range p.paths {
if next.Matches(pattern) {
f := f
if !f.CanSet() {
return fmt.Errorf("can't override attribute %s", name)
}
// f.SetZero() requires go 1.20
f.Set(reflect.Zero(f.Type()))
continue FIELDS
}
}
err := p.applyNullOverrides(f, next)
if err != nil {
return err
}
}
}
return nil
}

@ -176,5 +176,8 @@ func isFilePath(source string) bool {
} }
first, nextIndex := utf8.DecodeRuneInString(source) first, nextIndex := utf8.DecodeRuneInString(source)
if len(source) <= nextIndex {
return false
}
return isWindowsDrive([]rune{first}, rune(source[nextIndex])) return isWindowsDrive([]rune{first}, rune(source[nextIndex]))
} }

@ -83,6 +83,7 @@
"properties": { "properties": {
"deploy": {"$ref": "#/definitions/deployment"}, "deploy": {"$ref": "#/definitions/deployment"},
"annotations": {"$ref": "#/definitions/list_or_dict"},
"build": { "build": {
"oneOf": [ "oneOf": [
{"type": "string"}, {"type": "string"},

@ -28,7 +28,7 @@ import (
var delimiter = "\\$" var delimiter = "\\$"
var substitutionNamed = "[_a-z][_a-z0-9]*" var substitutionNamed = "[_a-z][_a-z0-9]*"
var substitutionBraced = "[_a-z][_a-z0-9]*(?::?[-+?](.*}|[^}]*))?" var substitutionBraced = "[_a-z][_a-z0-9]*(?::?[-+?](.*))?"
var patternString = fmt.Sprintf( var patternString = fmt.Sprintf(
"%s(?i:(?P<escaped>%s)|(?P<named>%s)|{(?:(?P<braced>%s)}|(?P<invalid>)))", "%s(?i:(?P<escaped>%s)|(?P<named>%s)|{(?:(?P<braced>%s)}|(?P<invalid>)))",

@ -0,0 +1,67 @@
/*
Copyright 2020 The Compose Specification Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package tree
import "strings"
const pathSeparator = "."
// PathMatchAll is a token used as part of a Path to match any key at that level
// in the nested structure
const PathMatchAll = "*"
// PathMatchList is a token used as part of a Path to match items in a list
const PathMatchList = "[]"
// Path is a dotted path of keys to a value in a nested mapping structure. A *
// section in a path will match any key in the mapping structure.
type Path string
// NewPath returns a new Path
func NewPath(items ...string) Path {
return Path(strings.Join(items, pathSeparator))
}
// Next returns a new path by append part to the current path
func (p Path) Next(part string) Path {
if p == "" {
return Path(part)
}
return Path(string(p) + pathSeparator + part)
}
func (p Path) Parts() []string {
return strings.Split(string(p), pathSeparator)
}
func (p Path) Matches(pattern Path) bool {
patternParts := pattern.Parts()
parts := p.Parts()
if len(patternParts) != len(parts) {
return false
}
for index, part := range parts {
switch patternParts[index] {
case PathMatchAll, part:
continue
default:
return false
}
}
return true
}

@ -36,12 +36,12 @@ import (
type Project struct { type Project struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"` Name string `yaml:"name,omitempty" json:"name,omitempty"`
WorkingDir string `yaml:"-" json:"-"` WorkingDir string `yaml:"-" json:"-"`
Services Services `json:"services"` Services Services `yaml:"services" json:"services"`
Networks Networks `yaml:",omitempty" json:"networks,omitempty"` Networks Networks `yaml:"networks,omitempty" json:"networks,omitempty"`
Volumes Volumes `yaml:",omitempty" json:"volumes,omitempty"` Volumes Volumes `yaml:"volumes,omitempty" json:"volumes,omitempty"`
Secrets Secrets `yaml:",omitempty" json:"secrets,omitempty"` Secrets Secrets `yaml:"secrets,omitempty" json:"secrets,omitempty"`
Configs Configs `yaml:",omitempty" json:"configs,omitempty"` Configs Configs `yaml:"configs,omitempty" json:"configs,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` // https://github.com/golang/go/issues/6213 Extensions Extensions `yaml:"#extensions,inline" json:"-"` // https://github.com/golang/go/issues/6213
ComposeFiles []string `yaml:"-" json:"-"` ComposeFiles []string `yaml:"-" json:"-"`
Environment Mapping `yaml:"-" json:"-"` Environment Mapping `yaml:"-" json:"-"`
@ -396,6 +396,11 @@ func (p *Project) ForServices(names []string, options ...DependencyOption) error
var enabled Services var enabled Services
for _, s := range p.Services { for _, s := range p.Services {
if _, ok := set[s.Name]; ok { if _, ok := set[s.Name]; ok {
for _, option := range options {
if option == IgnoreDependencies {
s.DependsOn = nil
}
}
enabled = append(enabled, s) enabled = append(enabled, s)
} else { } else {
p.DisabledServices = append(p.DisabledServices, s) p.DisabledServices = append(p.DisabledServices, s)

@ -86,42 +86,43 @@ func (s Services) MarshalJSON() ([]byte, error) {
// ServiceConfig is the configuration of one service // ServiceConfig is the configuration of one service
type ServiceConfig struct { type ServiceConfig struct {
Name string `yaml:"-" json:"-"` Name string `yaml:"-" json:"-"`
Profiles []string `mapstructure:"profiles" yaml:"profiles,omitempty" json:"profiles,omitempty"` Profiles []string `yaml:"profiles,omitempty" json:"profiles,omitempty"`
Build *BuildConfig `yaml:",omitempty" json:"build,omitempty"` Annotations Mapping `yaml:"annotations,omitempty" json:"annotations,omitempty"`
BlkioConfig *BlkioConfig `mapstructure:"blkio_config" yaml:",omitempty" json:"blkio_config,omitempty"` Build *BuildConfig `yaml:"build,omitempty" json:"build,omitempty"`
CapAdd []string `mapstructure:"cap_add" yaml:"cap_add,omitempty" json:"cap_add,omitempty"` BlkioConfig *BlkioConfig `yaml:"blkio_config,omitempty" json:"blkio_config,omitempty"`
CapDrop []string `mapstructure:"cap_drop" yaml:"cap_drop,omitempty" json:"cap_drop,omitempty"` CapAdd []string `yaml:"cap_add,omitempty" json:"cap_add,omitempty"`
CgroupParent string `mapstructure:"cgroup_parent" yaml:"cgroup_parent,omitempty" json:"cgroup_parent,omitempty"` CapDrop []string `yaml:"cap_drop,omitempty" json:"cap_drop,omitempty"`
Cgroup string `mapstructure:"cgroup" yaml:"cgroup,omitempty" json:"cgroup,omitempty"` CgroupParent string `yaml:"cgroup_parent,omitempty" json:"cgroup_parent,omitempty"`
CPUCount int64 `mapstructure:"cpu_count" yaml:"cpu_count,omitempty" json:"cpu_count,omitempty"` Cgroup string `yaml:"cgroup,omitempty" json:"cgroup,omitempty"`
CPUPercent float32 `mapstructure:"cpu_percent" yaml:"cpu_percent,omitempty" json:"cpu_percent,omitempty"` CPUCount int64 `yaml:"cpu_count,omitempty" json:"cpu_count,omitempty"`
CPUPeriod int64 `mapstructure:"cpu_period" yaml:"cpu_period,omitempty" json:"cpu_period,omitempty"` CPUPercent float32 `yaml:"cpu_percent,omitempty" json:"cpu_percent,omitempty"`
CPUQuota int64 `mapstructure:"cpu_quota" yaml:"cpu_quota,omitempty" json:"cpu_quota,omitempty"` CPUPeriod int64 `yaml:"cpu_period,omitempty" json:"cpu_period,omitempty"`
CPURTPeriod int64 `mapstructure:"cpu_rt_period" yaml:"cpu_rt_period,omitempty" json:"cpu_rt_period,omitempty"` CPUQuota int64 `yaml:"cpu_quota,omitempty" json:"cpu_quota,omitempty"`
CPURTRuntime int64 `mapstructure:"cpu_rt_runtime" yaml:"cpu_rt_runtime,omitempty" json:"cpu_rt_runtime,omitempty"` CPURTPeriod int64 `yaml:"cpu_rt_period,omitempty" json:"cpu_rt_period,omitempty"`
CPUS float32 `mapstructure:"cpus" yaml:"cpus,omitempty" json:"cpus,omitempty"` CPURTRuntime int64 `yaml:"cpu_rt_runtime,omitempty" json:"cpu_rt_runtime,omitempty"`
CPUSet string `mapstructure:"cpuset" yaml:"cpuset,omitempty" json:"cpuset,omitempty"` CPUS float32 `yaml:"cpus,omitempty" json:"cpus,omitempty"`
CPUShares int64 `mapstructure:"cpu_shares" yaml:"cpu_shares,omitempty" json:"cpu_shares,omitempty"` CPUSet string `yaml:"cpuset,omitempty" json:"cpuset,omitempty"`
CPUShares int64 `yaml:"cpu_shares,omitempty" json:"cpu_shares,omitempty"`
// Command for the service containers. // Command for the service containers.
// If set, overrides COMMAND from the image. // If set, overrides COMMAND from the image.
// //
// Set to `[]` or an empty string to clear the command from the image. // Set to `[]` or an empty string to clear the command from the image.
Command ShellCommand `yaml:",omitempty" json:"command"` // NOTE: we can NOT omitempty for JSON! see ShellCommand type for details. Command ShellCommand `yaml:"command,omitempty" json:"command"` // NOTE: we can NOT omitempty for JSON! see ShellCommand type for details.
Configs []ServiceConfigObjConfig `yaml:",omitempty" json:"configs,omitempty"` Configs []ServiceConfigObjConfig `yaml:"configs,omitempty" json:"configs,omitempty"`
ContainerName string `mapstructure:"container_name" yaml:"container_name,omitempty" json:"container_name,omitempty"` ContainerName string `yaml:"container_name,omitempty" json:"container_name,omitempty"`
CredentialSpec *CredentialSpecConfig `mapstructure:"credential_spec" yaml:"credential_spec,omitempty" json:"credential_spec,omitempty"` CredentialSpec *CredentialSpecConfig `yaml:"credential_spec,omitempty" json:"credential_spec,omitempty"`
DependsOn DependsOnConfig `mapstructure:"depends_on" yaml:"depends_on,omitempty" json:"depends_on,omitempty"` DependsOn DependsOnConfig `yaml:"depends_on,omitempty" json:"depends_on,omitempty"`
Deploy *DeployConfig `yaml:",omitempty" json:"deploy,omitempty"` Deploy *DeployConfig `yaml:"deploy,omitempty" json:"deploy,omitempty"`
DeviceCgroupRules []string `mapstructure:"device_cgroup_rules" yaml:"device_cgroup_rules,omitempty" json:"device_cgroup_rules,omitempty"` DeviceCgroupRules []string `yaml:"device_cgroup_rules,omitempty" json:"device_cgroup_rules,omitempty"`
Devices []string `yaml:",omitempty" json:"devices,omitempty"` Devices []string `yaml:"devices,omitempty" json:"devices,omitempty"`
DNS StringList `yaml:",omitempty" json:"dns,omitempty"` DNS StringList `yaml:"dns,omitempty" json:"dns,omitempty"`
DNSOpts []string `mapstructure:"dns_opt" yaml:"dns_opt,omitempty" json:"dns_opt,omitempty"` DNSOpts []string `yaml:"dns_opt,omitempty" json:"dns_opt,omitempty"`
DNSSearch StringList `mapstructure:"dns_search" yaml:"dns_search,omitempty" json:"dns_search,omitempty"` DNSSearch StringList `yaml:"dns_search,omitempty" json:"dns_search,omitempty"`
Dockerfile string `yaml:"dockerfile,omitempty" json:"dockerfile,omitempty"` Dockerfile string `yaml:"dockerfile,omitempty" json:"dockerfile,omitempty"`
DomainName string `mapstructure:"domainname" yaml:"domainname,omitempty" json:"domainname,omitempty"` DomainName string `yaml:"domainname,omitempty" json:"domainname,omitempty"`
// Entrypoint for the service containers. // Entrypoint for the service containers.
// If set, overrides ENTRYPOINT from the image. // If set, overrides ENTRYPOINT from the image.
@ -129,64 +130,80 @@ type ServiceConfig struct {
// Set to `[]` or an empty string to clear the entrypoint from the image. // Set to `[]` or an empty string to clear the entrypoint from the image.
Entrypoint ShellCommand `yaml:"entrypoint,omitempty" json:"entrypoint"` // NOTE: we can NOT omitempty for JSON! see ShellCommand type for details. Entrypoint ShellCommand `yaml:"entrypoint,omitempty" json:"entrypoint"` // NOTE: we can NOT omitempty for JSON! see ShellCommand type for details.
Environment MappingWithEquals `yaml:",omitempty" json:"environment,omitempty"` Environment MappingWithEquals `yaml:"environment,omitempty" json:"environment,omitempty"`
EnvFile StringList `mapstructure:"env_file" yaml:"env_file,omitempty" json:"env_file,omitempty"` EnvFile StringList `yaml:"env_file,omitempty" json:"env_file,omitempty"`
Expose StringOrNumberList `yaml:",omitempty" json:"expose,omitempty"` Expose StringOrNumberList `yaml:"expose,omitempty" json:"expose,omitempty"`
Extends *ExtendsConfig `yaml:"extends,omitempty" json:"extends,omitempty"` Extends *ExtendsConfig `yaml:"extends,omitempty" json:"extends,omitempty"`
ExternalLinks []string `mapstructure:"external_links" yaml:"external_links,omitempty" json:"external_links,omitempty"` ExternalLinks []string `yaml:"external_links,omitempty" json:"external_links,omitempty"`
ExtraHosts HostsList `mapstructure:"extra_hosts" yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"` ExtraHosts HostsList `yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
GroupAdd []string `mapstructure:"group_add" yaml:"group_add,omitempty" json:"group_add,omitempty"` GroupAdd []string `yaml:"group_add,omitempty" json:"group_add,omitempty"`
Hostname string `yaml:",omitempty" json:"hostname,omitempty"` Hostname string `yaml:"hostname,omitempty" json:"hostname,omitempty"`
HealthCheck *HealthCheckConfig `yaml:",omitempty" json:"healthcheck,omitempty"` HealthCheck *HealthCheckConfig `yaml:"healthcheck,omitempty" json:"healthcheck,omitempty"`
Image string `yaml:",omitempty" json:"image,omitempty"` Image string `yaml:"image,omitempty" json:"image,omitempty"`
Init *bool `yaml:",omitempty" json:"init,omitempty"` Init *bool `yaml:"init,omitempty" json:"init,omitempty"`
Ipc string `yaml:",omitempty" json:"ipc,omitempty"` Ipc string `yaml:"ipc,omitempty" json:"ipc,omitempty"`
Isolation string `mapstructure:"isolation" yaml:"isolation,omitempty" json:"isolation,omitempty"` Isolation string `yaml:"isolation,omitempty" json:"isolation,omitempty"`
Labels Labels `yaml:",omitempty" json:"labels,omitempty"` Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"`
CustomLabels Labels `yaml:"-" json:"-"` CustomLabels Labels `yaml:"-" json:"-"`
Links []string `yaml:",omitempty" json:"links,omitempty"` Links []string `yaml:"links,omitempty" json:"links,omitempty"`
Logging *LoggingConfig `yaml:",omitempty" json:"logging,omitempty"` Logging *LoggingConfig `yaml:"logging,omitempty" json:"logging,omitempty"`
LogDriver string `mapstructure:"log_driver" yaml:"log_driver,omitempty" json:"log_driver,omitempty"` LogDriver string `yaml:"log_driver,omitempty" json:"log_driver,omitempty"`
LogOpt map[string]string `mapstructure:"log_opt" yaml:"log_opt,omitempty" json:"log_opt,omitempty"` LogOpt map[string]string `yaml:"log_opt,omitempty" json:"log_opt,omitempty"`
MemLimit UnitBytes `mapstructure:"mem_limit" yaml:"mem_limit,omitempty" json:"mem_limit,omitempty"` MemLimit UnitBytes `yaml:"mem_limit,omitempty" json:"mem_limit,omitempty"`
MemReservation UnitBytes `mapstructure:"mem_reservation" yaml:"mem_reservation,omitempty" json:"mem_reservation,omitempty"` MemReservation UnitBytes `yaml:"mem_reservation,omitempty" json:"mem_reservation,omitempty"`
MemSwapLimit UnitBytes `mapstructure:"memswap_limit" yaml:"memswap_limit,omitempty" json:"memswap_limit,omitempty"` MemSwapLimit UnitBytes `yaml:"memswap_limit,omitempty" json:"memswap_limit,omitempty"`
MemSwappiness UnitBytes `mapstructure:"mem_swappiness" yaml:"mem_swappiness,omitempty" json:"mem_swappiness,omitempty"` MemSwappiness UnitBytes `yaml:"mem_swappiness,omitempty" json:"mem_swappiness,omitempty"`
MacAddress string `mapstructure:"mac_address" yaml:"mac_address,omitempty" json:"mac_address,omitempty"` MacAddress string `yaml:"mac_address,omitempty" json:"mac_address,omitempty"`
Net string `yaml:"net,omitempty" json:"net,omitempty"` Net string `yaml:"net,omitempty" json:"net,omitempty"`
NetworkMode string `mapstructure:"network_mode" yaml:"network_mode,omitempty" json:"network_mode,omitempty"` NetworkMode string `yaml:"network_mode,omitempty" json:"network_mode,omitempty"`
Networks map[string]*ServiceNetworkConfig `yaml:",omitempty" json:"networks,omitempty"` Networks map[string]*ServiceNetworkConfig `yaml:"networks,omitempty" json:"networks,omitempty"`
OomKillDisable bool `mapstructure:"oom_kill_disable" yaml:"oom_kill_disable,omitempty" json:"oom_kill_disable,omitempty"` OomKillDisable bool `yaml:"oom_kill_disable,omitempty" json:"oom_kill_disable,omitempty"`
OomScoreAdj int64 `mapstructure:"oom_score_adj" yaml:"oom_score_adj,omitempty" json:"oom_score_adj,omitempty"` OomScoreAdj int64 `yaml:"oom_score_adj,omitempty" json:"oom_score_adj,omitempty"`
Pid string `yaml:",omitempty" json:"pid,omitempty"` Pid string `yaml:"pid,omitempty" json:"pid,omitempty"`
PidsLimit int64 `mapstructure:"pids_limit" yaml:"pids_limit,omitempty" json:"pids_limit,omitempty"` PidsLimit int64 `yaml:"pids_limit,omitempty" json:"pids_limit,omitempty"`
Platform string `yaml:",omitempty" json:"platform,omitempty"` Platform string `yaml:"platform,omitempty" json:"platform,omitempty"`
Ports []ServicePortConfig `yaml:",omitempty" json:"ports,omitempty"` Ports []ServicePortConfig `yaml:"ports,omitempty" json:"ports,omitempty"`
Privileged bool `yaml:",omitempty" json:"privileged,omitempty"` Privileged bool `yaml:"privileged,omitempty" json:"privileged,omitempty"`
PullPolicy string `mapstructure:"pull_policy" yaml:"pull_policy,omitempty" json:"pull_policy,omitempty"` PullPolicy string `yaml:"pull_policy,omitempty" json:"pull_policy,omitempty"`
ReadOnly bool `mapstructure:"read_only" yaml:"read_only,omitempty" json:"read_only,omitempty"` ReadOnly bool `yaml:"read_only,omitempty" json:"read_only,omitempty"`
Restart string `yaml:",omitempty" json:"restart,omitempty"` Restart string `yaml:"restart,omitempty" json:"restart,omitempty"`
Runtime string `yaml:",omitempty" json:"runtime,omitempty"` Runtime string `yaml:"runtime,omitempty" json:"runtime,omitempty"`
Scale int `yaml:"-" json:"-"` Scale int `yaml:"scale,omitempty" json:"scale,omitempty"`
Secrets []ServiceSecretConfig `yaml:",omitempty" json:"secrets,omitempty"` Secrets []ServiceSecretConfig `yaml:"secrets,omitempty" json:"secrets,omitempty"`
SecurityOpt []string `mapstructure:"security_opt" yaml:"security_opt,omitempty" json:"security_opt,omitempty"` SecurityOpt []string `yaml:"security_opt,omitempty" json:"security_opt,omitempty"`
ShmSize UnitBytes `mapstructure:"shm_size" yaml:"shm_size,omitempty" json:"shm_size,omitempty"` ShmSize UnitBytes `yaml:"shm_size,omitempty" json:"shm_size,omitempty"`
StdinOpen bool `mapstructure:"stdin_open" yaml:"stdin_open,omitempty" json:"stdin_open,omitempty"` StdinOpen bool `yaml:"stdin_open,omitempty" json:"stdin_open,omitempty"`
StopGracePeriod *Duration `mapstructure:"stop_grace_period" yaml:"stop_grace_period,omitempty" json:"stop_grace_period,omitempty"` StopGracePeriod *Duration `yaml:"stop_grace_period,omitempty" json:"stop_grace_period,omitempty"`
StopSignal string `mapstructure:"stop_signal" yaml:"stop_signal,omitempty" json:"stop_signal,omitempty"` StopSignal string `yaml:"stop_signal,omitempty" json:"stop_signal,omitempty"`
Sysctls Mapping `yaml:",omitempty" json:"sysctls,omitempty"` Sysctls Mapping `yaml:"sysctls,omitempty" json:"sysctls,omitempty"`
Tmpfs StringList `yaml:",omitempty" json:"tmpfs,omitempty"` Tmpfs StringList `yaml:"tmpfs,omitempty" json:"tmpfs,omitempty"`
Tty bool `mapstructure:"tty" yaml:"tty,omitempty" json:"tty,omitempty"` Tty bool `yaml:"tty,omitempty" json:"tty,omitempty"`
Ulimits map[string]*UlimitsConfig `yaml:",omitempty" json:"ulimits,omitempty"` Ulimits map[string]*UlimitsConfig `yaml:"ulimits,omitempty" json:"ulimits,omitempty"`
User string `yaml:",omitempty" json:"user,omitempty"` User string `yaml:"user,omitempty" json:"user,omitempty"`
UserNSMode string `mapstructure:"userns_mode" yaml:"userns_mode,omitempty" json:"userns_mode,omitempty"` UserNSMode string `yaml:"userns_mode,omitempty" json:"userns_mode,omitempty"`
Uts string `yaml:"uts,omitempty" json:"uts,omitempty"` Uts string `yaml:"uts,omitempty" json:"uts,omitempty"`
VolumeDriver string `mapstructure:"volume_driver" yaml:"volume_driver,omitempty" json:"volume_driver,omitempty"` VolumeDriver string `yaml:"volume_driver,omitempty" json:"volume_driver,omitempty"`
Volumes []ServiceVolumeConfig `yaml:",omitempty" json:"volumes,omitempty"` Volumes []ServiceVolumeConfig `yaml:"volumes,omitempty" json:"volumes,omitempty"`
VolumesFrom []string `mapstructure:"volumes_from" yaml:"volumes_from,omitempty" json:"volumes_from,omitempty"` VolumesFrom []string `yaml:"volumes_from,omitempty" json:"volumes_from,omitempty"`
WorkingDir string `mapstructure:"working_dir" yaml:"working_dir,omitempty" json:"working_dir,omitempty"` WorkingDir string `yaml:"working_dir,omitempty" json:"working_dir,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
}
// MarshalYAML makes ServiceConfig implement yaml.Marshaller
func (s ServiceConfig) MarshalYAML() (interface{}, error) {
type t ServiceConfig
value := t(s)
value.Scale = 0 // deprecated, but default value "1" doesn't match omitempty
return value, nil
}
// MarshalJSON makes SSHKey implement json.Marshaller
func (s ServiceConfig) MarshalJSON() ([]byte, error) {
type t ServiceConfig
value := t(s)
value.Scale = 0 // deprecated, but default value "1" doesn't match omitempty
return json.Marshal(value)
} }
// NetworksByPriority return the service networks IDs sorted according to Priority // NetworksByPriority return the service networks IDs sorted according to Priority
@ -294,39 +311,39 @@ func (s set) toSlice() []string {
// BuildConfig is a type for build // BuildConfig is a type for build
type BuildConfig struct { type BuildConfig struct {
Context string `yaml:",omitempty" json:"context,omitempty"` Context string `yaml:"context,omitempty" json:"context,omitempty"`
Dockerfile string `yaml:",omitempty" json:"dockerfile,omitempty"` Dockerfile string `yaml:"dockerfile,omitempty" json:"dockerfile,omitempty"`
DockerfileInline string `mapstructure:"dockerfile_inline,omitempty" yaml:"dockerfile_inline,omitempty" json:"dockerfile_inline,omitempty"` DockerfileInline string `yaml:"dockerfile_inline,omitempty" json:"dockerfile_inline,omitempty"`
Args MappingWithEquals `yaml:",omitempty" json:"args,omitempty"` Args MappingWithEquals `yaml:"args,omitempty" json:"args,omitempty"`
SSH SSHConfig `yaml:"ssh,omitempty" json:"ssh,omitempty"` SSH SSHConfig `yaml:"ssh,omitempty" json:"ssh,omitempty"`
Labels Labels `yaml:",omitempty" json:"labels,omitempty"` Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"`
CacheFrom StringList `mapstructure:"cache_from" yaml:"cache_from,omitempty" json:"cache_from,omitempty"` CacheFrom StringList `yaml:"cache_from,omitempty" json:"cache_from,omitempty"`
CacheTo StringList `mapstructure:"cache_to" yaml:"cache_to,omitempty" json:"cache_to,omitempty"` CacheTo StringList `yaml:"cache_to,omitempty" json:"cache_to,omitempty"`
NoCache bool `mapstructure:"no_cache" yaml:"no_cache,omitempty" json:"no_cache,omitempty"` NoCache bool `yaml:"no_cache,omitempty" json:"no_cache,omitempty"`
AdditionalContexts Mapping `mapstructure:"additional_contexts" yaml:"additional_contexts,omitempty" json:"additional_contexts,omitempty"` AdditionalContexts Mapping `yaml:"additional_contexts,omitempty" json:"additional_contexts,omitempty"`
Pull bool `mapstructure:"pull" yaml:"pull,omitempty" json:"pull,omitempty"` Pull bool `yaml:"pull,omitempty" json:"pull,omitempty"`
ExtraHosts HostsList `mapstructure:"extra_hosts" yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"` ExtraHosts HostsList `yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
Isolation string `yaml:",omitempty" json:"isolation,omitempty"` Isolation string `yaml:"isolation,omitempty" json:"isolation,omitempty"`
Network string `yaml:",omitempty" json:"network,omitempty"` Network string `yaml:"network,omitempty" json:"network,omitempty"`
Target string `yaml:",omitempty" json:"target,omitempty"` Target string `yaml:"target,omitempty" json:"target,omitempty"`
Secrets []ServiceSecretConfig `yaml:",omitempty" json:"secrets,omitempty"` Secrets []ServiceSecretConfig `yaml:"secrets,omitempty" json:"secrets,omitempty"`
Tags StringList `mapstructure:"tags" yaml:"tags,omitempty" json:"tags,omitempty"` Tags StringList `yaml:"tags,omitempty" json:"tags,omitempty"`
Platforms StringList `mapstructure:"platforms" yaml:"platforms,omitempty" json:"platforms,omitempty"` Platforms StringList `yaml:"platforms,omitempty" json:"platforms,omitempty"`
Privileged bool `yaml:",omitempty" json:"privileged,omitempty"` Privileged bool `yaml:"privileged,omitempty" json:"privileged,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// BlkioConfig define blkio config // BlkioConfig define blkio config
type BlkioConfig struct { type BlkioConfig struct {
Weight uint16 `yaml:",omitempty" json:"weight,omitempty"` Weight uint16 `yaml:"weight,omitempty" json:"weight,omitempty"`
WeightDevice []WeightDevice `mapstructure:"weight_device" yaml:",omitempty" json:"weight_device,omitempty"` WeightDevice []WeightDevice `yaml:"weight_device,omitempty" json:"weight_device,omitempty"`
DeviceReadBps []ThrottleDevice `mapstructure:"device_read_bps" yaml:",omitempty" json:"device_read_bps,omitempty"` DeviceReadBps []ThrottleDevice `yaml:"device_read_bps,omitempty" json:"device_read_bps,omitempty"`
DeviceReadIOps []ThrottleDevice `mapstructure:"device_read_iops" yaml:",omitempty" json:"device_read_iops,omitempty"` DeviceReadIOps []ThrottleDevice `yaml:"device_read_iops,omitempty" json:"device_read_iops,omitempty"`
DeviceWriteBps []ThrottleDevice `mapstructure:"device_write_bps" yaml:",omitempty" json:"device_write_bps,omitempty"` DeviceWriteBps []ThrottleDevice `yaml:"device_write_bps,omitempty" json:"device_write_bps,omitempty"`
DeviceWriteIOps []ThrottleDevice `mapstructure:"device_write_iops" yaml:",omitempty" json:"device_write_iops,omitempty"` DeviceWriteIOps []ThrottleDevice `yaml:"device_write_iops,omitempty" json:"device_write_iops,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// WeightDevice is a structure that holds device:weight pair // WeightDevice is a structure that holds device:weight pair
@ -334,7 +351,7 @@ type WeightDevice struct {
Path string Path string
Weight uint16 Weight uint16
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// ThrottleDevice is a structure that holds device:rate_per_second pair // ThrottleDevice is a structure that holds device:rate_per_second pair
@ -342,7 +359,7 @@ type ThrottleDevice struct {
Path string Path string
Rate UnitBytes Rate UnitBytes
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// ShellCommand is a string or list of string args. // ShellCommand is a string or list of string args.
@ -562,37 +579,37 @@ func (h HostsList) MarshalJSON() ([]byte, error) {
// LoggingConfig the logging configuration for a service // LoggingConfig the logging configuration for a service
type LoggingConfig struct { type LoggingConfig struct {
Driver string `yaml:",omitempty" json:"driver,omitempty"` Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
Options map[string]string `yaml:",omitempty" json:"options,omitempty"` Options map[string]string `yaml:"options,omitempty" json:"options,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// DeployConfig the deployment configuration for a service // DeployConfig the deployment configuration for a service
type DeployConfig struct { type DeployConfig struct {
Mode string `yaml:",omitempty" json:"mode,omitempty"` Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
Replicas *uint64 `yaml:",omitempty" json:"replicas,omitempty"` Replicas *uint64 `yaml:"replicas,omitempty" json:"replicas,omitempty"`
Labels Labels `yaml:",omitempty" json:"labels,omitempty"` Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"`
UpdateConfig *UpdateConfig `mapstructure:"update_config" yaml:"update_config,omitempty" json:"update_config,omitempty"` UpdateConfig *UpdateConfig `yaml:"update_config,omitempty" json:"update_config,omitempty"`
RollbackConfig *UpdateConfig `mapstructure:"rollback_config" yaml:"rollback_config,omitempty" json:"rollback_config,omitempty"` RollbackConfig *UpdateConfig `yaml:"rollback_config,omitempty" json:"rollback_config,omitempty"`
Resources Resources `yaml:",omitempty" json:"resources,omitempty"` Resources Resources `yaml:"resources,omitempty" json:"resources,omitempty"`
RestartPolicy *RestartPolicy `mapstructure:"restart_policy" yaml:"restart_policy,omitempty" json:"restart_policy,omitempty"` RestartPolicy *RestartPolicy `yaml:"restart_policy,omitempty" json:"restart_policy,omitempty"`
Placement Placement `yaml:",omitempty" json:"placement,omitempty"` Placement Placement `yaml:"placement,omitempty" json:"placement,omitempty"`
EndpointMode string `mapstructure:"endpoint_mode" yaml:"endpoint_mode,omitempty" json:"endpoint_mode,omitempty"` EndpointMode string `yaml:"endpoint_mode,omitempty" json:"endpoint_mode,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// HealthCheckConfig the healthcheck configuration for a service // HealthCheckConfig the healthcheck configuration for a service
type HealthCheckConfig struct { type HealthCheckConfig struct {
Test HealthCheckTest `yaml:",omitempty" json:"test,omitempty"` Test HealthCheckTest `yaml:"test,omitempty" json:"test,omitempty"`
Timeout *Duration `yaml:",omitempty" json:"timeout,omitempty"` Timeout *Duration `yaml:"timeout,omitempty" json:"timeout,omitempty"`
Interval *Duration `yaml:",omitempty" json:"interval,omitempty"` Interval *Duration `yaml:"interval,omitempty" json:"interval,omitempty"`
Retries *uint64 `yaml:",omitempty" json:"retries,omitempty"` Retries *uint64 `yaml:"retries,omitempty" json:"retries,omitempty"`
StartPeriod *Duration `mapstructure:"start_period" yaml:"start_period,omitempty" json:"start_period,omitempty"` StartPeriod *Duration `yaml:"start_period,omitempty" json:"start_period,omitempty"`
Disable bool `yaml:",omitempty" json:"disable,omitempty"` Disable bool `yaml:"disable,omitempty" json:"disable,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// HealthCheckTest is the command run to test the health of a service // HealthCheckTest is the command run to test the health of a service
@ -600,49 +617,49 @@ type HealthCheckTest []string
// UpdateConfig the service update configuration // UpdateConfig the service update configuration
type UpdateConfig struct { type UpdateConfig struct {
Parallelism *uint64 `yaml:",omitempty" json:"parallelism,omitempty"` Parallelism *uint64 `yaml:"parallelism,omitempty" json:"parallelism,omitempty"`
Delay Duration `yaml:",omitempty" json:"delay,omitempty"` Delay Duration `yaml:"delay,omitempty" json:"delay,omitempty"`
FailureAction string `mapstructure:"failure_action" yaml:"failure_action,omitempty" json:"failure_action,omitempty"` FailureAction string `yaml:"failure_action,omitempty" json:"failure_action,omitempty"`
Monitor Duration `yaml:",omitempty" json:"monitor,omitempty"` Monitor Duration `yaml:"monitor,omitempty" json:"monitor,omitempty"`
MaxFailureRatio float32 `mapstructure:"max_failure_ratio" yaml:"max_failure_ratio,omitempty" json:"max_failure_ratio,omitempty"` MaxFailureRatio float32 `yaml:"max_failure_ratio,omitempty" json:"max_failure_ratio,omitempty"`
Order string `yaml:",omitempty" json:"order,omitempty"` Order string `yaml:"order,omitempty" json:"order,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// Resources the resource limits and reservations // Resources the resource limits and reservations
type Resources struct { type Resources struct {
Limits *Resource `yaml:",omitempty" json:"limits,omitempty"` Limits *Resource `yaml:"limits,omitempty" json:"limits,omitempty"`
Reservations *Resource `yaml:",omitempty" json:"reservations,omitempty"` Reservations *Resource `yaml:"reservations,omitempty" json:"reservations,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// Resource is a resource to be limited or reserved // Resource is a resource to be limited or reserved
type Resource struct { type Resource struct {
// TODO: types to convert from units and ratios // TODO: types to convert from units and ratios
NanoCPUs string `mapstructure:"cpus" yaml:"cpus,omitempty" json:"cpus,omitempty"` NanoCPUs string `yaml:"cpus,omitempty" json:"cpus,omitempty"`
MemoryBytes UnitBytes `mapstructure:"memory" yaml:"memory,omitempty" json:"memory,omitempty"` MemoryBytes UnitBytes `yaml:"memory,omitempty" json:"memory,omitempty"`
PIds int64 `mapstructure:"pids" yaml:"pids,omitempty" json:"pids,omitempty"` Pids int64 `yaml:"pids,omitempty" json:"pids,omitempty"`
Devices []DeviceRequest `mapstructure:"devices" yaml:"devices,omitempty" json:"devices,omitempty"` Devices []DeviceRequest `yaml:"devices,omitempty" json:"devices,omitempty"`
GenericResources []GenericResource `mapstructure:"generic_resources" yaml:"generic_resources,omitempty" json:"generic_resources,omitempty"` GenericResources []GenericResource `yaml:"generic_resources,omitempty" json:"generic_resources,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
type DeviceRequest struct { type DeviceRequest struct {
Capabilities []string `mapstructure:"capabilities" yaml:"capabilities,omitempty" json:"capabilities,omitempty"` Capabilities []string `yaml:"capabilities,omitempty" json:"capabilities,omitempty"`
Driver string `mapstructure:"driver" yaml:"driver,omitempty" json:"driver,omitempty"` Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
Count int64 `mapstructure:"count" yaml:"count,omitempty" json:"count,omitempty"` Count int64 `yaml:"count,omitempty" json:"count,omitempty"`
IDs []string `mapstructure:"device_ids" yaml:"device_ids,omitempty" json:"device_ids,omitempty"` IDs []string `yaml:"device_ids,omitempty" json:"device_ids,omitempty"`
} }
// GenericResource represents a "user defined" resource which can // GenericResource represents a "user defined" resource which can
// only be an integer (e.g: SSD=3) for a service // only be an integer (e.g: SSD=3) for a service
type GenericResource struct { type GenericResource struct {
DiscreteResourceSpec *DiscreteGenericResource `mapstructure:"discrete_resource_spec" yaml:"discrete_resource_spec,omitempty" json:"discrete_resource_spec,omitempty"` DiscreteResourceSpec *DiscreteGenericResource `yaml:"discrete_resource_spec,omitempty" json:"discrete_resource_spec,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// DiscreteGenericResource represents a "user defined" resource which is defined // DiscreteGenericResource represents a "user defined" resource which is defined
@ -653,7 +670,7 @@ type DiscreteGenericResource struct {
Kind string `json:"kind"` Kind string `json:"kind"`
Value int64 `json:"value"` Value int64 `json:"value"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// UnitBytes is the bytes type // UnitBytes is the bytes type
@ -671,50 +688,50 @@ func (u UnitBytes) MarshalJSON() ([]byte, error) {
// RestartPolicy the service restart policy // RestartPolicy the service restart policy
type RestartPolicy struct { type RestartPolicy struct {
Condition string `yaml:",omitempty" json:"condition,omitempty"` Condition string `yaml:"condition,omitempty" json:"condition,omitempty"`
Delay *Duration `yaml:",omitempty" json:"delay,omitempty"` Delay *Duration `yaml:"delay,omitempty" json:"delay,omitempty"`
MaxAttempts *uint64 `mapstructure:"max_attempts" yaml:"max_attempts,omitempty" json:"max_attempts,omitempty"` MaxAttempts *uint64 `yaml:"max_attempts,omitempty" json:"max_attempts,omitempty"`
Window *Duration `yaml:",omitempty" json:"window,omitempty"` Window *Duration `yaml:"window,omitempty" json:"window,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// Placement constraints for the service // Placement constraints for the service
type Placement struct { type Placement struct {
Constraints []string `yaml:",omitempty" json:"constraints,omitempty"` Constraints []string `yaml:"constraints,omitempty" json:"constraints,omitempty"`
Preferences []PlacementPreferences `yaml:",omitempty" json:"preferences,omitempty"` Preferences []PlacementPreferences `yaml:"preferences,omitempty" json:"preferences,omitempty"`
MaxReplicas uint64 `mapstructure:"max_replicas_per_node" yaml:"max_replicas_per_node,omitempty" json:"max_replicas_per_node,omitempty"` MaxReplicas uint64 `yaml:"max_replicas_per_node,omitempty" json:"max_replicas_per_node,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// PlacementPreferences is the preferences for a service placement // PlacementPreferences is the preferences for a service placement
type PlacementPreferences struct { type PlacementPreferences struct {
Spread string `yaml:",omitempty" json:"spread,omitempty"` Spread string `yaml:"spread,omitempty" json:"spread,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// ServiceNetworkConfig is the network configuration for a service // ServiceNetworkConfig is the network configuration for a service
type ServiceNetworkConfig struct { type ServiceNetworkConfig struct {
Priority int `yaml:",omitempty" json:"priority,omitempty"` Priority int `yaml:"priority,omitempty" json:"priority,omitempty"`
Aliases []string `yaml:",omitempty" json:"aliases,omitempty"` Aliases []string `yaml:"aliases,omitempty" json:"aliases,omitempty"`
Ipv4Address string `mapstructure:"ipv4_address" yaml:"ipv4_address,omitempty" json:"ipv4_address,omitempty"` Ipv4Address string `yaml:"ipv4_address,omitempty" json:"ipv4_address,omitempty"`
Ipv6Address string `mapstructure:"ipv6_address" yaml:"ipv6_address,omitempty" json:"ipv6_address,omitempty"` Ipv6Address string `yaml:"ipv6_address,omitempty" json:"ipv6_address,omitempty"`
LinkLocalIPs []string `mapstructure:"link_local_ips" yaml:"link_local_ips,omitempty" json:"link_local_ips,omitempty"` LinkLocalIPs []string `yaml:"link_local_ips,omitempty" json:"link_local_ips,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// ServicePortConfig is the port configuration for a service // ServicePortConfig is the port configuration for a service
type ServicePortConfig struct { type ServicePortConfig struct {
Mode string `yaml:",omitempty" json:"mode,omitempty"` Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
HostIP string `mapstructure:"host_ip" yaml:"host_ip,omitempty" json:"host_ip,omitempty"` HostIP string `yaml:"host_ip,omitempty" json:"host_ip,omitempty"`
Target uint32 `yaml:",omitempty" json:"target,omitempty"` Target uint32 `yaml:"target,omitempty" json:"target,omitempty"`
Published string `yaml:",omitempty" json:"published,omitempty"` Published string `yaml:"published,omitempty" json:"published,omitempty"`
Protocol string `yaml:",omitempty" json:"protocol,omitempty"` Protocol string `yaml:"protocol,omitempty" json:"protocol,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// ParsePortConfig parse short syntax for service port configuration // ParsePortConfig parse short syntax for service port configuration
@ -758,16 +775,16 @@ func convertPortToPortConfig(port nat.Port, portBindings map[nat.Port][]nat.Port
// ServiceVolumeConfig are references to a volume used by a service // ServiceVolumeConfig are references to a volume used by a service
type ServiceVolumeConfig struct { type ServiceVolumeConfig struct {
Type string `yaml:",omitempty" json:"type,omitempty"` Type string `yaml:"type,omitempty" json:"type,omitempty"`
Source string `yaml:",omitempty" json:"source,omitempty"` Source string `yaml:"source,omitempty" json:"source,omitempty"`
Target string `yaml:",omitempty" json:"target,omitempty"` Target string `yaml:"target,omitempty" json:"target,omitempty"`
ReadOnly bool `mapstructure:"read_only" yaml:"read_only,omitempty" json:"read_only,omitempty"` ReadOnly bool `yaml:"read_only,omitempty" json:"read_only,omitempty"`
Consistency string `yaml:",omitempty" json:"consistency,omitempty"` Consistency string `yaml:"consistency,omitempty" json:"consistency,omitempty"`
Bind *ServiceVolumeBind `yaml:",omitempty" json:"bind,omitempty"` Bind *ServiceVolumeBind `yaml:"bind,omitempty" json:"bind,omitempty"`
Volume *ServiceVolumeVolume `yaml:",omitempty" json:"volume,omitempty"` Volume *ServiceVolumeVolume `yaml:"volume,omitempty" json:"volume,omitempty"`
Tmpfs *ServiceVolumeTmpfs `yaml:",omitempty" json:"tmpfs,omitempty"` Tmpfs *ServiceVolumeTmpfs `yaml:"tmpfs,omitempty" json:"tmpfs,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// String render ServiceVolumeConfig as a volume string, one can parse back using loader.ParseVolume // String render ServiceVolumeConfig as a volume string, one can parse back using loader.ParseVolume
@ -807,11 +824,11 @@ const (
// ServiceVolumeBind are options for a service volume of type bind // ServiceVolumeBind are options for a service volume of type bind
type ServiceVolumeBind struct { type ServiceVolumeBind struct {
SELinux string `mapstructure:"selinux" yaml:",omitempty" json:"selinux,omitempty"` SELinux string `yaml:"selinux,omitempty" json:"selinux,omitempty"`
Propagation string `yaml:",omitempty" json:"propagation,omitempty"` Propagation string `yaml:"propagation,omitempty" json:"propagation,omitempty"`
CreateHostPath bool `mapstructure:"create_host_path" yaml:"create_host_path,omitempty" json:"create_host_path,omitempty"` CreateHostPath bool `yaml:"create_host_path,omitempty" json:"create_host_path,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// SELinux represents the SELinux re-labeling options. // SELinux represents the SELinux re-labeling options.
@ -840,29 +857,29 @@ const (
// ServiceVolumeVolume are options for a service volume of type volume // ServiceVolumeVolume are options for a service volume of type volume
type ServiceVolumeVolume struct { type ServiceVolumeVolume struct {
NoCopy bool `mapstructure:"nocopy" yaml:"nocopy,omitempty" json:"nocopy,omitempty"` NoCopy bool `yaml:"nocopy,omitempty" json:"nocopy,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// ServiceVolumeTmpfs are options for a service volume of type tmpfs // ServiceVolumeTmpfs are options for a service volume of type tmpfs
type ServiceVolumeTmpfs struct { type ServiceVolumeTmpfs struct {
Size UnitBytes `yaml:",omitempty" json:"size,omitempty"` Size UnitBytes `yaml:"size,omitempty" json:"size,omitempty"`
Mode uint32 `yaml:",omitempty" json:"mode,omitempty"` Mode uint32 `yaml:"mode,omitempty" json:"mode,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// FileReferenceConfig for a reference to a swarm file object // FileReferenceConfig for a reference to a swarm file object
type FileReferenceConfig struct { type FileReferenceConfig struct {
Source string `yaml:",omitempty" json:"source,omitempty"` Source string `yaml:"source,omitempty" json:"source,omitempty"`
Target string `yaml:",omitempty" json:"target,omitempty"` Target string `yaml:"target,omitempty" json:"target,omitempty"`
UID string `yaml:",omitempty" json:"uid,omitempty"` UID string `yaml:"uid,omitempty" json:"uid,omitempty"`
GID string `yaml:",omitempty" json:"gid,omitempty"` GID string `yaml:"gid,omitempty" json:"gid,omitempty"`
Mode *uint32 `yaml:",omitempty" json:"mode,omitempty"` Mode *uint32 `yaml:"mode,omitempty" json:"mode,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// ServiceConfigObjConfig is the config obj configuration for a service // ServiceConfigObjConfig is the config obj configuration for a service
@ -873,11 +890,11 @@ type ServiceSecretConfig FileReferenceConfig
// UlimitsConfig the ulimit configuration // UlimitsConfig the ulimit configuration
type UlimitsConfig struct { type UlimitsConfig struct {
Single int `yaml:",omitempty" json:"single,omitempty"` Single int `yaml:"single,omitempty" json:"single,omitempty"`
Soft int `yaml:",omitempty" json:"soft,omitempty"` Soft int `yaml:"soft,omitempty" json:"soft,omitempty"`
Hard int `yaml:",omitempty" json:"hard,omitempty"` Hard int `yaml:"hard,omitempty" json:"hard,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// MarshalYAML makes UlimitsConfig implement yaml.Marshaller // MarshalYAML makes UlimitsConfig implement yaml.Marshaller
@ -905,51 +922,51 @@ func (u *UlimitsConfig) MarshalJSON() ([]byte, error) {
// NetworkConfig for a network // NetworkConfig for a network
type NetworkConfig struct { type NetworkConfig struct {
Name string `yaml:",omitempty" json:"name,omitempty"` Name string `yaml:"name,omitempty" json:"name,omitempty"`
Driver string `yaml:",omitempty" json:"driver,omitempty"` Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
DriverOpts map[string]string `mapstructure:"driver_opts" yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"` DriverOpts map[string]string `yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
Ipam IPAMConfig `yaml:",omitempty" json:"ipam,omitempty"` Ipam IPAMConfig `yaml:"ipam,omitempty" json:"ipam,omitempty"`
External External `yaml:",omitempty" json:"external,omitempty"` External External `yaml:"external,omitempty" json:"external,omitempty"`
Internal bool `yaml:",omitempty" json:"internal,omitempty"` Internal bool `yaml:"internal,omitempty" json:"internal,omitempty"`
Attachable bool `yaml:",omitempty" json:"attachable,omitempty"` Attachable bool `yaml:"attachable,omitempty" json:"attachable,omitempty"`
Labels Labels `yaml:",omitempty" json:"labels,omitempty"` Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"`
EnableIPv6 bool `mapstructure:"enable_ipv6" yaml:"enable_ipv6,omitempty" json:"enable_ipv6,omitempty"` EnableIPv6 bool `yaml:"enable_ipv6,omitempty" json:"enable_ipv6,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// IPAMConfig for a network // IPAMConfig for a network
type IPAMConfig struct { type IPAMConfig struct {
Driver string `yaml:",omitempty" json:"driver,omitempty"` Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
Config []*IPAMPool `yaml:",omitempty" json:"config,omitempty"` Config []*IPAMPool `yaml:"config,omitempty" json:"config,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// IPAMPool for a network // IPAMPool for a network
type IPAMPool struct { type IPAMPool struct {
Subnet string `yaml:",omitempty" json:"subnet,omitempty"` Subnet string `yaml:"subnet,omitempty" json:"subnet,omitempty"`
Gateway string `yaml:",omitempty" json:"gateway,omitempty"` Gateway string `yaml:"gateway,omitempty" json:"gateway,omitempty"`
IPRange string `mapstructure:"ip_range" yaml:"ip_range,omitempty" json:"ip_range,omitempty"` IPRange string `yaml:"ip_range,omitempty" json:"ip_range,omitempty"`
AuxiliaryAddresses map[string]string `mapstructure:"aux_addresses" yaml:"aux_addresses,omitempty" json:"aux_addresses,omitempty"` AuxiliaryAddresses map[string]string `yaml:"aux_addresses,omitempty" json:"aux_addresses,omitempty"`
Extensions map[string]interface{} `yaml:",inline" json:"-"` Extensions map[string]interface{} `yaml:",inline" json:"-"`
} }
// VolumeConfig for a volume // VolumeConfig for a volume
type VolumeConfig struct { type VolumeConfig struct {
Name string `yaml:",omitempty" json:"name,omitempty"` Name string `yaml:"name,omitempty" json:"name,omitempty"`
Driver string `yaml:",omitempty" json:"driver,omitempty"` Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
DriverOpts map[string]string `mapstructure:"driver_opts" yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"` DriverOpts map[string]string `yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
External External `yaml:",omitempty" json:"external,omitempty"` External External `yaml:"external,omitempty" json:"external,omitempty"`
Labels Labels `yaml:",omitempty" json:"labels,omitempty"` Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// External identifies a Volume or Network as a reference to a resource that is // External identifies a Volume or Network as a reference to a resource that is
// not managed, and should already exist. // not managed, and should already exist.
// External.name is deprecated and replaced by Volume.name // External.name is deprecated and replaced by Volume.name
type External struct { type External struct {
Name string `yaml:",omitempty" json:"name,omitempty"` Name string `yaml:"name,omitempty" json:"name,omitempty"`
External bool `yaml:",omitempty" json:"external,omitempty"` External bool `yaml:"external,omitempty" json:"external,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// MarshalYAML makes External implement yaml.Marshaller // MarshalYAML makes External implement yaml.Marshaller
@ -970,23 +987,23 @@ func (e External) MarshalJSON() ([]byte, error) {
// CredentialSpecConfig for credential spec on Windows // CredentialSpecConfig for credential spec on Windows
type CredentialSpecConfig struct { type CredentialSpecConfig struct {
Config string `yaml:",omitempty" json:"config,omitempty"` // Config was added in API v1.40 Config string `yaml:"config,omitempty" json:"config,omitempty"` // Config was added in API v1.40
File string `yaml:",omitempty" json:"file,omitempty"` File string `yaml:"file,omitempty" json:"file,omitempty"`
Registry string `yaml:",omitempty" json:"registry,omitempty"` Registry string `yaml:"registry,omitempty" json:"registry,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
// FileObjectConfig is a config type for a file used by a service // FileObjectConfig is a config type for a file used by a service
type FileObjectConfig struct { type FileObjectConfig struct {
Name string `yaml:",omitempty" json:"name,omitempty"` Name string `yaml:"name,omitempty" json:"name,omitempty"`
File string `yaml:",omitempty" json:"file,omitempty"` File string `yaml:"file,omitempty" json:"file,omitempty"`
Environment string `yaml:",omitempty" json:"environment,omitempty"` Environment string `yaml:"environment,omitempty" json:"environment,omitempty"`
External External `yaml:",omitempty" json:"external,omitempty"` External External `yaml:"external,omitempty" json:"external,omitempty"`
Labels Labels `yaml:",omitempty" json:"labels,omitempty"` Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"`
Driver string `yaml:",omitempty" json:"driver,omitempty"` Driver string `yaml:"driver,omitempty" json:"driver,omitempty"`
DriverOpts map[string]string `mapstructure:"driver_opts" yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"` DriverOpts map[string]string `yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
TemplateDriver string `mapstructure:"template_driver" yaml:"template_driver,omitempty" json:"template_driver,omitempty"` TemplateDriver string `yaml:"template_driver,omitempty" json:"template_driver,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
const ( const (
@ -1003,14 +1020,14 @@ const (
type DependsOnConfig map[string]ServiceDependency type DependsOnConfig map[string]ServiceDependency
type ServiceDependency struct { type ServiceDependency struct {
Condition string `yaml:",omitempty" json:"condition,omitempty"` Condition string `yaml:"condition,omitempty" json:"condition,omitempty"`
Restart bool `yaml:",omitempty" json:"restart,omitempty"` Restart bool `yaml:"restart,omitempty" json:"restart,omitempty"`
Extensions Extensions `mapstructure:"#extensions" yaml:",inline" json:"-"` Extensions Extensions `yaml:"#extensions,inline" json:"-"`
} }
type ExtendsConfig struct { type ExtendsConfig struct {
File string `yaml:",omitempty" json:"file,omitempty"` File string `yaml:"file,omitempty" json:"file,omitempty"`
Service string `yaml:",omitempty" json:"service,omitempty"` Service string `yaml:"service,omitempty" json:"service,omitempty"`
} }
// SecretConfig for a secret // SecretConfig for a secret

@ -131,7 +131,7 @@ github.com/cenkalti/backoff/v4
github.com/cespare/xxhash/v2 github.com/cespare/xxhash/v2
# github.com/cloudflare/cfssl v0.0.0-20181213083726-b94e044bb51e # github.com/cloudflare/cfssl v0.0.0-20181213083726-b94e044bb51e
## explicit ## explicit
# github.com/compose-spec/compose-go v1.13.4 # github.com/compose-spec/compose-go v1.14.0
## explicit; go 1.19 ## explicit; go 1.19
github.com/compose-spec/compose-go/cli github.com/compose-spec/compose-go/cli
github.com/compose-spec/compose-go/consts github.com/compose-spec/compose-go/consts
@ -141,6 +141,7 @@ github.com/compose-spec/compose-go/interpolation
github.com/compose-spec/compose-go/loader github.com/compose-spec/compose-go/loader
github.com/compose-spec/compose-go/schema github.com/compose-spec/compose-go/schema
github.com/compose-spec/compose-go/template github.com/compose-spec/compose-go/template
github.com/compose-spec/compose-go/tree
github.com/compose-spec/compose-go/types github.com/compose-spec/compose-go/types
github.com/compose-spec/compose-go/utils github.com/compose-spec/compose-go/utils
# github.com/containerd/console v1.0.3 # github.com/containerd/console v1.0.3
@ -809,7 +810,7 @@ golang.org/x/net/trace
## explicit; go 1.17 ## explicit; go 1.17
golang.org/x/oauth2 golang.org/x/oauth2
golang.org/x/oauth2/internal golang.org/x/oauth2/internal
# golang.org/x/sync v0.1.0 # golang.org/x/sync v0.2.0
## explicit ## explicit
golang.org/x/sync/errgroup golang.org/x/sync/errgroup
golang.org/x/sync/semaphore golang.org/x/sync/semaphore

Loading…
Cancel
Save