浏览代码

Add an integration test for secrets using bind mounts.

Signed-off-by: Daniel Nephin <[email protected]>
Daniel Nephin 8 年之前
父节点
当前提交
4053adc7d3
共有 4 个文件被更改,包括 86 次插入58 次删除
  1. 1 1
      compose/project.py
  2. 1 0
      tests/fixtures/secrets/default
  3. 79 53
      tests/integration/project_test.py
  4. 5 4
      tests/integration/testcases.py

+ 1 - 1
compose/project.py

@@ -106,7 +106,7 @@ class Project(object):
 
             secrets = get_secrets(
                 service_dict['name'],
-                service_dict.get('secrets') or [],
+                service_dict.pop('secrets', None) or [],
                 config_data.secrets)
 
             project.services.append(

+ 1 - 0
tests/fixtures/secrets/default

@@ -0,0 +1 @@
+This is the secret

+ 79 - 53
tests/integration/project_test.py

@@ -1,6 +1,7 @@
 from __future__ import absolute_import
 from __future__ import unicode_literals
 
+import os.path
 import random
 
 import py
@@ -8,12 +9,14 @@ import pytest
 from docker.errors import NotFound
 
 from .. import mock
-from ..helpers import build_config
+from ..helpers import build_config as load_config
 from .testcases import DockerClientTestCase
 from compose.config import config
 from compose.config import ConfigurationError
+from compose.config import types
 from compose.config.config import V2_0
 from compose.config.config import V2_1
+from compose.config.config import V3_1
 from compose.config.types import VolumeFromSpec
 from compose.config.types import VolumeSpec
 from compose.const import LABEL_PROJECT
@@ -26,6 +29,16 @@ from compose.project import ProjectError
 from compose.service import ConvergenceStrategy
 from tests.integration.testcases import v2_1_only
 from tests.integration.testcases import v2_only
+from tests.integration.testcases import v3_only
+
+
+def build_config(**kwargs):
+    return config.Config(
+        version=kwargs.get('version'),
+        services=kwargs.get('services'),
+        volumes=kwargs.get('volumes'),
+        networks=kwargs.get('networks'),
+        secrets=kwargs.get('secrets'))
 
 
 class ProjectTest(DockerClientTestCase):
@@ -70,7 +83,7 @@ class ProjectTest(DockerClientTestCase):
     def test_volumes_from_service(self):
         project = Project.from_config(
             name='composetest',
-            config_data=build_config({
+            config_data=load_config({
                 'data': {
                     'image': 'busybox:latest',
                     'volumes': ['/var/data'],
@@ -96,7 +109,7 @@ class ProjectTest(DockerClientTestCase):
         )
         project = Project.from_config(
             name='composetest',
-            config_data=build_config({
+            config_data=load_config({
                 'db': {
                     'image': 'busybox:latest',
                     'volumes_from': ['composetest_data_container'],
@@ -112,7 +125,7 @@ class ProjectTest(DockerClientTestCase):
         project = Project.from_config(
             name='composetest',
             client=self.client,
-            config_data=build_config({
+            config_data=load_config({
                 'version': V2_0,
                 'services': {
                     'net': {
@@ -139,7 +152,7 @@ class ProjectTest(DockerClientTestCase):
         def get_project():
             return Project.from_config(
                 name='composetest',
-                config_data=build_config({
+                config_data=load_config({
                     'version': V2_0,
                     'services': {
                         'web': {
@@ -174,7 +187,7 @@ class ProjectTest(DockerClientTestCase):
     def test_net_from_service_v1(self):
         project = Project.from_config(
             name='composetest',
-            config_data=build_config({
+            config_data=load_config({
                 'net': {
                     'image': 'busybox:latest',
                     'command': ["top"]
@@ -198,7 +211,7 @@ class ProjectTest(DockerClientTestCase):
         def get_project():
             return Project.from_config(
                 name='composetest',
-                config_data=build_config({
+                config_data=load_config({
                     'web': {
                         'image': 'busybox:latest',
                         'net': 'container:composetest_net_container'
@@ -469,7 +482,7 @@ class ProjectTest(DockerClientTestCase):
     def test_project_up_starts_depends(self):
         project = Project.from_config(
             name='composetest',
-            config_data=build_config({
+            config_data=load_config({
                 'console': {
                     'image': 'busybox:latest',
                     'command': ["top"],
@@ -504,7 +517,7 @@ class ProjectTest(DockerClientTestCase):
     def test_project_up_with_no_deps(self):
         project = Project.from_config(
             name='composetest',
-            config_data=build_config({
+            config_data=load_config({
                 'console': {
                     'image': 'busybox:latest',
                     'command': ["top"],
@@ -564,7 +577,7 @@ class ProjectTest(DockerClientTestCase):
 
     @v2_only()
     def test_project_up_networks(self):
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -576,7 +589,6 @@ class ProjectTest(DockerClientTestCase):
                     'baz': {'aliases': ['extra']},
                 },
             }],
-            volumes={},
             networks={
                 'foo': {'driver': 'bridge'},
                 'bar': {'driver': None},
@@ -610,14 +622,13 @@ class ProjectTest(DockerClientTestCase):
 
     @v2_only()
     def test_up_with_ipam_config(self):
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
                 'image': 'busybox:latest',
                 'networks': {'front': None},
             }],
-            volumes={},
             networks={
                 'front': {
                     'driver': 'bridge',
@@ -671,7 +682,7 @@ class ProjectTest(DockerClientTestCase):
 
     @v2_only()
     def test_up_with_network_static_addresses(self):
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -684,7 +695,6 @@ class ProjectTest(DockerClientTestCase):
                     }
                 },
             }],
-            volumes={},
             networks={
                 'static_test': {
                     'driver': 'bridge',
@@ -726,7 +736,7 @@ class ProjectTest(DockerClientTestCase):
     @v2_1_only()
     def test_up_with_enable_ipv6(self):
         self.require_api_version('1.23')
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -738,7 +748,6 @@ class ProjectTest(DockerClientTestCase):
                     }
                 },
             }],
-            volumes={},
             networks={
                 'static_test': {
                     'driver': 'bridge',
@@ -770,7 +779,7 @@ class ProjectTest(DockerClientTestCase):
 
     @v2_only()
     def test_up_with_network_static_addresses_missing_subnet(self):
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -782,7 +791,6 @@ class ProjectTest(DockerClientTestCase):
                     }
                 },
             }],
-            volumes={},
             networks={
                 'static_test': {
                     'driver': 'bridge',
@@ -807,7 +815,7 @@ class ProjectTest(DockerClientTestCase):
 
     @v2_1_only()
     def test_up_with_network_link_local_ips(self):
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_1,
             services=[{
                 'name': 'web',
@@ -818,7 +826,6 @@ class ProjectTest(DockerClientTestCase):
                     }
                 }
             }],
-            volumes={},
             networks={
                 'linklocaltest': {'driver': 'bridge'}
             }
@@ -844,15 +851,13 @@ class ProjectTest(DockerClientTestCase):
     @v2_1_only()
     def test_up_with_isolation(self):
         self.require_api_version('1.24')
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_1,
             services=[{
                 'name': 'web',
                 'image': 'busybox:latest',
                 'isolation': 'default'
             }],
-            volumes={},
-            networks={}
         )
         project = Project.from_config(
             client=self.client,
@@ -866,15 +871,13 @@ class ProjectTest(DockerClientTestCase):
     @v2_1_only()
     def test_up_with_invalid_isolation(self):
         self.require_api_version('1.24')
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_1,
             services=[{
                 'name': 'web',
                 'image': 'busybox:latest',
                 'isolation': 'foobar'
             }],
-            volumes={},
-            networks={}
         )
         project = Project.from_config(
             client=self.client,
@@ -887,14 +890,13 @@ class ProjectTest(DockerClientTestCase):
     @v2_only()
     def test_project_up_with_network_internal(self):
         self.require_api_version('1.23')
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
                 'image': 'busybox:latest',
                 'networks': {'internal': None},
             }],
-            volumes={},
             networks={
                 'internal': {'driver': 'bridge', 'internal': True},
             },
@@ -917,14 +919,13 @@ class ProjectTest(DockerClientTestCase):
 
         network_name = 'network_with_label'
 
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
                 'image': 'busybox:latest',
                 'networks': {network_name: None}
             }],
-            volumes={},
             networks={
                 network_name: {'labels': {'label_key': 'label_val'}}
             }
@@ -951,7 +952,7 @@ class ProjectTest(DockerClientTestCase):
     def test_project_up_volumes(self):
         vol_name = '{0:x}'.format(random.getrandbits(32))
         full_vol_name = 'composetest_{0}'.format(vol_name)
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -959,7 +960,6 @@ class ProjectTest(DockerClientTestCase):
                 'command': 'top'
             }],
             volumes={vol_name: {'driver': 'local'}},
-            networks={},
         )
 
         project = Project.from_config(
@@ -979,7 +979,7 @@ class ProjectTest(DockerClientTestCase):
 
         volume_name = 'volume_with_label'
 
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -993,7 +993,6 @@ class ProjectTest(DockerClientTestCase):
                     }
                 }
             },
-            networks={},
         )
 
         project = Project.from_config(
@@ -1106,7 +1105,7 @@ class ProjectTest(DockerClientTestCase):
     def test_initialize_volumes(self):
         vol_name = '{0:x}'.format(random.getrandbits(32))
         full_vol_name = 'composetest_{0}'.format(vol_name)
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -1114,7 +1113,6 @@ class ProjectTest(DockerClientTestCase):
                 'command': 'top'
             }],
             volumes={vol_name: {}},
-            networks={},
         )
 
         project = Project.from_config(
@@ -1124,14 +1122,14 @@ class ProjectTest(DockerClientTestCase):
         project.volumes.initialize()
 
         volume_data = self.client.inspect_volume(full_vol_name)
-        self.assertEqual(volume_data['Name'], full_vol_name)
-        self.assertEqual(volume_data['Driver'], 'local')
+        assert volume_data['Name'] == full_vol_name
+        assert volume_data['Driver'] == 'local'
 
     @v2_only()
     def test_project_up_implicit_volume_driver(self):
         vol_name = '{0:x}'.format(random.getrandbits(32))
         full_vol_name = 'composetest_{0}'.format(vol_name)
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -1139,7 +1137,6 @@ class ProjectTest(DockerClientTestCase):
                 'command': 'top'
             }],
             volumes={vol_name: {}},
-            networks={},
         )
 
         project = Project.from_config(
@@ -1152,11 +1149,45 @@ class ProjectTest(DockerClientTestCase):
         self.assertEqual(volume_data['Name'], full_vol_name)
         self.assertEqual(volume_data['Driver'], 'local')
 
+    @v3_only()
+    def test_project_up_with_secrets(self):
+        config_data = build_config(
+            version=V3_1,
+            services=[{
+                'name': 'web',
+                'image': 'busybox:latest',
+                'command': 'cat /run/secrets/special',
+                'secrets': [
+                    types.ServiceSecret.parse({'source': 'super', 'target': 'special'}),
+                ],
+            }],
+            secrets={
+                'super': {
+                    'file': os.path.abspath('tests/fixtures/secrets/default'),
+                },
+            },
+        )
+
+        project = Project.from_config(
+            client=self.client,
+            name='composetest',
+            config_data=config_data,
+        )
+        project.up()
+        project.stop()
+
+        containers = project.containers(stopped=True)
+        assert len(containers) == 1
+        container, = containers
+
+        output = container.logs()
+        assert output == "This is the secret\n"
+
     @v2_only()
     def test_initialize_volumes_invalid_volume_driver(self):
         vol_name = '{0:x}'.format(random.getrandbits(32))
 
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -1164,7 +1195,6 @@ class ProjectTest(DockerClientTestCase):
                 'command': 'top'
             }],
             volumes={vol_name: {'driver': 'foobar'}},
-            networks={},
         )
 
         project = Project.from_config(
@@ -1179,7 +1209,7 @@ class ProjectTest(DockerClientTestCase):
         vol_name = '{0:x}'.format(random.getrandbits(32))
         full_vol_name = 'composetest_{0}'.format(vol_name)
 
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -1187,7 +1217,6 @@ class ProjectTest(DockerClientTestCase):
                 'command': 'top'
             }],
             volumes={vol_name: {'driver': 'local'}},
-            networks={},
         )
         project = Project.from_config(
             name='composetest',
@@ -1218,7 +1247,7 @@ class ProjectTest(DockerClientTestCase):
         vol_name = '{0:x}'.format(random.getrandbits(32))
         full_vol_name = 'composetest_{0}'.format(vol_name)
 
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -1226,7 +1255,6 @@ class ProjectTest(DockerClientTestCase):
                 'command': 'top'
             }],
             volumes={vol_name: {'driver': 'local'}},
-            networks={},
         )
         project = Project.from_config(
             name='composetest',
@@ -1257,7 +1285,7 @@ class ProjectTest(DockerClientTestCase):
         vol_name = 'composetest_{0:x}'.format(random.getrandbits(32))
         full_vol_name = 'composetest_{0}'.format(vol_name)
         self.client.create_volume(vol_name)
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -1267,7 +1295,6 @@ class ProjectTest(DockerClientTestCase):
             volumes={
                 vol_name: {'external': True, 'external_name': vol_name}
             },
-            networks=None,
         )
         project = Project.from_config(
             name='composetest',
@@ -1282,7 +1309,7 @@ class ProjectTest(DockerClientTestCase):
     def test_initialize_volumes_inexistent_external_volume(self):
         vol_name = '{0:x}'.format(random.getrandbits(32))
 
-        config_data = config.Config(
+        config_data = build_config(
             version=V2_0,
             services=[{
                 'name': 'web',
@@ -1292,7 +1319,6 @@ class ProjectTest(DockerClientTestCase):
             volumes={
                 vol_name: {'external': True, 'external_name': vol_name}
             },
-            networks=None,
         )
         project = Project.from_config(
             name='composetest',
@@ -1349,7 +1375,7 @@ class ProjectTest(DockerClientTestCase):
             }
         }
 
-        config_data = build_config(config_dict)
+        config_data = load_config(config_dict)
         project = Project.from_config(
             name='composetest', config_data=config_data, client=self.client
         )
@@ -1357,7 +1383,7 @@ class ProjectTest(DockerClientTestCase):
         config_dict['service2'] = config_dict['service1']
         del config_dict['service1']
 
-        config_data = build_config(config_dict)
+        config_data = load_config(config_dict)
         project = Project.from_config(
             name='composetest', config_data=config_data, client=self.client
         )

+ 5 - 4
tests/integration/testcases.py

@@ -41,9 +41,9 @@ def engine_max_version():
     version = os.environ['DOCKER_VERSION'].partition('-')[0]
     if version_lt(version, '1.10'):
         return V1
-    elif version_lt(version, '1.12'):
+    if version_lt(version, '1.12'):
         return V2_0
-    elif version_lt(version, '1.13'):
+    if version_lt(version, '1.13'):
         return V2_1
     return V3_0
 
@@ -52,8 +52,9 @@ def build_version_required_decorator(ignored_versions):
     def decorator(f):
         @functools.wraps(f)
         def wrapper(self, *args, **kwargs):
-            if engine_max_version() in ignored_versions:
-                skip("Engine version is too low")
+            max_version = engine_max_version()
+            if max_version in ignored_versions:
+                skip("Engine version %s is too low" % max_version)
                 return
             return f(self, *args, **kwargs)
         return wrapper