Add an integration test for secrets using bind mounts.

Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
Daniel Nephin 2017-01-05 14:54:35 -05:00
parent e0c6397999
commit 4053adc7d3
4 changed files with 86 additions and 58 deletions

View File

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

1
tests/fixtures/secrets/default vendored Normal file
View File

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

View File

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

View File

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