소스 검색

Merge pull request #2626 from shin-/dbonev-2503-move-logging-config-under-separate-key

Move logging config under separate key in v2 compose files
Aanand Prasad 9 년 전
부모
커밋
52e50a9d9a

+ 16 - 3
compose/config/config.py

@@ -51,8 +51,6 @@ DOCKER_CONFIG_KEYS = [
     'ipc',
     'labels',
     'links',
-    'log_driver',
-    'log_opt',
     'mac_address',
     'mem_limit',
     'memswap_limit',
@@ -78,6 +76,7 @@ ALLOWED_KEYS = DOCKER_CONFIG_KEYS + [
     'dockerfile',
     'expose',
     'external_links',
+    'logging',
 ]
 
 DOCKER_VALID_URL_PREFIXES = (
@@ -288,7 +287,7 @@ def load_services(working_dir, config_files, version):
         service_dict = process_service(resolver.run())
 
         # TODO: move to validate_service()
-        validate_against_service_schema(service_dict, service_config.name)
+        validate_against_service_schema(service_dict, service_config.name, version)
         validate_paths(service_dict)
 
         service_dict = finalize_service(service_config._replace(config=service_dict))
@@ -505,6 +504,20 @@ def finalize_service(service_config):
     if 'restart' in service_dict:
         service_dict['restart'] = parse_restart_spec(service_dict['restart'])
 
+    return normalize_v1_service_format(service_dict)
+
+
+def normalize_v1_service_format(service_dict):
+    if 'log_driver' in service_dict or 'log_opt' in service_dict:
+        if 'logging' not in service_dict:
+            service_dict['logging'] = {}
+        if 'log_driver' in service_dict:
+            service_dict['logging']['driver'] = service_dict['log_driver']
+            del service_dict['log_driver']
+        if 'log_opt' in service_dict:
+            service_dict['logging']['options'] = service_dict['log_opt']
+            del service_dict['log_opt']
+
     return service_dict
 
 

+ 2 - 152
compose/config/fields_schema_v1.json

@@ -6,158 +6,8 @@
 
   "patternProperties": {
     "^[a-zA-Z0-9._-]+$": {
-      "$ref": "#/definitions/service"
+      "$ref": "service_schema_v1.json#/definitions/service"
     }
   },
-  "additionalProperties": false,
-
-  "definitions": {
-    "service": {
-      "id": "#/definitions/service",
-      "type": "object",
-
-      "properties": {
-        "build": {"type": "string"},
-        "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"},
-        "cpu_shares": {"type": ["number", "string"]},
-        "cpu_quota": {"type": ["number", "string"]},
-        "cpuset": {"type": "string"},
-        "devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
-        "dns": {"$ref": "#/definitions/string_or_list"},
-        "dns_search": {"$ref": "#/definitions/string_or_list"},
-        "dockerfile": {"type": "string"},
-        "domainname": {"type": "string"},
-        "entrypoint": {"$ref": "#/definitions/string_or_list"},
-        "env_file": {"$ref": "#/definitions/string_or_list"},
-        "environment": {"$ref": "#/definitions/list_or_dict"},
-
-        "expose": {
-          "type": "array",
-          "items": {
-            "type": ["string", "number"],
-            "format": "expose"
-          },
-          "uniqueItems": true
-        },
-
-        "extends": {
-          "oneOf": [
-            {
-              "type": "string"
-            },
-            {
-              "type": "object",
-
-              "properties": {
-                "service": {"type": "string"},
-                "file": {"type": "string"}
-              },
-              "required": ["service"],
-              "additionalProperties": false
-            }
-          ]
-        },
-
-        "extra_hosts": {"$ref": "#/definitions/list_or_dict"},
-        "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
-        "hostname": {"type": "string"},
-        "image": {"type": "string"},
-        "ipc": {"type": "string"},
-        "labels": {"$ref": "#/definitions/list_or_dict"},
-        "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
-
-        "log_driver": {"type": "string"},
-        "log_opt": {"type": "object"},
-
-        "mac_address": {"type": "string"},
-        "mem_limit": {"type": ["number", "string"]},
-        "memswap_limit": {"type": ["number", "string"]},
-        "net": {"type": "string"},
-        "pid": {"type": ["string", "null"]},
-
-        "ports": {
-          "type": "array",
-          "items": {
-            "type": ["string", "number"],
-            "format": "ports"
-          },
-          "uniqueItems": true
-        },
-
-        "privileged": {"type": "boolean"},
-        "read_only": {"type": "boolean"},
-        "restart": {"type": "string"},
-        "security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
-        "stdin_open": {"type": "boolean"},
-        "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"},
-        "volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
-        "volume_driver": {"type": "string"},
-        "volumes_from": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
-        "working_dir": {"type": "string"}
-      },
-
-      "dependencies": {
-        "memswap_limit": ["mem_limit"]
-      },
-      "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", "boolean", "null"],
-              "format": "bool-value-in-mapping"
-            }
-          },
-          "additionalProperties": false
-        },
-        {"type": "array", "items": {"type": "string"}, "uniqueItems": true}
-      ]
-    }
-  }
+  "additionalProperties": false
 }

