Browse Source

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

Compose file v3.2
Daniel Nephin 8 years ago
parent
commit
cd56476f18

+ 7 - 3
cli/compose/convert/service.go

@@ -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 {

+ 2 - 1
cli/compose/convert/service_test.go

@@ -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,

+ 12 - 6
cli/compose/loader/loader_test.go

@@ -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 it is too large
+ 1 - 0
cli/compose/schema/bindata.go


+ 3 - 46
cli/compose/schema/data/config_schema_v3.1.json

@@ -167,20 +167,8 @@
         "ports": {
         "ports": {
           "type": "array",
           "type": "array",
           "items": {
           "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
-              }
-            ]
+            "type": ["string", "number"],
+            "format": "ports"
           },
           },
           "uniqueItems": true
           "uniqueItems": true
         },
         },
@@ -235,37 +223,7 @@
         },
         },
         "user": {"type": "string"},
         "user": {"type": "string"},
         "userns_mode": {"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
-          }
-        },
+        "volumes": {"type": "array", "items": {"type": "string"}, "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

+ 473 - 0
cli/compose/schema/data/config_schema_v3.2.json

@@ -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"]
+          }
+        }
+      }
+    }
+  }
+}

+ 1 - 0
cli/compose/types/types.go

@@ -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

Some files were not shown because too many files changed in this diff