1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #31795 from dnephin/compose-file-v3.2

Compose file v3.2
This commit is contained in:
Daniel Nephin 2017-03-14 14:10:24 -04:00 committed by GitHub
commit cd56476f18
7 changed files with 522 additions and 57 deletions

View file

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"sort" "sort"
"strings"
"time" "time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
@ -56,7 +57,7 @@ func convertService(
) (swarm.ServiceSpec, error) { ) (swarm.ServiceSpec, error) {
name := namespace.Scope(service.Name) name := namespace.Scope(service.Name)
endpoint, err := convertEndpointSpec(service.Ports) endpoint, err := convertEndpointSpec(service.Deploy.EndpointMode, service.Ports)
if err != nil { if err != nil {
return swarm.ServiceSpec{}, err return swarm.ServiceSpec{}, err
} }
@ -373,7 +374,7 @@ func (a byPublishedPort) Len() int { return len(a) }
func (a byPublishedPort) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a byPublishedPort) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byPublishedPort) Less(i, j int) bool { return a[i].PublishedPort < a[j].PublishedPort } func (a byPublishedPort) Less(i, j int) bool { return a[i].PublishedPort < a[j].PublishedPort }
func convertEndpointSpec(source []composetypes.ServicePortConfig) (*swarm.EndpointSpec, error) { func convertEndpointSpec(endpointMode string, source []composetypes.ServicePortConfig) (*swarm.EndpointSpec, error) {
portConfigs := []swarm.PortConfig{} portConfigs := []swarm.PortConfig{}
for _, port := range source { for _, port := range source {
portConfig := swarm.PortConfig{ portConfig := swarm.PortConfig{
@ -386,7 +387,10 @@ func convertEndpointSpec(source []composetypes.ServicePortConfig) (*swarm.Endpoi
} }
sort.Sort(byPublishedPort(portConfigs)) sort.Sort(byPublishedPort(portConfigs))
return &swarm.EndpointSpec{Ports: portConfigs}, nil return &swarm.EndpointSpec{
Mode: swarm.ResolutionMode(strings.ToLower(endpointMode)),
Ports: portConfigs,
}, nil
} }
func convertEnvironment(source map[string]string) []string { func convertEnvironment(source map[string]string) []string {

View file

@ -156,9 +156,10 @@ func TestConvertEndpointSpec(t *testing.T) {
Published: 80, Published: 80,
}, },
} }
endpoint, err := convertEndpointSpec(source) endpoint, err := convertEndpointSpec("vip", source)
expected := swarm.EndpointSpec{ expected := swarm.EndpointSpec{
Mode: swarm.ResolutionMode(strings.ToLower("vip")),
Ports: []swarm.PortConfig{ Ports: []swarm.PortConfig{
{ {
TargetPort: 8080, TargetPort: 8080,

View file

@ -977,7 +977,7 @@ func (sbn servicesByName) Less(i, j int) bool { return sbn[i].Name < sbn[j].Name
func TestLoadAttachableNetwork(t *testing.T) { func TestLoadAttachableNetwork(t *testing.T) {
config, err := loadYAML(` config, err := loadYAML(`
version: "3.1" version: "3.2"
networks: networks:
mynet1: mynet1:
driver: overlay driver: overlay
@ -985,7 +985,9 @@ networks:
mynet2: mynet2:
driver: bridge driver: bridge
`) `)
assert.NoError(t, err) if !assert.NoError(t, err) {
return
}
expected := map[string]types.NetworkConfig{ expected := map[string]types.NetworkConfig{
"mynet1": { "mynet1": {
@ -1003,7 +1005,7 @@ networks:
func TestLoadExpandedPortFormat(t *testing.T) { func TestLoadExpandedPortFormat(t *testing.T) {
config, err := loadYAML(` config, err := loadYAML(`
version: "3.1" version: "3.2"
services: services:
web: web:
image: busybox image: busybox
@ -1019,7 +1021,9 @@ services:
target: 22 target: 22
published: 10022 published: 10022
`) `)
assert.NoError(t, err) if !assert.NoError(t, err) {
return
}
expected := []types.ServicePortConfig{ expected := []types.ServicePortConfig{
{ {
@ -1088,7 +1092,7 @@ services:
func TestLoadExpandedMountFormat(t *testing.T) { func TestLoadExpandedMountFormat(t *testing.T) {
config, err := loadYAML(` config, err := loadYAML(`
version: "3.1" version: "3.2"
services: services:
web: web:
image: busybox image: busybox
@ -1100,7 +1104,9 @@ services:
volumes: volumes:
foo: {} foo: {}
`) `)
assert.NoError(t, err) if !assert.NoError(t, err) {
return
}
expected := types.ServiceVolumeConfig{ expected := types.ServiceVolumeConfig{
Type: "volume", Type: "volume",

File diff suppressed because one or more lines are too long

View file

@ -167,20 +167,8 @@
"ports": { "ports": {
"type": "array", "type": "array",
"items": { "items": {
"oneOf": [ "type": ["string", "number"],
{"type": "number", "format": "ports"}, "format": "ports"
{"type": "string", "format": "ports"},
{
"type": "object",
"properties": {
"mode": {"type": "string"},
"target": {"type": "integer"},
"published": {"type": "integer"},
"protocol": {"type": "string"}
},
"additionalProperties": false
}
]
}, },
"uniqueItems": true "uniqueItems": true
}, },
@ -235,37 +223,7 @@
}, },
"user": {"type": "string"}, "user": {"type": "string"},
"userns_mode": {"type": "string"}, "userns_mode": {"type": "string"},
"volumes": { "volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"type": "array",
"items": {
"oneOf": [
{"type": "string"},
{
"type": "object",
"required": ["type"],
"properties": {
"type": {"type": "string"},
"source": {"type": "string"},
"target": {"type": "string"},
"read_only": {"type": "boolean"},
"bind": {
"type": "object",
"properties": {
"propagation": {"type": "string"}
}
},
"volume": {
"type": "object",
"properties": {
"nocopy": {"type": "boolean"}
}
}
}
}
],
"uniqueItems": true
}
},
"working_dir": {"type": "string"} "working_dir": {"type": "string"}
}, },
"additionalProperties": false "additionalProperties": false
@ -380,7 +338,6 @@
"additionalProperties": false "additionalProperties": false
}, },
"internal": {"type": "boolean"}, "internal": {"type": "boolean"},
"attachable": {"type": "boolean"},
"labels": {"$ref": "#/definitions/list_or_dict"} "labels": {"$ref": "#/definitions/list_or_dict"}
}, },
"additionalProperties": false "additionalProperties": false

View file

@ -0,0 +1,473 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "config_schema_v3.1.json",
"type": "object",
"required": ["version"],
"properties": {
"version": {
"type": "string"
},
"services": {
"id": "#/properties/services",
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9._-]+$": {
"$ref": "#/definitions/service"
}
},
"additionalProperties": false
},
"networks": {
"id": "#/properties/networks",
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9._-]+$": {
"$ref": "#/definitions/network"
}
}
},
"volumes": {
"id": "#/properties/volumes",
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9._-]+$": {
"$ref": "#/definitions/volume"
}
},
"additionalProperties": false
},
"secrets": {
"id": "#/properties/secrets",
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9._-]+$": {
"$ref": "#/definitions/secret"
}
},
"additionalProperties": false
}
},
"additionalProperties": false,
"definitions": {
"service": {
"id": "#/definitions/service",
"type": "object",
"properties": {
"deploy": {"$ref": "#/definitions/deployment"},
"build": {
"oneOf": [
{"type": "string"},
{
"type": "object",
"properties": {
"context": {"type": "string"},
"dockerfile": {"type": "string"},
"args": {"$ref": "#/definitions/list_or_dict"},
"cache_from": {"$ref": "#/definitions/list_of_strings"}
},
"additionalProperties": false
}
]
},
"cap_add": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"cap_drop": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"cgroup_parent": {"type": "string"},
"command": {
"oneOf": [
{"type": "string"},
{"type": "array", "items": {"type": "string"}}
]
},
"container_name": {"type": "string"},
"depends_on": {"$ref": "#/definitions/list_of_strings"},
"devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"dns": {"$ref": "#/definitions/string_or_list"},
"dns_search": {"$ref": "#/definitions/string_or_list"},
"domainname": {"type": "string"},
"entrypoint": {
"oneOf": [
{"type": "string"},
{"type": "array", "items": {"type": "string"}}
]
},
"env_file": {"$ref": "#/definitions/string_or_list"},
"environment": {"$ref": "#/definitions/list_or_dict"},
"expose": {
"type": "array",
"items": {
"type": ["string", "number"],
"format": "expose"
},
"uniqueItems": true
},
"external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"extra_hosts": {"$ref": "#/definitions/list_or_dict"},
"healthcheck": {"$ref": "#/definitions/healthcheck"},
"hostname": {"type": "string"},
"image": {"type": "string"},
"ipc": {"type": "string"},
"labels": {"$ref": "#/definitions/list_or_dict"},
"links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"logging": {
"type": "object",
"properties": {
"driver": {"type": "string"},
"options": {
"type": "object",
"patternProperties": {
"^.+$": {"type": ["string", "number", "null"]}
}
}
},
"additionalProperties": false
},
"mac_address": {"type": "string"},
"network_mode": {"type": "string"},
"networks": {
"oneOf": [
{"$ref": "#/definitions/list_of_strings"},
{
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9._-]+$": {
"oneOf": [
{
"type": "object",
"properties": {
"aliases": {"$ref": "#/definitions/list_of_strings"},
"ipv4_address": {"type": "string"},
"ipv6_address": {"type": "string"}
},
"additionalProperties": false
},
{"type": "null"}
]
}
},
"additionalProperties": false
}
]
},
"pid": {"type": ["string", "null"]},
"ports": {
"type": "array",
"items": {
"oneOf": [
{"type": "number", "format": "ports"},
{"type": "string", "format": "ports"},
{
"type": "object",
"properties": {
"mode": {"type": "string"},
"target": {"type": "integer"},
"published": {"type": "integer"},
"protocol": {"type": "string"}
},
"additionalProperties": false
}
]
},
"uniqueItems": true
},
"privileged": {"type": "boolean"},
"read_only": {"type": "boolean"},
"restart": {"type": "string"},
"security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
"shm_size": {"type": ["number", "string"]},
"secrets": {
"type": "array",
"items": {
"oneOf": [
{"type": "string"},
{
"type": "object",
"properties": {
"source": {"type": "string"},
"target": {"type": "string"},
"uid": {"type": "string"},
"gid": {"type": "string"},
"mode": {"type": "number"}
}
}
]
}
},
"sysctls": {"$ref": "#/definitions/list_or_dict"},
"stdin_open": {"type": "boolean"},
"stop_grace_period": {"type": "string", "format": "duration"},
"stop_signal": {"type": "string"},
"tmpfs": {"$ref": "#/definitions/string_or_list"},
"tty": {"type": "boolean"},
"ulimits": {
"type": "object",
"patternProperties": {
"^[a-z]+$": {
"oneOf": [
{"type": "integer"},
{
"type":"object",
"properties": {
"hard": {"type": "integer"},
"soft": {"type": "integer"}
},
"required": ["soft", "hard"],
"additionalProperties": false
}
]
}
}
},
"user": {"type": "string"},
"userns_mode": {"type": "string"},
"volumes": {
"type": "array",
"items": {
"oneOf": [
{"type": "string"},
{
"type": "object",
"required": ["type"],
"properties": {
"type": {"type": "string"},
"source": {"type": "string"},
"target": {"type": "string"},
"read_only": {"type": "boolean"},
"bind": {
"type": "object",
"properties": {
"propagation": {"type": "string"}
}
},
"volume": {
"type": "object",
"properties": {
"nocopy": {"type": "boolean"}
}
}
}
}
],
"uniqueItems": true
}
},
"working_dir": {"type": "string"}
},
"additionalProperties": false
},
"healthcheck": {
"id": "#/definitions/healthcheck",
"type": "object",
"additionalProperties": false,
"properties": {
"disable": {"type": "boolean"},
"interval": {"type": "string"},
"retries": {"type": "number"},
"test": {
"oneOf": [
{"type": "string"},
{"type": "array", "items": {"type": "string"}}
]
},
"timeout": {"type": "string"}
}
},
"deployment": {
"id": "#/definitions/deployment",
"type": ["object", "null"],
"properties": {
"mode": {"type": "string"},
"endpoint_mode": {"type": "string"},
"replicas": {"type": "integer"},
"labels": {"$ref": "#/definitions/list_or_dict"},
"update_config": {
"type": "object",
"properties": {
"parallelism": {"type": "integer"},
"delay": {"type": "string", "format": "duration"},
"failure_action": {"type": "string"},
"monitor": {"type": "string", "format": "duration"},
"max_failure_ratio": {"type": "number"}
},
"additionalProperties": false
},
"resources": {
"type": "object",
"properties": {
"limits": {"$ref": "#/definitions/resource"},
"reservations": {"$ref": "#/definitions/resource"}
}
},
"restart_policy": {
"type": "object",
"properties": {
"condition": {"type": "string"},
"delay": {"type": "string", "format": "duration"},
"max_attempts": {"type": "integer"},
"window": {"type": "string", "format": "duration"}
},
"additionalProperties": false
},
"placement": {
"type": "object",
"properties": {
"constraints": {"type": "array", "items": {"type": "string"}}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"resource": {
"id": "#/definitions/resource",
"type": "object",
"properties": {
"cpus": {"type": "string"},
"memory": {"type": "string"}
},
"additionalProperties": false
},
"network": {
"id": "#/definitions/network",
"type": ["object", "null"],
"properties": {
"driver": {"type": "string"},
"driver_opts": {
"type": "object",
"patternProperties": {
"^.+$": {"type": ["string", "number"]}
}
},
"ipam": {
"type": "object",
"properties": {
"driver": {"type": "string"},
"config": {
"type": "array",
"items": {
"type": "object",
"properties": {
"subnet": {"type": "string"}
},
"additionalProperties": false
}
}
},
"additionalProperties": false
},
"external": {
"type": ["boolean", "object"],
"properties": {
"name": {"type": "string"}
},
"additionalProperties": false
},
"internal": {"type": "boolean"},
"attachable": {"type": "boolean"},
"labels": {"$ref": "#/definitions/list_or_dict"}
},
"additionalProperties": false
},
"volume": {
"id": "#/definitions/volume",
"type": ["object", "null"],
"properties": {
"driver": {"type": "string"},
"driver_opts": {
"type": "object",
"patternProperties": {
"^.+$": {"type": ["string", "number"]}
}
},
"external": {
"type": ["boolean", "object"],
"properties": {
"name": {"type": "string"}
},
"additionalProperties": false
},
"labels": {"$ref": "#/definitions/list_or_dict"}
},
"additionalProperties": false
},
"secret": {
"id": "#/definitions/secret",
"type": "object",
"properties": {
"file": {"type": "string"},
"external": {
"type": ["boolean", "object"],
"properties": {
"name": {"type": "string"}
}
},
"labels": {"$ref": "#/definitions/list_or_dict"}
},
"additionalProperties": false
},
"string_or_list": {
"oneOf": [
{"type": "string"},
{"$ref": "#/definitions/list_of_strings"}
]
},
"list_of_strings": {
"type": "array",
"items": {"type": "string"},
"uniqueItems": true
},
"list_or_dict": {
"oneOf": [
{
"type": "object",
"patternProperties": {
".+": {
"type": ["string", "number", "null"]
}
},
"additionalProperties": false
},
{"type": "array", "items": {"type": "string"}, "uniqueItems": true}
]
},
"constraints": {
"service": {
"id": "#/definitions/constraints/service",
"anyOf": [
{"required": ["build"]},
{"required": ["image"]}
],
"properties": {
"build": {
"required": ["context"]
}
}
}
}
}
}

View file

@ -156,6 +156,7 @@ type DeployConfig struct {
Resources Resources Resources Resources
RestartPolicy *RestartPolicy `mapstructure:"restart_policy"` RestartPolicy *RestartPolicy `mapstructure:"restart_policy"`
Placement Placement Placement Placement
EndpointMode string
} }
// HealthCheckConfig the healthcheck configuration for a service // HealthCheckConfig the healthcheck configuration for a service