+ 1 - 1
compose/config/fields_schema_v2.json

@@ -12,7 +12,7 @@
       "type": "object",
       "patternProperties": {
         "^[a-zA-Z0-9._-]+$": {
-          "$ref": "fields_schema_v1.json#/definitions/service"
+          "$ref": "service_schema_v2.json#/definitions/service"
         }
       },
       "additionalProperties": false

+ 0 - 30
compose/config/service_schema.json

@@ -1,30 +0,0 @@
-{
-  "$schema": "http://json-schema.org/draft-04/schema#",
-  "id": "service_schema.json",
-
-  "type": "object",
-
-  "allOf": [
-    {"$ref": "fields_schema_v1.json#/definitions/service"},
-    {"$ref": "#/definitions/constraints"}
-  ],
-
-  "definitions": {
-    "constraints": {
-      "id": "#/definitions/constraints",
-      "anyOf": [
-        {
-          "required": ["build"],
-          "not": {"required": ["image"]}
-        },
-        {
-          "required": ["image"],
-          "not": {"anyOf": [
-            {"required": ["build"]},
-            {"required": ["dockerfile"]}
-          ]}
-        }
-      ]
-    }
-  }
-}

+ 175 - 0
compose/config/service_schema_v1.json

@@ -0,0 +1,175 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "id": "service_schema_v1.json",
+
+  "type": "object",
+
+  "allOf": [
+    {"$ref": "#/definitions/service"},
+    {"$ref": "#/definitions/constraints"}
+  ],
+
+  "definitions": {
+    "service": {
+      "id": "#/definitions/service",
+      "type": "object",
+
+      "properties": {
+        "build": {"type": "string"},
+        "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"},
+        "cpu_shares": {"type": ["number", "string"]},
+        "cpu_quota": {"type": ["number", "string"]},
+        "cpuset": {"type": "string"},
+        "devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "dns": {"$ref": "#/definitions/string_or_list"},
+        "dns_search": {"$ref": "#/definitions/string_or_list"},
+        "dockerfile": {"type": "string"},
+        "domainname": {"type": "string"},
+        "entrypoint": {"$ref": "#/definitions/string_or_list"},
+        "env_file": {"$ref": "#/definitions/string_or_list"},
+        "environment": {"$ref": "#/definitions/list_or_dict"},
+
+        "expose": {
+          "type": "array",
+          "items": {
+            "type": ["string", "number"],
+            "format": "expose"
+          },
+          "uniqueItems": true
+        },
+
+        "extends": {
+          "oneOf": [
+            {
+              "type": "string"
+            },
+            {
+              "type": "object",
+
+              "properties": {
+                "service": {"type": "string"},
+                "file": {"type": "string"}
+              },
+              "required": ["service"],
+              "additionalProperties": false
+            }
+          ]
+        },
+
+        "extra_hosts": {"$ref": "#/definitions/list_or_dict"},
+        "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "hostname": {"type": "string"},
+        "image": {"type": "string"},
+        "ipc": {"type": "string"},
+        "labels": {"$ref": "#/definitions/list_or_dict"},
+        "links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "log_driver": {"type": "string"},
+        "log_opt": {"type": "object"},
+        "mac_address": {"type": "string"},
+        "mem_limit": {"type": ["number", "string"]},
+        "memswap_limit": {"type": ["number", "string"]},
+        "net": {"type": "string"},
+        "pid": {"type": ["string", "null"]},
+
+        "ports": {
+          "type": "array",
+          "items": {
+            "type": ["string", "number"],
+            "format": "ports"
+          },
+          "uniqueItems": true
+        },
+
+        "privileged": {"type": "boolean"},
+        "read_only": {"type": "boolean"},
+        "restart": {"type": "string"},
+        "security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "stdin_open": {"type": "boolean"},
+        "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"},
+        "volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "volume_driver": {"type": "string"},
+        "volumes_from": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "working_dir": {"type": "string"}
+      },
+
+      "dependencies": {
+        "memswap_limit": ["mem_limit"]
+      },
+      "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", "boolean", "null"],
+              "format": "bool-value-in-mapping"
+            }
+          },
+          "additionalProperties": false
+        },
+        {"type": "array", "items": {"type": "string"}, "uniqueItems": true}
+      ]
+    },
+    "constraints": {
+      "id": "#/definitions/constraints",
+      "anyOf": [
+        {
+          "required": ["build"],
+          "not": {"required": ["image"]}
+        },
+        {
+          "required": ["image"],
+          "not": {"anyOf": [
+            {"required": ["build"]},
+            {"required": ["dockerfile"]}
+          ]}
+        }
+      ]
+    }
+  }
+}

