mirror of https://github.com/docker/cli.git
Merge pull request #1326 from shin-/compose-json-annotations
Allow marshalling of Compose config to JSON
This commit is contained in:
commit
11ef349c58
|
@ -222,7 +222,7 @@ func fromComposeServiceConfig(s composeTypes.ServiceConfig) v1beta2.ServiceConfi
|
||||||
ReadOnly: s.ReadOnly,
|
ReadOnly: s.ReadOnly,
|
||||||
Secrets: fromComposeServiceSecrets(s.Secrets),
|
Secrets: fromComposeServiceSecrets(s.Secrets),
|
||||||
StdinOpen: s.StdinOpen,
|
StdinOpen: s.StdinOpen,
|
||||||
StopGracePeriod: s.StopGracePeriod,
|
StopGracePeriod: composetypes.ConvertDurationPtr(s.StopGracePeriod),
|
||||||
Tmpfs: s.Tmpfs,
|
Tmpfs: s.Tmpfs,
|
||||||
Tty: s.Tty,
|
Tty: s.Tty,
|
||||||
User: userID,
|
User: userID,
|
||||||
|
@ -285,8 +285,8 @@ func fromComposeHealthcheck(h *composeTypes.HealthCheckConfig) *v1beta2.HealthCh
|
||||||
}
|
}
|
||||||
return &v1beta2.HealthCheckConfig{
|
return &v1beta2.HealthCheckConfig{
|
||||||
Test: h.Test,
|
Test: h.Test,
|
||||||
Timeout: h.Timeout,
|
Timeout: composetypes.ConvertDurationPtr(h.Timeout),
|
||||||
Interval: h.Interval,
|
Interval: composetypes.ConvertDurationPtr(h.Interval),
|
||||||
Retries: h.Retries,
|
Retries: h.Retries,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWarnings(t *testing.T) {
|
func TestWarnings(t *testing.T) {
|
||||||
duration := 5 * time.Second
|
duration := composetypes.Duration(5 * time.Second)
|
||||||
attempts := uint64(3)
|
attempts := uint64(3)
|
||||||
config := &composetypes.Config{
|
config := &composetypes.Config{
|
||||||
Version: "3.4",
|
Version: "3.4",
|
||||||
|
@ -26,9 +26,9 @@ func TestWarnings(t *testing.T) {
|
||||||
DependsOn: []string{"ignored"},
|
DependsOn: []string{"ignored"},
|
||||||
Deploy: composetypes.DeployConfig{
|
Deploy: composetypes.DeployConfig{
|
||||||
UpdateConfig: &composetypes.UpdateConfig{
|
UpdateConfig: &composetypes.UpdateConfig{
|
||||||
Delay: 5 * time.Second,
|
Delay: composetypes.Duration(5 * time.Second),
|
||||||
FailureAction: "rollback",
|
FailureAction: "rollback",
|
||||||
Monitor: 10 * time.Second,
|
Monitor: composetypes.Duration(10 * time.Second),
|
||||||
MaxFailureRatio: 0.5,
|
MaxFailureRatio: 0.5,
|
||||||
},
|
},
|
||||||
RestartPolicy: &composetypes.RestartPolicy{
|
RestartPolicy: &composetypes.RestartPolicy{
|
||||||
|
|
|
@ -141,7 +141,7 @@ func Service(
|
||||||
Dir: service.WorkingDir,
|
Dir: service.WorkingDir,
|
||||||
User: service.User,
|
User: service.User,
|
||||||
Mounts: mounts,
|
Mounts: mounts,
|
||||||
StopGracePeriod: service.StopGracePeriod,
|
StopGracePeriod: composetypes.ConvertDurationPtr(service.StopGracePeriod),
|
||||||
StopSignal: service.StopSignal,
|
StopSignal: service.StopSignal,
|
||||||
TTY: service.Tty,
|
TTY: service.Tty,
|
||||||
OpenStdin: service.StdinOpen,
|
OpenStdin: service.StdinOpen,
|
||||||
|
@ -414,13 +414,13 @@ func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container
|
||||||
|
|
||||||
}
|
}
|
||||||
if healthcheck.Timeout != nil {
|
if healthcheck.Timeout != nil {
|
||||||
timeout = *healthcheck.Timeout
|
timeout = time.Duration(*healthcheck.Timeout)
|
||||||
}
|
}
|
||||||
if healthcheck.Interval != nil {
|
if healthcheck.Interval != nil {
|
||||||
interval = *healthcheck.Interval
|
interval = time.Duration(*healthcheck.Interval)
|
||||||
}
|
}
|
||||||
if healthcheck.StartPeriod != nil {
|
if healthcheck.StartPeriod != nil {
|
||||||
startPeriod = *healthcheck.StartPeriod
|
startPeriod = time.Duration(*healthcheck.StartPeriod)
|
||||||
}
|
}
|
||||||
if healthcheck.Retries != nil {
|
if healthcheck.Retries != nil {
|
||||||
retries = int(*healthcheck.Retries)
|
retries = int(*healthcheck.Retries)
|
||||||
|
@ -458,11 +458,12 @@ func convertRestartPolicy(restart string, source *composetypes.RestartPolicy) (*
|
||||||
return nil, errors.Errorf("unknown restart policy: %s", restart)
|
return nil, errors.Errorf("unknown restart policy: %s", restart)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &swarm.RestartPolicy{
|
return &swarm.RestartPolicy{
|
||||||
Condition: swarm.RestartPolicyCondition(source.Condition),
|
Condition: swarm.RestartPolicyCondition(source.Condition),
|
||||||
Delay: source.Delay,
|
Delay: composetypes.ConvertDurationPtr(source.Delay),
|
||||||
MaxAttempts: source.MaxAttempts,
|
MaxAttempts: source.MaxAttempts,
|
||||||
Window: source.Window,
|
Window: composetypes.ConvertDurationPtr(source.Window),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,9 +477,9 @@ func convertUpdateConfig(source *composetypes.UpdateConfig) *swarm.UpdateConfig
|
||||||
}
|
}
|
||||||
return &swarm.UpdateConfig{
|
return &swarm.UpdateConfig{
|
||||||
Parallelism: parallel,
|
Parallelism: parallel,
|
||||||
Delay: source.Delay,
|
Delay: time.Duration(source.Delay),
|
||||||
FailureAction: source.FailureAction,
|
FailureAction: source.FailureAction,
|
||||||
Monitor: source.Monitor,
|
Monitor: time.Duration(source.Monitor),
|
||||||
MaxFailureRatio: source.MaxFailureRatio,
|
MaxFailureRatio: source.MaxFailureRatio,
|
||||||
Order: source.Order,
|
Order: source.Order,
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,8 +124,8 @@ func TestConvertResourcesOnlyMemory(t *testing.T) {
|
||||||
|
|
||||||
func TestConvertHealthcheck(t *testing.T) {
|
func TestConvertHealthcheck(t *testing.T) {
|
||||||
retries := uint64(10)
|
retries := uint64(10)
|
||||||
timeout := 30 * time.Second
|
timeout := composetypes.Duration(30 * time.Second)
|
||||||
interval := 2 * time.Millisecond
|
interval := composetypes.Duration(2 * time.Millisecond)
|
||||||
source := &composetypes.HealthCheckConfig{
|
source := &composetypes.HealthCheckConfig{
|
||||||
Test: []string{"EXEC", "touch", "/foo"},
|
Test: []string{"EXEC", "touch", "/foo"},
|
||||||
Timeout: &timeout,
|
Timeout: &timeout,
|
||||||
|
@ -134,8 +134,8 @@ func TestConvertHealthcheck(t *testing.T) {
|
||||||
}
|
}
|
||||||
expected := &container.HealthConfig{
|
expected := &container.HealthConfig{
|
||||||
Test: source.Test,
|
Test: source.Test,
|
||||||
Timeout: timeout,
|
Timeout: time.Duration(timeout),
|
||||||
Interval: interval,
|
Interval: time.Duration(interval),
|
||||||
Retries: 10,
|
Retries: 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,17 +65,17 @@ func services(workingDir, homeDir string) []types.ServiceConfig {
|
||||||
Labels: map[string]string{"FOO": "BAR"},
|
Labels: map[string]string{"FOO": "BAR"},
|
||||||
RollbackConfig: &types.UpdateConfig{
|
RollbackConfig: &types.UpdateConfig{
|
||||||
Parallelism: uint64Ptr(3),
|
Parallelism: uint64Ptr(3),
|
||||||
Delay: time.Duration(10 * time.Second),
|
Delay: types.Duration(10 * time.Second),
|
||||||
FailureAction: "continue",
|
FailureAction: "continue",
|
||||||
Monitor: time.Duration(60 * time.Second),
|
Monitor: types.Duration(60 * time.Second),
|
||||||
MaxFailureRatio: 0.3,
|
MaxFailureRatio: 0.3,
|
||||||
Order: "start-first",
|
Order: "start-first",
|
||||||
},
|
},
|
||||||
UpdateConfig: &types.UpdateConfig{
|
UpdateConfig: &types.UpdateConfig{
|
||||||
Parallelism: uint64Ptr(3),
|
Parallelism: uint64Ptr(3),
|
||||||
Delay: time.Duration(10 * time.Second),
|
Delay: types.Duration(10 * time.Second),
|
||||||
FailureAction: "continue",
|
FailureAction: "continue",
|
||||||
Monitor: time.Duration(60 * time.Second),
|
Monitor: types.Duration(60 * time.Second),
|
||||||
MaxFailureRatio: 0.3,
|
MaxFailureRatio: 0.3,
|
||||||
Order: "start-first",
|
Order: "start-first",
|
||||||
},
|
},
|
||||||
|
@ -344,7 +344,7 @@ func services(workingDir, homeDir string) []types.ServiceConfig {
|
||||||
},
|
},
|
||||||
StdinOpen: true,
|
StdinOpen: true,
|
||||||
StopSignal: "SIGUSR1",
|
StopSignal: "SIGUSR1",
|
||||||
StopGracePeriod: durationPtr(time.Duration(20 * time.Second)),
|
StopGracePeriod: durationPtr(20 * time.Second),
|
||||||
Tmpfs: []string{"/run", "/tmp"},
|
Tmpfs: []string{"/run", "/tmp"},
|
||||||
Tty: true,
|
Tty: true,
|
||||||
Ulimits: map[string]*types.UlimitsConfig{
|
Ulimits: map[string]*types.UlimitsConfig{
|
||||||
|
@ -887,3 +887,551 @@ x-nested:
|
||||||
workingDir,
|
workingDir,
|
||||||
workingDir)
|
workingDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fullExampleJSON(workingDir string) string {
|
||||||
|
return fmt.Sprintf(`{
|
||||||
|
"configs": {
|
||||||
|
"config1": {
|
||||||
|
"file": "%s/config_data",
|
||||||
|
"external": false,
|
||||||
|
"labels": {
|
||||||
|
"foo": "bar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config2": {
|
||||||
|
"name": "my_config",
|
||||||
|
"external": true
|
||||||
|
},
|
||||||
|
"config3": {
|
||||||
|
"name": "config3",
|
||||||
|
"external": true
|
||||||
|
},
|
||||||
|
"config4": {
|
||||||
|
"name": "foo",
|
||||||
|
"file": "%s",
|
||||||
|
"external": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"networks": {
|
||||||
|
"external-network": {
|
||||||
|
"name": "external-network",
|
||||||
|
"ipam": {},
|
||||||
|
"external": true
|
||||||
|
},
|
||||||
|
"other-external-network": {
|
||||||
|
"name": "my-cool-network",
|
||||||
|
"ipam": {},
|
||||||
|
"external": true
|
||||||
|
},
|
||||||
|
"other-network": {
|
||||||
|
"driver": "overlay",
|
||||||
|
"driver_opts": {
|
||||||
|
"baz": "1",
|
||||||
|
"foo": "bar"
|
||||||
|
},
|
||||||
|
"ipam": {
|
||||||
|
"driver": "overlay",
|
||||||
|
"config": [
|
||||||
|
{
|
||||||
|
"subnet": "172.16.238.0/24"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"subnet": "2001:3984:3989::/64"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"external": false,
|
||||||
|
"labels": {
|
||||||
|
"foo": "bar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"some-network": {
|
||||||
|
"ipam": {},
|
||||||
|
"external": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"secrets": {
|
||||||
|
"secret1": {
|
||||||
|
"file": "%s/secret_data",
|
||||||
|
"external": false,
|
||||||
|
"labels": {
|
||||||
|
"foo": "bar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"secret2": {
|
||||||
|
"name": "my_secret",
|
||||||
|
"external": true
|
||||||
|
},
|
||||||
|
"secret3": {
|
||||||
|
"name": "secret3",
|
||||||
|
"external": true
|
||||||
|
},
|
||||||
|
"secret4": {
|
||||||
|
"name": "bar",
|
||||||
|
"file": "%s",
|
||||||
|
"external": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"services": {
|
||||||
|
"foo": {
|
||||||
|
"build": {
|
||||||
|
"context": "./dir",
|
||||||
|
"dockerfile": "Dockerfile",
|
||||||
|
"args": {
|
||||||
|
"foo": "bar"
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"FOO": "BAR"
|
||||||
|
},
|
||||||
|
"cache_from": [
|
||||||
|
"foo",
|
||||||
|
"bar"
|
||||||
|
],
|
||||||
|
"network": "foo",
|
||||||
|
"target": "foo"
|
||||||
|
},
|
||||||
|
"cap_add": [
|
||||||
|
"ALL"
|
||||||
|
],
|
||||||
|
"cap_drop": [
|
||||||
|
"NET_ADMIN",
|
||||||
|
"SYS_ADMIN"
|
||||||
|
],
|
||||||
|
"cgroup_parent": "m-executor-abcd",
|
||||||
|
"command": [
|
||||||
|
"bundle",
|
||||||
|
"exec",
|
||||||
|
"thin",
|
||||||
|
"-p",
|
||||||
|
"3000"
|
||||||
|
],
|
||||||
|
"configs": [
|
||||||
|
{
|
||||||
|
"source": "config1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "config2",
|
||||||
|
"target": "/my_config",
|
||||||
|
"uid": "103",
|
||||||
|
"gid": "103",
|
||||||
|
"mode": 288
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"container_name": "my-web-container",
|
||||||
|
"credential_spec": {},
|
||||||
|
"depends_on": [
|
||||||
|
"db",
|
||||||
|
"redis"
|
||||||
|
],
|
||||||
|
"deploy": {
|
||||||
|
"mode": "replicated",
|
||||||
|
"replicas": 6,
|
||||||
|
"labels": {
|
||||||
|
"FOO": "BAR"
|
||||||
|
},
|
||||||
|
"update_config": {
|
||||||
|
"parallelism": 3,
|
||||||
|
"delay": "10s",
|
||||||
|
"failure_action": "continue",
|
||||||
|
"monitor": "1m0s",
|
||||||
|
"max_failure_ratio": 0.3,
|
||||||
|
"order": "start-first"
|
||||||
|
},
|
||||||
|
"rollback_config": {
|
||||||
|
"parallelism": 3,
|
||||||
|
"delay": "10s",
|
||||||
|
"failure_action": "continue",
|
||||||
|
"monitor": "1m0s",
|
||||||
|
"max_failure_ratio": 0.3,
|
||||||
|
"order": "start-first"
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"limits": {
|
||||||
|
"cpus": "0.001",
|
||||||
|
"memory": "52428800"
|
||||||
|
},
|
||||||
|
"reservations": {
|
||||||
|
"cpus": "0.0001",
|
||||||
|
"memory": "20971520",
|
||||||
|
"generic_resources": [
|
||||||
|
{
|
||||||
|
"discrete_resource_spec": {
|
||||||
|
"kind": "gpu",
|
||||||
|
"value": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"discrete_resource_spec": {
|
||||||
|
"kind": "ssd",
|
||||||
|
"value": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"restart_policy": {
|
||||||
|
"condition": "on-failure",
|
||||||
|
"delay": "5s",
|
||||||
|
"max_attempts": 3,
|
||||||
|
"window": "2m0s"
|
||||||
|
},
|
||||||
|
"placement": {
|
||||||
|
"constraints": [
|
||||||
|
"node=foo"
|
||||||
|
],
|
||||||
|
"preferences": [
|
||||||
|
{
|
||||||
|
"spread": "node.labels.az"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"endpoint_mode": "dnsrr"
|
||||||
|
},
|
||||||
|
"devices": [
|
||||||
|
"/dev/ttyUSB0:/dev/ttyUSB0"
|
||||||
|
],
|
||||||
|
"dns": [
|
||||||
|
"8.8.8.8",
|
||||||
|
"9.9.9.9"
|
||||||
|
],
|
||||||
|
"dns_search": [
|
||||||
|
"dc1.example.com",
|
||||||
|
"dc2.example.com"
|
||||||
|
],
|
||||||
|
"domainname": "foo.com",
|
||||||
|
"entrypoint": [
|
||||||
|
"/code/entrypoint.sh",
|
||||||
|
"-p",
|
||||||
|
"3000"
|
||||||
|
],
|
||||||
|
"environment": {
|
||||||
|
"BAR": "bar_from_env_file_2",
|
||||||
|
"BAZ": "baz_from_service_def",
|
||||||
|
"FOO": "foo_from_env_file",
|
||||||
|
"QUX": "qux_from_environment"
|
||||||
|
},
|
||||||
|
"env_file": [
|
||||||
|
"./example1.env",
|
||||||
|
"./example2.env"
|
||||||
|
],
|
||||||
|
"expose": [
|
||||||
|
"3000",
|
||||||
|
"8000"
|
||||||
|
],
|
||||||
|
"external_links": [
|
||||||
|
"redis_1",
|
||||||
|
"project_db_1:mysql",
|
||||||
|
"project_db_1:postgresql"
|
||||||
|
],
|
||||||
|
"extra_hosts": [
|
||||||
|
"somehost:162.242.195.82",
|
||||||
|
"otherhost:50.31.209.229"
|
||||||
|
],
|
||||||
|
"hostname": "foo",
|
||||||
|
"healthcheck": {
|
||||||
|
"test": [
|
||||||
|
"CMD-SHELL",
|
||||||
|
"echo \"hello world\""
|
||||||
|
],
|
||||||
|
"timeout": "1s",
|
||||||
|
"interval": "10s",
|
||||||
|
"retries": 5,
|
||||||
|
"start_period": "15s"
|
||||||
|
},
|
||||||
|
"image": "redis",
|
||||||
|
"ipc": "host",
|
||||||
|
"labels": {
|
||||||
|
"com.example.description": "Accounting webapp",
|
||||||
|
"com.example.empty-label": "",
|
||||||
|
"com.example.number": "42"
|
||||||
|
},
|
||||||
|
"links": [
|
||||||
|
"db",
|
||||||
|
"db:database",
|
||||||
|
"redis"
|
||||||
|
],
|
||||||
|
"logging": {
|
||||||
|
"driver": "syslog",
|
||||||
|
"options": {
|
||||||
|
"syslog-address": "tcp://192.168.0.42:123"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mac_address": "02:42:ac:11:65:43",
|
||||||
|
"network_mode": "container:0cfeab0f748b9a743dc3da582046357c6ef497631c1a016d28d2bf9b4f899f7b",
|
||||||
|
"networks": {
|
||||||
|
"other-network": {
|
||||||
|
"ipv4_address": "172.16.238.10",
|
||||||
|
"ipv6_address": "2001:3984:3989::10"
|
||||||
|
},
|
||||||
|
"other-other-network": null,
|
||||||
|
"some-network": {
|
||||||
|
"aliases": [
|
||||||
|
"alias1",
|
||||||
|
"alias3"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pid": "host",
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 3000,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 3001,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 3002,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 3003,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 3004,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 3005,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 8000,
|
||||||
|
"published": 8000,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 8080,
|
||||||
|
"published": 9090,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 8081,
|
||||||
|
"published": 9091,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 22,
|
||||||
|
"published": 49100,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 8001,
|
||||||
|
"published": 8001,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 5000,
|
||||||
|
"published": 5000,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 5001,
|
||||||
|
"published": 5001,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 5002,
|
||||||
|
"published": 5002,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 5003,
|
||||||
|
"published": 5003,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 5004,
|
||||||
|
"published": 5004,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 5005,
|
||||||
|
"published": 5005,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 5006,
|
||||||
|
"published": 5006,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 5007,
|
||||||
|
"published": 5007,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 5008,
|
||||||
|
"published": 5008,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 5009,
|
||||||
|
"published": 5009,
|
||||||
|
"protocol": "tcp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mode": "ingress",
|
||||||
|
"target": 5010,
|
||||||
|
"published": 5010,
|
||||||
|
"protocol": "tcp"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"privileged": true,
|
||||||
|
"read_only": true,
|
||||||
|
"restart": "always",
|
||||||
|
"secrets": [
|
||||||
|
{
|
||||||
|
"source": "secret1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "secret2",
|
||||||
|
"target": "my_secret",
|
||||||
|
"uid": "103",
|
||||||
|
"gid": "103",
|
||||||
|
"mode": 288
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"security_opt": [
|
||||||
|
"label=level:s0:c100,c200",
|
||||||
|
"label=type:svirt_apache_t"
|
||||||
|
],
|
||||||
|
"stdin_open": true,
|
||||||
|
"stop_grace_period": "20s",
|
||||||
|
"stop_signal": "SIGUSR1",
|
||||||
|
"tmpfs": [
|
||||||
|
"/run",
|
||||||
|
"/tmp"
|
||||||
|
],
|
||||||
|
"tty": true,
|
||||||
|
"ulimits": {
|
||||||
|
"nofile": {
|
||||||
|
"soft": 20000,
|
||||||
|
"hard": 40000
|
||||||
|
},
|
||||||
|
"nproc": 65535
|
||||||
|
},
|
||||||
|
"user": "someone",
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"type": "volume",
|
||||||
|
"target": "/var/lib/mysql"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "bind",
|
||||||
|
"source": "/opt/data",
|
||||||
|
"target": "/var/lib/mysql"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "bind",
|
||||||
|
"source": "/foo",
|
||||||
|
"target": "/code"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "bind",
|
||||||
|
"source": "%s",
|
||||||
|
"target": "/var/www/html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "bind",
|
||||||
|
"source": "/bar/configs",
|
||||||
|
"target": "/etc/configs/",
|
||||||
|
"read_only": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "volume",
|
||||||
|
"source": "datavolume",
|
||||||
|
"target": "/var/lib/mysql"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "bind",
|
||||||
|
"source": "%s",
|
||||||
|
"target": "/opt",
|
||||||
|
"consistency": "cached"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tmpfs",
|
||||||
|
"target": "/opt",
|
||||||
|
"tmpfs": {
|
||||||
|
"size": 10000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"working_dir": "/code"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": "3.7",
|
||||||
|
"volumes": {
|
||||||
|
"another-volume": {
|
||||||
|
"name": "user_specified_name",
|
||||||
|
"driver": "vsphere",
|
||||||
|
"driver_opts": {
|
||||||
|
"baz": "1",
|
||||||
|
"foo": "bar"
|
||||||
|
},
|
||||||
|
"external": false
|
||||||
|
},
|
||||||
|
"external-volume": {
|
||||||
|
"name": "external-volume",
|
||||||
|
"external": true
|
||||||
|
},
|
||||||
|
"external-volume3": {
|
||||||
|
"name": "this-is-volume3",
|
||||||
|
"external": true
|
||||||
|
},
|
||||||
|
"other-external-volume": {
|
||||||
|
"name": "my-cool-volume",
|
||||||
|
"external": true
|
||||||
|
},
|
||||||
|
"other-volume": {
|
||||||
|
"driver": "flocker",
|
||||||
|
"driver_opts": {
|
||||||
|
"baz": "1",
|
||||||
|
"foo": "bar"
|
||||||
|
},
|
||||||
|
"external": false,
|
||||||
|
"labels": {
|
||||||
|
"foo": "bar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"some-volume": {
|
||||||
|
"external": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-bar": "baz",
|
||||||
|
"x-foo": "bar",
|
||||||
|
"x-nested": {
|
||||||
|
"bar": "baz",
|
||||||
|
"foo": "bar"
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
workingDir,
|
||||||
|
workingDir,
|
||||||
|
workingDir,
|
||||||
|
workingDir,
|
||||||
|
filepath.Join(workingDir, "static"),
|
||||||
|
filepath.Join(workingDir, "opt"))
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
interp "github.com/docker/cli/cli/compose/interpolation"
|
interp "github.com/docker/cli/cli/compose/interpolation"
|
||||||
"github.com/docker/cli/cli/compose/schema"
|
"github.com/docker/cli/cli/compose/schema"
|
||||||
|
@ -309,6 +310,7 @@ func createTransformHook(additionalTransformers ...Transformer) mapstructure.Dec
|
||||||
reflect.TypeOf(types.HostsList{}): transformListOrMappingFunc(":", false),
|
reflect.TypeOf(types.HostsList{}): transformListOrMappingFunc(":", false),
|
||||||
reflect.TypeOf(types.ServiceVolumeConfig{}): transformServiceVolumeConfig,
|
reflect.TypeOf(types.ServiceVolumeConfig{}): transformServiceVolumeConfig,
|
||||||
reflect.TypeOf(types.BuildConfig{}): transformBuildConfig,
|
reflect.TypeOf(types.BuildConfig{}): transformBuildConfig,
|
||||||
|
reflect.TypeOf(types.Duration(0)): transformStringToDuration,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, transformer := range additionalTransformers {
|
for _, transformer := range additionalTransformers {
|
||||||
|
@ -854,6 +856,19 @@ func transformSize(value interface{}) (interface{}, error) {
|
||||||
panic(errors.Errorf("invalid type for size %T", value))
|
panic(errors.Errorf("invalid type for size %T", value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func transformStringToDuration(value interface{}) (interface{}, error) {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case string:
|
||||||
|
d, err := time.ParseDuration(value)
|
||||||
|
if err != nil {
|
||||||
|
return value, err
|
||||||
|
}
|
||||||
|
return types.Duration(d), nil
|
||||||
|
default:
|
||||||
|
return value, errors.Errorf("invalid type %T for duration", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func toServicePortConfigs(value string) ([]interface{}, error) {
|
func toServicePortConfigs(value string) ([]interface{}, error) {
|
||||||
var portConfigs []interface{}
|
var portConfigs []interface{}
|
||||||
|
|
||||||
|
|
|
@ -806,15 +806,16 @@ volumes:
|
||||||
external_volume:
|
external_volume:
|
||||||
name: user_specified_name
|
name: user_specified_name
|
||||||
external:
|
external:
|
||||||
name: external_name
|
name: external_name
|
||||||
`)
|
`)
|
||||||
|
|
||||||
assert.ErrorContains(t, err, "volume.external.name and volume.name conflict; only use volume.name")
|
assert.ErrorContains(t, err, "volume.external.name and volume.name conflict; only use volume.name")
|
||||||
assert.ErrorContains(t, err, "external_volume")
|
assert.ErrorContains(t, err, "external_volume")
|
||||||
}
|
}
|
||||||
|
|
||||||
func durationPtr(value time.Duration) *time.Duration {
|
func durationPtr(value time.Duration) *types.Duration {
|
||||||
return &value
|
result := types.Duration(value)
|
||||||
|
return &result
|
||||||
}
|
}
|
||||||
|
|
||||||
func uint64Ptr(value uint64) *uint64 {
|
func uint64Ptr(value uint64) *uint64 {
|
||||||
|
@ -1281,7 +1282,7 @@ secrets:
|
||||||
external_secret:
|
external_secret:
|
||||||
name: user_specified_name
|
name: user_specified_name
|
||||||
external:
|
external:
|
||||||
name: external_name
|
name: external_name
|
||||||
`)
|
`)
|
||||||
|
|
||||||
assert.ErrorContains(t, err, "secret.external.name and secret.name conflict; only use secret.name")
|
assert.ErrorContains(t, err, "secret.external.name and secret.name conflict; only use secret.name")
|
||||||
|
@ -1368,7 +1369,7 @@ networks:
|
||||||
foo:
|
foo:
|
||||||
name: user_specified_name
|
name: user_specified_name
|
||||||
external:
|
external:
|
||||||
name: external_name
|
name: external_name
|
||||||
`)
|
`)
|
||||||
|
|
||||||
assert.ErrorContains(t, err, "network.external.name and network.name conflict; only use network.name")
|
assert.ErrorContains(t, err, "network.external.name and network.name conflict; only use network.name")
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package loader
|
package loader
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
yaml "gopkg.in/yaml.v2"
|
yaml "gopkg.in/yaml.v2"
|
||||||
|
@ -24,3 +25,19 @@ func TestMarshallConfig(t *testing.T) {
|
||||||
_, err = Load(buildConfigDetails(dict, map[string]string{}))
|
_, err = Load(buildConfigDetails(dict, map[string]string{}))
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJSONMarshallConfig(t *testing.T) {
|
||||||
|
workingDir := "/foo"
|
||||||
|
homeDir := "/bar"
|
||||||
|
cfg := fullExampleConfig(workingDir, homeDir)
|
||||||
|
expected := fullExampleJSON(workingDir)
|
||||||
|
|
||||||
|
actual, err := json.MarshalIndent(cfg, "", " ")
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.Equal(expected, string(actual)))
|
||||||
|
|
||||||
|
dict, err := ParseYAML([]byte(expected))
|
||||||
|
assert.NilError(t, err)
|
||||||
|
_, err = Load(buildConfigDetails(dict, map[string]string{}))
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -62,6 +63,32 @@ type ConfigDetails struct {
|
||||||
Environment map[string]string
|
Environment map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Duration is a thin wrapper around time.Duration with improved JSON marshalling
|
||||||
|
type Duration time.Duration
|
||||||
|
|
||||||
|
func (d Duration) String() string {
|
||||||
|
return time.Duration(d).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertDurationPtr converts a typedefined Duration pointer to a time.Duration pointer with the same value.
|
||||||
|
func ConvertDurationPtr(d *Duration) *time.Duration {
|
||||||
|
if d == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
res := time.Duration(*d)
|
||||||
|
return &res
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON makes Duration implement json.Marshaler
|
||||||
|
func (d Duration) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(d.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalYAML makes Duration implement yaml.Marshaler
|
||||||
|
func (d Duration) MarshalYAML() (interface{}, error) {
|
||||||
|
return d.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// LookupEnv provides a lookup function for environment variables
|
// LookupEnv provides a lookup function for environment variables
|
||||||
func (cd ConfigDetails) LookupEnv(key string) (string, bool) {
|
func (cd ConfigDetails) LookupEnv(key string) (string, bool) {
|
||||||
v, ok := cd.Environment[key]
|
v, ok := cd.Environment[key]
|
||||||
|
@ -70,14 +97,39 @@ func (cd ConfigDetails) LookupEnv(key string) (string, bool) {
|
||||||
|
|
||||||
// Config is a full compose file configuration
|
// Config is a full compose file configuration
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Filename string `yaml:"-"`
|
Filename string `yaml:"-" json:"-"`
|
||||||
Version string
|
Version string `json:"version"`
|
||||||
Services Services
|
Services Services `json:"services"`
|
||||||
Networks map[string]NetworkConfig `yaml:",omitempty"`
|
Networks map[string]NetworkConfig `yaml:",omitempty" json:"networks,omitempty"`
|
||||||
Volumes map[string]VolumeConfig `yaml:",omitempty"`
|
Volumes map[string]VolumeConfig `yaml:",omitempty" json:"volumes,omitempty"`
|
||||||
Secrets map[string]SecretConfig `yaml:",omitempty"`
|
Secrets map[string]SecretConfig `yaml:",omitempty" json:"secrets,omitempty"`
|
||||||
Configs map[string]ConfigObjConfig `yaml:",omitempty"`
|
Configs map[string]ConfigObjConfig `yaml:",omitempty" json:"configs,omitempty"`
|
||||||
Extras map[string]interface{} `yaml:",inline"`
|
Extras map[string]interface{} `yaml:",inline", json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON makes Config implement json.Marshaler
|
||||||
|
func (c Config) MarshalJSON() ([]byte, error) {
|
||||||
|
m := map[string]interface{}{
|
||||||
|
"version": c.Version,
|
||||||
|
"services": c.Services,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.Networks) > 0 {
|
||||||
|
m["networks"] = c.Networks
|
||||||
|
}
|
||||||
|
if len(c.Volumes) > 0 {
|
||||||
|
m["volumes"] = c.Volumes
|
||||||
|
}
|
||||||
|
if len(c.Secrets) > 0 {
|
||||||
|
m["secrets"] = c.Secrets
|
||||||
|
}
|
||||||
|
if len(c.Configs) > 0 {
|
||||||
|
m["configs"] = c.Configs
|
||||||
|
}
|
||||||
|
for k, v := range c.Extras {
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
return json.Marshal(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Services is a list of ServiceConfig
|
// Services is a list of ServiceConfig
|
||||||
|
@ -92,75 +144,84 @@ func (s Services) MarshalYAML() (interface{}, error) {
|
||||||
return services, nil
|
return services, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON makes Services implement json.Marshaler
|
||||||
|
func (s Services) MarshalJSON() ([]byte, error) {
|
||||||
|
data, err := s.MarshalYAML()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return json.MarshalIndent(data, "", " ")
|
||||||
|
}
|
||||||
|
|
||||||
// ServiceConfig is the configuration of one service
|
// ServiceConfig is the configuration of one service
|
||||||
type ServiceConfig struct {
|
type ServiceConfig struct {
|
||||||
Name string `yaml:"-"`
|
Name string `yaml:"-" json:"-"`
|
||||||
|
|
||||||
Build BuildConfig `yaml:",omitempty"`
|
Build BuildConfig `yaml:",omitempty" json:"build,omitempty"`
|
||||||
CapAdd []string `mapstructure:"cap_add" yaml:"cap_add,omitempty"`
|
CapAdd []string `mapstructure:"cap_add" yaml:"cap_add,omitempty" json:"cap_add,omitempty"`
|
||||||
CapDrop []string `mapstructure:"cap_drop" yaml:"cap_drop,omitempty"`
|
CapDrop []string `mapstructure:"cap_drop" yaml:"cap_drop,omitempty" json:"cap_drop,omitempty"`
|
||||||
CgroupParent string `mapstructure:"cgroup_parent" yaml:"cgroup_parent,omitempty"`
|
CgroupParent string `mapstructure:"cgroup_parent" yaml:"cgroup_parent,omitempty" json:"cgroup_parent,omitempty"`
|
||||||
Command ShellCommand `yaml:",omitempty"`
|
Command ShellCommand `yaml:",omitempty" json:"command,omitempty"`
|
||||||
Configs []ServiceConfigObjConfig `yaml:",omitempty"`
|
Configs []ServiceConfigObjConfig `yaml:",omitempty" json:"configs,omitempty"`
|
||||||
ContainerName string `mapstructure:"container_name" yaml:"container_name,omitempty"`
|
ContainerName string `mapstructure:"container_name" yaml:"container_name,omitempty" json:"container_name,omitempty"`
|
||||||
CredentialSpec CredentialSpecConfig `mapstructure:"credential_spec" yaml:"credential_spec,omitempty"`
|
CredentialSpec CredentialSpecConfig `mapstructure:"credential_spec" yaml:"credential_spec,omitempty" json:"credential_spec,omitempty"`
|
||||||
DependsOn []string `mapstructure:"depends_on" yaml:"depends_on,omitempty"`
|
DependsOn []string `mapstructure:"depends_on" yaml:"depends_on,omitempty" json:"depends_on,omitempty"`
|
||||||
Deploy DeployConfig `yaml:",omitempty"`
|
Deploy DeployConfig `yaml:",omitempty" json:"deploy,omitempty"`
|
||||||
Devices []string `yaml:",omitempty"`
|
Devices []string `yaml:",omitempty" json:"devices,omitempty"`
|
||||||
DNS StringList `yaml:",omitempty"`
|
DNS StringList `yaml:",omitempty" json:"dns,omitempty"`
|
||||||
DNSSearch StringList `mapstructure:"dns_search" yaml:"dns_search,omitempty"`
|
DNSSearch StringList `mapstructure:"dns_search" yaml:"dns_search,omitempty" json:"dns_search,omitempty"`
|
||||||
DomainName string `mapstructure:"domainname" yaml:"domainname,omitempty"`
|
DomainName string `mapstructure:"domainname" yaml:"domainname,omitempty" json:"domainname,omitempty"`
|
||||||
Entrypoint ShellCommand `yaml:",omitempty"`
|
Entrypoint ShellCommand `yaml:",omitempty" json:"entrypoint,omitempty"`
|
||||||
Environment MappingWithEquals `yaml:",omitempty"`
|
Environment MappingWithEquals `yaml:",omitempty" json:"environment,omitempty"`
|
||||||
EnvFile StringList `mapstructure:"env_file" yaml:"env_file,omitempty"`
|
EnvFile StringList `mapstructure:"env_file" yaml:"env_file,omitempty" json:"env_file,omitempty"`
|
||||||
Expose StringOrNumberList `yaml:",omitempty"`
|
Expose StringOrNumberList `yaml:",omitempty" json:"expose,omitempty"`
|
||||||
ExternalLinks []string `mapstructure:"external_links" yaml:"external_links,omitempty"`
|
ExternalLinks []string `mapstructure:"external_links" yaml:"external_links,omitempty" json:"external_links,omitempty"`
|
||||||
ExtraHosts HostsList `mapstructure:"extra_hosts" yaml:"extra_hosts,omitempty"`
|
ExtraHosts HostsList `mapstructure:"extra_hosts" yaml:"extra_hosts,omitempty" json:"extra_hosts,omitempty"`
|
||||||
Hostname string `yaml:",omitempty"`
|
Hostname string `yaml:",omitempty" json:"hostname,omitempty"`
|
||||||
HealthCheck *HealthCheckConfig `yaml:",omitempty"`
|
HealthCheck *HealthCheckConfig `yaml:",omitempty" json:"healthcheck,omitempty"`
|
||||||
Image string `yaml:",omitempty"`
|
Image string `yaml:",omitempty" json:"image,omitempty"`
|
||||||
Init *bool `yaml:",omitempty"`
|
Init *bool `yaml:",omitempty" json:"init,omitempty"`
|
||||||
Ipc string `yaml:",omitempty"`
|
Ipc string `yaml:",omitempty" json:"ipc,omitempty"`
|
||||||
Isolation string `mapstructure:"isolation" yaml:"isolation,omitempty"`
|
Isolation string `mapstructure:"isolation" yaml:"isolation,omitempty" json:"isolation,omitempty"`
|
||||||
Labels Labels `yaml:",omitempty"`
|
Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
|
||||||
Links []string `yaml:",omitempty"`
|
Links []string `yaml:",omitempty" json:"links,omitempty"`
|
||||||
Logging *LoggingConfig `yaml:",omitempty"`
|
Logging *LoggingConfig `yaml:",omitempty" json:"logging,omitempty"`
|
||||||
MacAddress string `mapstructure:"mac_address" yaml:"mac_address,omitempty"`
|
MacAddress string `mapstructure:"mac_address" yaml:"mac_address,omitempty" json:"mac_address,omitempty"`
|
||||||
NetworkMode string `mapstructure:"network_mode" yaml:"network_mode,omitempty"`
|
NetworkMode string `mapstructure:"network_mode" yaml:"network_mode,omitempty" json:"network_mode,omitempty"`
|
||||||
Networks map[string]*ServiceNetworkConfig `yaml:",omitempty"`
|
Networks map[string]*ServiceNetworkConfig `yaml:",omitempty" json:"networks,omitempty"`
|
||||||
Pid string `yaml:",omitempty"`
|
Pid string `yaml:",omitempty" json:"pid,omitempty"`
|
||||||
Ports []ServicePortConfig `yaml:",omitempty"`
|
Ports []ServicePortConfig `yaml:",omitempty" json:"ports,omitempty"`
|
||||||
Privileged bool `yaml:",omitempty"`
|
Privileged bool `yaml:",omitempty" json:"privileged,omitempty"`
|
||||||
ReadOnly bool `mapstructure:"read_only" yaml:"read_only,omitempty"`
|
ReadOnly bool `mapstructure:"read_only" yaml:"read_only,omitempty" json:"read_only,omitempty"`
|
||||||
Restart string `yaml:",omitempty"`
|
Restart string `yaml:",omitempty" json:"restart,omitempty"`
|
||||||
Secrets []ServiceSecretConfig `yaml:",omitempty"`
|
Secrets []ServiceSecretConfig `yaml:",omitempty" json:"secrets,omitempty"`
|
||||||
SecurityOpt []string `mapstructure:"security_opt" yaml:"security_opt,omitempty"`
|
SecurityOpt []string `mapstructure:"security_opt" yaml:"security_opt,omitempty" json:"security_opt,omitempty"`
|
||||||
ShmSize string `mapstructure:"shm_size" yaml:"shm_size,omitempty"`
|
ShmSize string `mapstructure:"shm_size" yaml:"shm_size,omitempty" json:"shm_size,omitempty"`
|
||||||
StdinOpen bool `mapstructure:"stdin_open" yaml:"stdin_open,omitempty"`
|
StdinOpen bool `mapstructure:"stdin_open" yaml:"stdin_open,omitempty" json:"stdin_open,omitempty"`
|
||||||
StopGracePeriod *time.Duration `mapstructure:"stop_grace_period" yaml:"stop_grace_period,omitempty"`
|
StopGracePeriod *Duration `mapstructure:"stop_grace_period" yaml:"stop_grace_period,omitempty" json:"stop_grace_period,omitempty"`
|
||||||
StopSignal string `mapstructure:"stop_signal" yaml:"stop_signal,omitempty"`
|
StopSignal string `mapstructure:"stop_signal" yaml:"stop_signal,omitempty" json:"stop_signal,omitempty"`
|
||||||
Sysctls StringList `yaml:",omitempty"`
|
Sysctls StringList `yaml:",omitempty" json:"sysctls,omitempty"`
|
||||||
Tmpfs StringList `yaml:",omitempty"`
|
Tmpfs StringList `yaml:",omitempty" json:"tmpfs,omitempty"`
|
||||||
Tty bool `mapstructure:"tty" yaml:"tty,omitempty"`
|
Tty bool `mapstructure:"tty" yaml:"tty,omitempty" json:"tty,omitempty"`
|
||||||
Ulimits map[string]*UlimitsConfig `yaml:",omitempty"`
|
Ulimits map[string]*UlimitsConfig `yaml:",omitempty" json:"ulimits,omitempty"`
|
||||||
User string `yaml:",omitempty"`
|
User string `yaml:",omitempty" json:"user,omitempty"`
|
||||||
UserNSMode string `mapstructure:"userns_mode" yaml:"userns_mode,omitempty"`
|
UserNSMode string `mapstructure:"userns_mode" yaml:"userns_mode,omitempty" json:"userns_mode,omitempty"`
|
||||||
Volumes []ServiceVolumeConfig `yaml:",omitempty"`
|
Volumes []ServiceVolumeConfig `yaml:",omitempty" json:"volumes,omitempty"`
|
||||||
WorkingDir string `mapstructure:"working_dir" yaml:"working_dir,omitempty"`
|
WorkingDir string `mapstructure:"working_dir" yaml:"working_dir,omitempty" json:"working_dir,omitempty"`
|
||||||
|
|
||||||
Extras map[string]interface{} `yaml:",inline"`
|
Extras map[string]interface{} `yaml:",inline" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildConfig is a type for build
|
// BuildConfig is a type for build
|
||||||
// using the same format at libcompose: https://github.com/docker/libcompose/blob/master/yaml/build.go#L12
|
// using the same format at libcompose: https://github.com/docker/libcompose/blob/master/yaml/build.go#L12
|
||||||
type BuildConfig struct {
|
type BuildConfig struct {
|
||||||
Context string `yaml:",omitempty"`
|
Context string `yaml:",omitempty" json:"context,omitempty"`
|
||||||
Dockerfile string `yaml:",omitempty"`
|
Dockerfile string `yaml:",omitempty" json:"dockerfile,omitempty"`
|
||||||
Args MappingWithEquals `yaml:",omitempty"`
|
Args MappingWithEquals `yaml:",omitempty" json:"args,omitempty"`
|
||||||
Labels Labels `yaml:",omitempty"`
|
Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
|
||||||
CacheFrom StringList `mapstructure:"cache_from" yaml:"cache_from,omitempty"`
|
CacheFrom StringList `mapstructure:"cache_from" yaml:"cache_from,omitempty" json:"cache_from,omitempty"`
|
||||||
Network string `yaml:",omitempty"`
|
Network string `yaml:",omitempty" json:"network,omitempty"`
|
||||||
Target string `yaml:",omitempty"`
|
Target string `yaml:",omitempty" json:"target,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShellCommand is a string or list of string args
|
// ShellCommand is a string or list of string args
|
||||||
|
@ -191,31 +252,31 @@ type HostsList []string
|
||||||
|
|
||||||
// LoggingConfig the logging configuration for a service
|
// LoggingConfig the logging configuration for a service
|
||||||
type LoggingConfig struct {
|
type LoggingConfig struct {
|
||||||
Driver string `yaml:",omitempty"`
|
Driver string `yaml:",omitempty" json:"driver,omitempty"`
|
||||||
Options map[string]string `yaml:",omitempty"`
|
Options map[string]string `yaml:",omitempty" json:"options,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeployConfig the deployment configuration for a service
|
// DeployConfig the deployment configuration for a service
|
||||||
type DeployConfig struct {
|
type DeployConfig struct {
|
||||||
Mode string `yaml:",omitempty"`
|
Mode string `yaml:",omitempty" json:"mode,omitempty"`
|
||||||
Replicas *uint64 `yaml:",omitempty"`
|
Replicas *uint64 `yaml:",omitempty" json:"replicas,omitempty"`
|
||||||
Labels Labels `yaml:",omitempty"`
|
Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
|
||||||
UpdateConfig *UpdateConfig `mapstructure:"update_config" yaml:"update_config,omitempty"`
|
UpdateConfig *UpdateConfig `mapstructure:"update_config" yaml:"update_config,omitempty" json:"update_config,omitempty"`
|
||||||
RollbackConfig *UpdateConfig `mapstructure:"rollback_config" yaml:"rollback_config,omitempty"`
|
RollbackConfig *UpdateConfig `mapstructure:"rollback_config" yaml:"rollback_config,omitempty" json:"rollback_config,omitempty"`
|
||||||
Resources Resources `yaml:",omitempty"`
|
Resources Resources `yaml:",omitempty" json:"resources,omitempty"`
|
||||||
RestartPolicy *RestartPolicy `mapstructure:"restart_policy" yaml:"restart_policy,omitempty"`
|
RestartPolicy *RestartPolicy `mapstructure:"restart_policy" yaml:"restart_policy,omitempty" json:"restart_policy,omitempty"`
|
||||||
Placement Placement `yaml:",omitempty"`
|
Placement Placement `yaml:",omitempty" json:"placement,omitempty"`
|
||||||
EndpointMode string `mapstructure:"endpoint_mode" yaml:"endpoint_mode,omitempty"`
|
EndpointMode string `mapstructure:"endpoint_mode" yaml:"endpoint_mode,omitempty" json:"endpoint_mode,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// HealthCheckConfig the healthcheck configuration for a service
|
// HealthCheckConfig the healthcheck configuration for a service
|
||||||
type HealthCheckConfig struct {
|
type HealthCheckConfig struct {
|
||||||
Test HealthCheckTest `yaml:",omitempty"`
|
Test HealthCheckTest `yaml:",omitempty" json:"test,omitempty"`
|
||||||
Timeout *time.Duration `yaml:",omitempty"`
|
Timeout *Duration `yaml:",omitempty" json:"timeout,omitempty"`
|
||||||
Interval *time.Duration `yaml:",omitempty"`
|
Interval *Duration `yaml:",omitempty" json:"interval,omitempty"`
|
||||||
Retries *uint64 `yaml:",omitempty"`
|
Retries *uint64 `yaml:",omitempty" json:"retries,omitempty"`
|
||||||
StartPeriod *time.Duration `mapstructure:"start_period" yaml:"start_period,omitempty"`
|
StartPeriod *Duration `mapstructure:"start_period" yaml:"start_period,omitempty" json:"start_period,omitempty"`
|
||||||
Disable bool `yaml:",omitempty"`
|
Disable bool `yaml:",omitempty" json:"disable,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// HealthCheckTest is the command run to test the health of a service
|
// HealthCheckTest is the command run to test the health of a service
|
||||||
|
@ -223,32 +284,32 @@ type HealthCheckTest []string
|
||||||
|
|
||||||
// UpdateConfig the service update configuration
|
// UpdateConfig the service update configuration
|
||||||
type UpdateConfig struct {
|
type UpdateConfig struct {
|
||||||
Parallelism *uint64 `yaml:",omitempty"`
|
Parallelism *uint64 `yaml:",omitempty" json:"parallelism,omitempty"`
|
||||||
Delay time.Duration `yaml:",omitempty"`
|
Delay Duration `yaml:",omitempty" json:"delay,omitempty"`
|
||||||
FailureAction string `mapstructure:"failure_action" yaml:"failure_action,omitempty"`
|
FailureAction string `mapstructure:"failure_action" yaml:"failure_action,omitempty" json:"failure_action,omitempty"`
|
||||||
Monitor time.Duration `yaml:",omitempty"`
|
Monitor Duration `yaml:",omitempty" json:"monitor,omitempty"`
|
||||||
MaxFailureRatio float32 `mapstructure:"max_failure_ratio" yaml:"max_failure_ratio,omitempty"`
|
MaxFailureRatio float32 `mapstructure:"max_failure_ratio" yaml:"max_failure_ratio,omitempty" json:"max_failure_ratio,omitempty"`
|
||||||
Order string `yaml:",omitempty"`
|
Order string `yaml:",omitempty" json:"order,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resources the resource limits and reservations
|
// Resources the resource limits and reservations
|
||||||
type Resources struct {
|
type Resources struct {
|
||||||
Limits *Resource `yaml:",omitempty"`
|
Limits *Resource `yaml:",omitempty" json:"limits,omitempty"`
|
||||||
Reservations *Resource `yaml:",omitempty"`
|
Reservations *Resource `yaml:",omitempty" json:"reservations,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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"`
|
NanoCPUs string `mapstructure:"cpus" yaml:"cpus,omitempty" json:"cpus,omitempty"`
|
||||||
MemoryBytes UnitBytes `mapstructure:"memory" yaml:"memory,omitempty"`
|
MemoryBytes UnitBytes `mapstructure:"memory" yaml:"memory,omitempty" json:"memory,omitempty"`
|
||||||
GenericResources []GenericResource `mapstructure:"generic_resources" yaml:"generic_resources,omitempty"`
|
GenericResources []GenericResource `mapstructure:"generic_resources" yaml:"generic_resources,omitempty" json:"generic_resources,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"`
|
DiscreteResourceSpec *DiscreteGenericResource `mapstructure:"discrete_resource_spec" yaml:"discrete_resource_spec,omitempty" json:"discrete_resource_spec,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiscreteGenericResource represents a "user defined" resource which is defined
|
// DiscreteGenericResource represents a "user defined" resource which is defined
|
||||||
|
@ -256,8 +317,8 @@ type GenericResource struct {
|
||||||
// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
|
// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
|
||||||
// Value is used to count the resource (SSD=5, HDD=3, ...)
|
// Value is used to count the resource (SSD=5, HDD=3, ...)
|
||||||
type DiscreteGenericResource struct {
|
type DiscreteGenericResource struct {
|
||||||
Kind string
|
Kind string `json:"kind"`
|
||||||
Value int64
|
Value int64 `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnitBytes is the bytes type
|
// UnitBytes is the bytes type
|
||||||
|
@ -268,74 +329,79 @@ func (u UnitBytes) MarshalYAML() (interface{}, error) {
|
||||||
return fmt.Sprintf("%d", u), nil
|
return fmt.Sprintf("%d", u), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON makes UnitBytes implement json.Marshaler
|
||||||
|
func (u UnitBytes) MarshalJSON() ([]byte, error) {
|
||||||
|
return []byte(fmt.Sprintf(`"%d"`, u)), nil
|
||||||
|
}
|
||||||
|
|
||||||
// RestartPolicy the service restart policy
|
// RestartPolicy the service restart policy
|
||||||
type RestartPolicy struct {
|
type RestartPolicy struct {
|
||||||
Condition string `yaml:",omitempty"`
|
Condition string `yaml:",omitempty" json:"condition,omitempty"`
|
||||||
Delay *time.Duration `yaml:",omitempty"`
|
Delay *Duration `yaml:",omitempty" json:"delay,omitempty"`
|
||||||
MaxAttempts *uint64 `mapstructure:"max_attempts" yaml:"max_attempts,omitempty"`
|
MaxAttempts *uint64 `mapstructure:"max_attempts" yaml:"max_attempts,omitempty" json:"max_attempts,omitempty"`
|
||||||
Window *time.Duration `yaml:",omitempty"`
|
Window *Duration `yaml:",omitempty" json:"window,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Placement constraints for the service
|
// Placement constraints for the service
|
||||||
type Placement struct {
|
type Placement struct {
|
||||||
Constraints []string `yaml:",omitempty"`
|
Constraints []string `yaml:",omitempty" json:"constraints,omitempty"`
|
||||||
Preferences []PlacementPreferences `yaml:",omitempty"`
|
Preferences []PlacementPreferences `yaml:",omitempty" json:"preferences,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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"`
|
Spread string `yaml:",omitempty" json:"spread,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceNetworkConfig is the network configuration for a service
|
// ServiceNetworkConfig is the network configuration for a service
|
||||||
type ServiceNetworkConfig struct {
|
type ServiceNetworkConfig struct {
|
||||||
Aliases []string `yaml:",omitempty"`
|
Aliases []string `yaml:",omitempty" json:"aliases,omitempty"`
|
||||||
Ipv4Address string `mapstructure:"ipv4_address" yaml:"ipv4_address,omitempty"`
|
Ipv4Address string `mapstructure:"ipv4_address" yaml:"ipv4_address,omitempty" json:"ipv4_address,omitempty"`
|
||||||
Ipv6Address string `mapstructure:"ipv6_address" yaml:"ipv6_address,omitempty"`
|
Ipv6Address string `mapstructure:"ipv6_address" yaml:"ipv6_address,omitempty" json:"ipv6_address,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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"`
|
Mode string `yaml:",omitempty" json:"mode,omitempty"`
|
||||||
Target uint32 `yaml:",omitempty"`
|
Target uint32 `yaml:",omitempty" json:"target,omitempty"`
|
||||||
Published uint32 `yaml:",omitempty"`
|
Published uint32 `yaml:",omitempty" json:"published,omitempty"`
|
||||||
Protocol string `yaml:",omitempty"`
|
Protocol string `yaml:",omitempty" json:"protocol,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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"`
|
Type string `yaml:",omitempty" json:"type,omitempty"`
|
||||||
Source string `yaml:",omitempty"`
|
Source string `yaml:",omitempty" json:"source,omitempty"`
|
||||||
Target string `yaml:",omitempty"`
|
Target string `yaml:",omitempty" json:"target,omitempty"`
|
||||||
ReadOnly bool `mapstructure:"read_only" yaml:"read_only,omitempty"`
|
ReadOnly bool `mapstructure:"read_only" yaml:"read_only,omitempty" json:"read_only,omitempty"`
|
||||||
Consistency string `yaml:",omitempty"`
|
Consistency string `yaml:",omitempty" json:"consistency,omitempty"`
|
||||||
Bind *ServiceVolumeBind `yaml:",omitempty"`
|
Bind *ServiceVolumeBind `yaml:",omitempty" json:"bind,omitempty"`
|
||||||
Volume *ServiceVolumeVolume `yaml:",omitempty"`
|
Volume *ServiceVolumeVolume `yaml:",omitempty" json:"volume,omitempty"`
|
||||||
Tmpfs *ServiceVolumeTmpfs `yaml:",omitempty"`
|
Tmpfs *ServiceVolumeTmpfs `yaml:",omitempty" json:"tmpfs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
Propagation string `yaml:",omitempty"`
|
Propagation string `yaml:",omitempty" json:"propagation,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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"`
|
NoCopy bool `mapstructure:"nocopy" yaml:"nocopy,omitempty" json:"nocopy,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 int64 `yaml:",omitempty"`
|
Size int64 `yaml:",omitempty" json:"size,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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"`
|
Source string `yaml:",omitempty" json:"source,omitempty"`
|
||||||
Target string `yaml:",omitempty"`
|
Target string `yaml:",omitempty" json:"target,omitempty"`
|
||||||
UID string `yaml:",omitempty"`
|
UID string `yaml:",omitempty" json:"uid,omitempty"`
|
||||||
GID string `yaml:",omitempty"`
|
GID string `yaml:",omitempty" json:"gid,omitempty"`
|
||||||
Mode *uint32 `yaml:",omitempty"`
|
Mode *uint32 `yaml:",omitempty" json:"mode,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceConfigObjConfig is the config obj configuration for a service
|
// ServiceConfigObjConfig is the config obj configuration for a service
|
||||||
|
@ -346,9 +412,9 @@ type ServiceSecretConfig FileReferenceConfig
|
||||||
|
|
||||||
// UlimitsConfig the ulimit configuration
|
// UlimitsConfig the ulimit configuration
|
||||||
type UlimitsConfig struct {
|
type UlimitsConfig struct {
|
||||||
Single int `yaml:",omitempty"`
|
Single int `yaml:",omitempty" json:"single,omitempty"`
|
||||||
Soft int `yaml:",omitempty"`
|
Soft int `yaml:",omitempty" json:"soft,omitempty"`
|
||||||
Hard int `yaml:",omitempty"`
|
Hard int `yaml:",omitempty" json:"hard,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalYAML makes UlimitsConfig implement yaml.Marshaller
|
// MarshalYAML makes UlimitsConfig implement yaml.Marshaller
|
||||||
|
@ -359,46 +425,55 @@ func (u *UlimitsConfig) MarshalYAML() (interface{}, error) {
|
||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON makes UlimitsConfig implement json.Marshaller
|
||||||
|
func (u *UlimitsConfig) MarshalJSON() ([]byte, error) {
|
||||||
|
if u.Single != 0 {
|
||||||
|
return json.Marshal(u.Single)
|
||||||
|
}
|
||||||
|
// Pass as a value to avoid re-entering this method and use the default implementation
|
||||||
|
return json.Marshal(*u)
|
||||||
|
}
|
||||||
|
|
||||||
// NetworkConfig for a network
|
// NetworkConfig for a network
|
||||||
type NetworkConfig struct {
|
type NetworkConfig struct {
|
||||||
Name string `yaml:",omitempty"`
|
Name string `yaml:",omitempty" json:"name,omitempty"`
|
||||||
Driver string `yaml:",omitempty"`
|
Driver string `yaml:",omitempty" json:"driver,omitempty"`
|
||||||
DriverOpts map[string]string `mapstructure:"driver_opts" yaml:"driver_opts,omitempty"`
|
DriverOpts map[string]string `mapstructure:"driver_opts" yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
|
||||||
Ipam IPAMConfig `yaml:",omitempty"`
|
Ipam IPAMConfig `yaml:",omitempty" json:"ipam,omitempty"`
|
||||||
External External `yaml:",omitempty"`
|
External External `yaml:",omitempty" json:"external,omitempty"`
|
||||||
Internal bool `yaml:",omitempty"`
|
Internal bool `yaml:",omitempty" json:"internal,omitempty"`
|
||||||
Attachable bool `yaml:",omitempty"`
|
Attachable bool `yaml:",omitempty" json:"attachable,omitempty"`
|
||||||
Labels Labels `yaml:",omitempty"`
|
Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
|
||||||
Extras map[string]interface{} `yaml:",inline"`
|
Extras map[string]interface{} `yaml:",inline" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IPAMConfig for a network
|
// IPAMConfig for a network
|
||||||
type IPAMConfig struct {
|
type IPAMConfig struct {
|
||||||
Driver string `yaml:",omitempty"`
|
Driver string `yaml:",omitempty" json:"driver,omitempty"`
|
||||||
Config []*IPAMPool `yaml:",omitempty"`
|
Config []*IPAMPool `yaml:",omitempty" json:"config,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IPAMPool for a network
|
// IPAMPool for a network
|
||||||
type IPAMPool struct {
|
type IPAMPool struct {
|
||||||
Subnet string `yaml:",omitempty"`
|
Subnet string `yaml:",omitempty" json:"subnet,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// VolumeConfig for a volume
|
// VolumeConfig for a volume
|
||||||
type VolumeConfig struct {
|
type VolumeConfig struct {
|
||||||
Name string `yaml:",omitempty"`
|
Name string `yaml:",omitempty" json:"name,omitempty"`
|
||||||
Driver string `yaml:",omitempty"`
|
Driver string `yaml:",omitempty" json:"driver,omitempty"`
|
||||||
DriverOpts map[string]string `mapstructure:"driver_opts" yaml:"driver_opts,omitempty"`
|
DriverOpts map[string]string `mapstructure:"driver_opts" yaml:"driver_opts,omitempty" json:"driver_opts,omitempty"`
|
||||||
External External `yaml:",omitempty"`
|
External External `yaml:",omitempty" json:"external,omitempty"`
|
||||||
Labels Labels `yaml:",omitempty"`
|
Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
|
||||||
Extras map[string]interface{} `yaml:",inline"`
|
Extras map[string]interface{} `yaml:",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"`
|
Name string `yaml:",omitempty" json:"name,omitempty"`
|
||||||
External bool `yaml:",omitempty"`
|
External bool `yaml:",omitempty" json:"external,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalYAML makes External implement yaml.Marshaller
|
// MarshalYAML makes External implement yaml.Marshaller
|
||||||
|
@ -409,19 +484,27 @@ func (e External) MarshalYAML() (interface{}, error) {
|
||||||
return External{Name: e.Name}, nil
|
return External{Name: e.Name}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON makes External implement json.Marshaller
|
||||||
|
func (e External) MarshalJSON() ([]byte, error) {
|
||||||
|
if e.Name == "" {
|
||||||
|
return []byte(fmt.Sprintf("%v", e.External)), nil
|
||||||
|
}
|
||||||
|
return []byte(fmt.Sprintf(`{"name": %q}`, e.Name)), nil
|
||||||
|
}
|
||||||
|
|
||||||
// CredentialSpecConfig for credential spec on Windows
|
// CredentialSpecConfig for credential spec on Windows
|
||||||
type CredentialSpecConfig struct {
|
type CredentialSpecConfig struct {
|
||||||
File string `yaml:",omitempty"`
|
File string `yaml:",omitempty" json:"file,omitempty"`
|
||||||
Registry string `yaml:",omitempty"`
|
Registry string `yaml:",omitempty" json:"registry,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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"`
|
Name string `yaml:",omitempty" json:"name,omitempty"`
|
||||||
File string `yaml:",omitempty"`
|
File string `yaml:",omitempty" json:"file,omitempty"`
|
||||||
External External `yaml:",omitempty"`
|
External External `yaml:",omitempty" json:"external,omitempty"`
|
||||||
Labels Labels `yaml:",omitempty"`
|
Labels Labels `yaml:",omitempty" json:"labels,omitempty"`
|
||||||
Extras map[string]interface{} `yaml:",inline"`
|
Extras map[string]interface{} `yaml:",inline" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecretConfig for a secret
|
// SecretConfig for a secret
|
||||||
|
|
Loading…
Reference in New Issue