+ 184 - 0
compose/config/service_schema_v2.json

@@ -0,0 +1,184 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "id": "service_schema_v2.json",
+
+  "type": "object",
+
+  "allOf": [
+    {"$ref": "#/definitions/service"},
+    {"$ref": "#/definitions/constraints"}
+  ],
+
+  "definitions": {
+    "service": {
+      "id": "#/definitions/service",
+      "type": "object",
+
+      "properties": {
+        "build": {"type": "string"},
+        "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"},
+        "cpu_shares": {"type": ["number", "string"]},
+        "cpu_quota": {"type": ["number", "string"]},
+        "cpuset": {"type": "string"},
+        "devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "dns": {"$ref": "#/definitions/string_or_list"},
+        "dns_search": {"$ref": "#/definitions/string_or_list"},
+        "dockerfile": {"type": "string"},
+        "domainname": {"type": "string"},
+        "entrypoint": {"$ref": "#/definitions/string_or_list"},
+        "env_file": {"$ref": "#/definitions/string_or_list"},
+        "environment": {"$ref": "#/definitions/list_or_dict"},
+
+        "expose": {
+          "type": "array",
+          "items": {
+            "type": ["string", "number"],
+            "format": "expose"
+          },
+          "uniqueItems": true
+        },
+
+        "extends": {
+          "oneOf": [
+            {
+              "type": "string"
+            },
+            {
+              "type": "object",
+
+              "properties": {
+                "service": {"type": "string"},
+                "file": {"type": "string"}
+              },
+              "required": ["service"],
+              "additionalProperties": false
+            }
+          ]
+        },
+
+        "extra_hosts": {"$ref": "#/definitions/list_or_dict"},
+        "external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "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"}
+            },
+            "additionalProperties": false
+        },
+
+        "mac_address": {"type": "string"},
+        "mem_limit": {"type": ["number", "string"]},
+        "memswap_limit": {"type": ["number", "string"]},
+        "net": {"type": "string"},
+        "pid": {"type": ["string", "null"]},
+
+        "ports": {
+          "type": "array",
+          "items": {
+            "type": ["string", "number"],
+            "format": "ports"
+          },
+          "uniqueItems": true
+        },
+
+        "privileged": {"type": "boolean"},
+        "read_only": {"type": "boolean"},
+        "restart": {"type": "string"},
+        "security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "stdin_open": {"type": "boolean"},
+        "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"},
+        "volumes": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "volume_driver": {"type": "string"},
+        "volumes_from": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
+        "working_dir": {"type": "string"}
+      },
+
+      "dependencies": {
+        "memswap_limit": ["mem_limit"]
+      },
+      "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", "boolean", "null"],
+              "format": "bool-value-in-mapping"
+            }
+          },
+          "additionalProperties": false
+        },
+        {"type": "array", "items": {"type": "string"}, "uniqueItems": true}
+      ]
+    },
+    "constraints": {
+      "id": "#/definitions/constraints",
+      "anyOf": [
+        {
+          "required": ["build"],
+          "not": {"required": ["image"]}
+        },
+        {
+          "required": ["image"],
+          "not": {"anyOf": [
+            {"required": ["build"]},
+            {"required": ["dockerfile"]}
+          ]}
+        }
+      ]
+    }
+  }
+}

+ 2 - 2
compose/config/validation.py

@@ -298,10 +298,10 @@ def validate_against_fields_schema(config, filename, version):
         filename=filename)
 
 
-def validate_against_service_schema(config, service_name):
+def validate_against_service_schema(config, service_name, version):
     _validate_against_schema(
         config,
-        "service_schema.json",
+        "service_schema_v{0}.json".format(version),
         format_checker=["ports"],
         service_name=service_name)
 

+ 12 - 4
compose/service.py

@@ -590,10 +590,9 @@ class Service(object):
     def _get_container_host_config(self, override_options, one_off=False):
         options = dict(self.options, **override_options)
 
-        log_config = LogConfig(
-            type=options.get('log_driver', ""),
-            config=options.get('log_opt', None)
-        )
+        logging_dict = options.get('logging', None)
+        log_config = get_log_config(logging_dict)
+
         return self.client.create_host_config(
             links=self._get_links(link_to_self=one_off),
             port_bindings=build_port_bindings(options.get('ports') or []),
@@ -954,3 +953,12 @@ def build_ulimits(ulimit_config):
             ulimits.append(ulimit_dict)
 
     return ulimits
+
+
+def get_log_config(logging_dict):
+    log_driver = logging_dict.get('driver', "") if logging_dict else ""
+    log_options = logging_dict.get('options', None) if logging_dict else None
+    return LogConfig(
+        type=log_driver,
+        config=log_options
+    )

+ 7 - 2
docker-compose.spec

@@ -28,8 +28,13 @@ exe = EXE(pyz,
                 'DATA'
             ),
             (
-                'compose/config/service_schema.json',
-                'compose/config/service_schema.json',
+                'compose/config/service_schema_v1.json',
+                'compose/config/service_schema_v1.json',
+                'DATA'
+            ),
+            (
+                'compose/config/service_schema_v2.json',
+                'compose/config/service_schema_v2.json',
                 'DATA'
             ),
             (

+ 18 - 10
docs/compose-file.md

@@ -324,29 +324,37 @@ for this service, e.g:
 Environment variables will also be created - see the [environment variable
 reference](env.md) for details.
 
-### log_driver
+### logging
 
-Specify a logging driver for the service's containers, as with the ``--log-driver``
-option for docker run ([documented here](https://docs.docker.com/engine/reference/logging/overview/)).
+Logging configuration for the service. This configuration replaces the previous
+`log_driver` and `log_opt` keys.
+
+    logging:
+        driver: log_driver
+        options:
+            syslog-address: "tcp://192.168.0.42:123"
+
+The `driver`  name specifies a logging driver for the service's
+containers, as with the ``--log-driver`` option for docker run
+([documented here](https://docs.docker.com/engine/reference/logging/overview/)).
 
 The default value is json-file.
 
-    log_driver: "json-file"
-    log_driver: "syslog"
-    log_driver: "none"
+    driver: "json-file"
+    driver: "syslog"
+    driver: "none"
 
 > **Note:** Only the `json-file` driver makes the logs available directly from
 > `docker-compose up` and `docker-compose logs`. Using any other driver will not
 > print any logs.
 
-### log_opt
+Specify logging options for the logging driver with the ``options`` key, as with the ``--log-opt`` option for `docker run`.
 
-Specify logging options with `log_opt` for the logging driver, as with the ``--log-opt`` option for `docker run`.
 
 Logging options are key value pairs. An example of `syslog` options:
 
-    log_driver: "syslog"
-    log_opt:
+    driver: "syslog"
+    options:
       syslog-address: "tcp://192.168.0.42:123"
 
 ### net

+ 28 - 0
tests/acceptance/cli_test.py

@@ -718,6 +718,34 @@ class CLITestCase(DockerClientTestCase):
         result = self.dispatch(['start'], returncode=1)
         assert 'No containers to start' in result.stderr
 
+    def test_up_logging(self):
+        self.base_dir = 'tests/fixtures/logging-composefile'
+        self.dispatch(['up', '-d'])
+        simple = self.project.get_service('simple').containers()[0]
+        log_config = simple.get('HostConfig.LogConfig')
+        self.assertTrue(log_config)
+        self.assertEqual(log_config.get('Type'), 'none')
+
+        another = self.project.get_service('another').containers()[0]
+        log_config = another.get('HostConfig.LogConfig')
+        self.assertTrue(log_config)
+        self.assertEqual(log_config.get('Type'), 'json-file')
+        self.assertEqual(log_config.get('Config')['max-size'], '10m')
+
+    def test_up_logging_legacy(self):
+        self.base_dir = 'tests/fixtures/logging-composefile-legacy'
+        self.dispatch(['up', '-d'])
+        simple = self.project.get_service('simple').containers()[0]
+        log_config = simple.get('HostConfig.LogConfig')
+        self.assertTrue(log_config)
+        self.assertEqual(log_config.get('Type'), 'none')
+
+        another = self.project.get_service('another').containers()[0]
+        log_config = another.get('HostConfig.LogConfig')
+        self.assertTrue(log_config)
+        self.assertEqual(log_config.get('Type'), 'json-file')
+        self.assertEqual(log_config.get('Config')['max-size'], '10m')
+
     def test_pause_unpause(self):
         self.dispatch(['up', '-d'], None)
         service = self.project.get_service('simple')

+ 10 - 0
tests/fixtures/logging-composefile-legacy/docker-compose.yml

@@ -0,0 +1,10 @@
+simple:
+  image: busybox:latest
+  command: top
+  log_driver: "none"
+another:
+  image: busybox:latest
+  command: top
+  log_driver: "json-file"
+  log_opt:
+    max-size: "10m"

+ 14 - 0
tests/fixtures/logging-composefile/docker-compose.yml

@@ -0,0 +1,14 @@
+version: 2
+services:
+  simple:
+    image: busybox:latest
+    command: top
+    logging:
+      driver: "none"
+  another:
+    image: busybox:latest
+    command: top
+    logging:
+      driver: "json-file"
+      options:
+          max-size: "10m"

+ 53 - 0
tests/integration/project_test.py

@@ -3,6 +3,8 @@ from __future__ import unicode_literals
 
 import random
 
+import py
+
 from .testcases import DockerClientTestCase
 from compose.cli.docker_client import docker_client
 from compose.config import config
@@ -534,6 +536,57 @@ class ProjectTest(DockerClientTestCase):
         self.assertEqual(volume_data['Name'], full_vol_name)
         self.assertEqual(volume_data['Driver'], 'local')
 
+    def test_project_up_logging_with_multiple_files(self):
+        base_file = config.ConfigFile(
+            'base.yml',
+            {
+                'version': 2,
+                'services': {
+                    'simple': {'image': 'busybox:latest', 'command': 'top'},
+                    'another': {
+                        'image': 'busybox:latest',
+                        'command': 'top',
+                        'logging': {
+                            'driver': "json-file",
+                            'options': {
+                                'max-size': "10m"
+                            }
+                        }
+                    }
+                }
+
+            })
+        override_file = config.ConfigFile(
+            'override.yml',
+            {
+                'version': 2,
+                'services': {
+                    'another': {
+                        'logging': {
+                            'driver': "none"
+                        }
+                    }
+                }
+
+            })
+        details = config.ConfigDetails('.', [base_file, override_file])
+
+        tmpdir = py.test.ensuretemp('logging_test')
+        self.addCleanup(tmpdir.remove)
+        with tmpdir.as_cwd():
+            config_data = config.load(details)
+        project = Project.from_config(
+            name='composetest', config_data=config_data, client=self.client
+        )
+        project.up()
+        containers = project.containers()
+        self.assertEqual(len(containers), 2)
+
+        another = project.get_service('another').containers()[0]
+        log_config = another.get('HostConfig.LogConfig')
+        self.assertTrue(log_config)
+        self.assertEqual(log_config.get('Type'), 'none')
+
     def test_initialize_volumes(self):
         vol_name = '{0:x}'.format(random.getrandbits(32))
         full_vol_name = 'composetest_{0}'.format(vol_name)

+ 2 - 2
tests/integration/service_test.py

@@ -888,7 +888,7 @@ class ServiceTest(DockerClientTestCase):
         self.assertNotEqual(one_off_container.name, 'my-web-container')
 
     def test_log_drive_invalid(self):
-        service = self.create_service('web', log_driver='xxx')
+        service = self.create_service('web', logging={'driver': 'xxx'})
         expected_error_msg = "logger: no log driver named 'xxx' is registered"
 
         with self.assertRaisesRegexp(APIError, expected_error_msg):
@@ -902,7 +902,7 @@ class ServiceTest(DockerClientTestCase):
         self.assertFalse(log_config['Config'])
 
     def test_log_drive_none(self):
-        service = self.create_service('web', log_driver='none')
+        service = self.create_service('web', logging={'driver': 'none'})
         log_config = create_and_start_container(service).log_config
 
         self.assertEqual('none', log_config['Type'])

+ 2 - 1
tests/unit/service_test.py

@@ -156,7 +156,8 @@ class ServiceTest(unittest.TestCase):
         self.mock_client.create_host_config.return_value = {}
 
         log_opt = {'syslog-address': 'tcp://192.168.0.42:123'}
-        service = Service(name='foo', image='foo', hostname='name', client=self.mock_client, log_driver='syslog', log_opt=log_opt)
+        logging = {'driver': 'syslog', 'options': log_opt}
+        service = Service(name='foo', image='foo', hostname='name', client=self.mock_client, logging=logging)
         service._get_container_create_options({'some': 'overrides'}, 1)
 
         self.assertTrue(self.mock_client.create_host_config.called)