def test_project_platform_value(self): service_config = { 'name': 'web', 'image': 'busybox:latest', } config_data = Config( version=V2_4, services=[service_config], networks={}, volumes={}, secrets=None, configs=None ) project = Project.from_config(name='test', client=self.mock_client, config_data=config_data) assert project.get_service('web').platform is None project = Project.from_config( name='test', client=self.mock_client, config_data=config_data, default_platform='windows' ) assert project.get_service('web').platform == 'windows' service_config['platform'] = 'linux/s390x' project = Project.from_config(name='test', client=self.mock_client, config_data=config_data) assert project.get_service('web').platform == 'linux/s390x' project = Project.from_config( name='test', client=self.mock_client, config_data=config_data, default_platform='windows' ) assert project.get_service('web').platform == 'linux/s390x'
def test_project_up_updated_driver(self): vol_name = '{0:x}'.format(random.getrandbits(32)) full_vol_name = 'composetest_{0}'.format(vol_name) config_data = config.Config( version=2, services=[{ 'name': 'web', 'image': 'busybox:latest', 'command': 'top' }], volumes={vol_name: {'driver': 'local'}} ) project = Project.from_config( name='composetest', config_data=config_data, client=self.client ) project.initialize_volumes() volume_data = self.client.inspect_volume(full_vol_name) self.assertEqual(volume_data['Name'], full_vol_name) self.assertEqual(volume_data['Driver'], 'local') config_data = config_data._replace( volumes={vol_name: {'driver': 'smb'}} ) project = Project.from_config( name='composetest', config_data=config_data, client=self.client ) with self.assertRaises(config.ConfigurationError) as e: project.initialize_volumes() assert 'Configuration for volume {0} specifies driver smb'.format( vol_name ) in str(e.exception)
def test_use_net_from_service(self): container_name = 'test_aaa_1' self.mock_client.containers.return_value = [{ "Name": container_name, "Names": [container_name], "Id": container_name, "Image": 'busybox:latest' }] project = Project.from_config( name='test', client=self.mock_client, config_data=Config( version=None, services=[ { 'name': 'aaa', 'image': 'busybox:latest' }, { 'name': 'test', 'image': 'busybox:latest', 'network_mode': 'service:aaa' }, ], networks=None, volumes=None, ), ) service = project.get_service('test') self.assertEqual(service.network_mode.mode, 'container:' + container_name)
def test_run_interactive_passes_logs_false(self, mock_pseudo_terminal, mock_run_operation): mock_client = mock.create_autospec(docker.APIClient) project = Project.from_config( name='composetest', client=mock_client, config_data=build_config({ 'service': {'image': 'busybox'} }), ) command = TopLevelCommand(project) with pytest.raises(SystemExit): command.run({ 'SERVICE': 'service', 'COMMAND': None, '-e': [], '--user': None, '--no-deps': None, '-d': False, '-T': None, '--entrypoint': None, '--service-ports': None, '--publish': [], '--rm': None, '--name': None, '--workdir': None, }) _, _, call_kwargs = mock_run_operation.mock_calls[0] assert call_kwargs['logs'] is False
def test_project_up_with_network_internal(self): self.require_api_version('1.23') config_data = config.Config( version=V2_0, services=[{ 'name': 'web', 'image': 'busybox:latest', 'networks': {'internal': None}, }], volumes={}, networks={ 'internal': {'driver': 'bridge', 'internal': True}, }, ) project = Project.from_config( client=self.client, name='composetest', config_data=config_data, ) project.up() network = self.client.networks(names=['composetest_internal'])[0] assert network['Internal'] is True
def test_up_with_network_static_addresses_missing_subnet(self): config_data = config.Config( version=V2_0, services=[{ 'name': 'web', 'image': 'busybox:latest', 'networks': { 'static_test': { 'ipv4_address': '172.16.100.100', 'ipv6_address': 'fe80::1001:101' } }, }], volumes={}, networks={ 'static_test': { 'driver': 'bridge', 'driver_opts': { "com.docker.network.enable_ipv6": "true", }, 'ipam': { 'driver': 'default', }, }, }, ) project = Project.from_config( client=self.client, name='composetest', config_data=config_data, ) with self.assertRaises(ProjectError): project.up()
def test_project_up_named_volumes_in_binds(self): vol_name = '{0:x}'.format(random.getrandbits(32)) full_vol_name = 'composetest_{0}'.format(vol_name) base_file = config.ConfigFile( 'base.yml', { 'version': V2_0, 'services': { 'simple': { 'image': 'busybox:latest', 'command': 'top', 'volumes': ['{0}:/data'.format(vol_name)] }, }, 'volumes': { vol_name: {'driver': 'local'} } }) config_details = config.ConfigDetails('.', [base_file]) config_data = config.load(config_details) project = Project.from_config( name='composetest', config_data=config_data, client=self.client ) service = project.services[0] self.assertEqual(service.name, 'simple') volumes = service.options.get('volumes') self.assertEqual(len(volumes), 1) self.assertEqual(volumes[0].external, full_vol_name) project.up() engine_volumes = self.client.volumes()['Volumes'] container = service.get_container() assert [mount['Name'] for mount in container.get('Mounts')] == [full_vol_name] assert next((v for v in engine_volumes if v['Name'] == vol_name), None) is None
def test_project_up_port_mappings_with_multiple_files(self): base_file = config.ConfigFile( 'base.yml', { 'version': V2_0, 'services': { 'simple': { 'image': 'busybox:latest', 'command': 'top', 'ports': ['1234:1234'] }, }, }) override_file = config.ConfigFile( 'override.yml', { 'version': V2_0, 'services': { 'simple': { 'ports': ['1234:1234'] } } }) details = config.ConfigDetails('.', [base_file, override_file]) 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), 1)
def test_down_with_no_resources(self): project = Project.from_config( name='test', client=self.mock_client, config_data=Config( project_name='', version=V2_0, services=[{ 'name': 'web', 'image': BUSYBOX_IMAGE_WITH_TAG, }], networks={'default': {}}, volumes={'data': {}}, secrets=None, configs=None, ), ) self.mock_client.remove_network.side_effect = NotFound( None, None, 'oops') self.mock_client.remove_volume.side_effect = NotFound( None, None, 'oops') project.down(ImageType.all, True) self.mock_client.remove_image.assert_called_once_with( BUSYBOX_IMAGE_WITH_TAG)
def test_net_from_container(self): net_container = Container.create( self.client, image='busybox:latest', name='composetest_net_container', command='top', labels={LABEL_PROJECT: 'composetest'}, ) net_container.start() project = Project.from_config( name='composetest', config_data=build_service_dicts({ 'web': { 'image': 'busybox:latest', 'net': 'container:composetest_net_container' }, }), client=self.client, ) project.up() web = project.get_service('web') self.assertEqual(web.net.mode, 'container:' + net_container.id)
def test_run_interactive_passes_logs_false(self, mock_pseudo_terminal, mock_run_operation): os.environ['COMPOSE_INTERACTIVE_NO_CLI'] = 'true' mock_client = mock.create_autospec(docker.APIClient) mock_client.api_version = DEFAULT_DOCKER_API_VERSION project = Project.from_config( name='composetest', client=mock_client, config_data=build_config({'service': { 'image': 'busybox' }}), ) command = TopLevelCommand(project) with pytest.raises(SystemExit): command.run({ 'SERVICE': 'service', 'COMMAND': None, '-e': [], '--label': [], '--user': None, '--no-deps': None, '--detach': False, '-T': None, '--entrypoint': None, '--service-ports': None, '--publish': [], '--volume': [], '--rm': None, '--name': None, '--workdir': None, }) _, _, call_kwargs = mock_run_operation.mock_calls[0] assert call_kwargs['logs'] is False
def test_command_manual_and_service_ports_together(self): project = Project.from_config( name='composetest', client=None, config_data=build_config({ 'service': {'image': 'busybox'}, }), ) command = TopLevelCommand(project) with pytest.raises(UserError): command.run({ 'SERVICE': 'service', 'COMMAND': None, '-e': [], '--label': [], '--user': None, '--no-deps': None, '--detach': True, '-T': None, '--entrypoint': None, '--service-ports': True, '--use-aliases': None, '--publish': ['80:80'], '--rm': None, '--name': None, })
def test_net_unset(self): project = Project.from_config( "test", Config(None, [{"name": "test", "image": "busybox:latest"}], None), self.mock_client ) service = project.get_service("test") self.assertEqual(service.net.id, None) self.assertNotIn("NetworkMode", service._get_container_host_config({}))
def test_container_without_name(self): self.mock_client.containers.return_value = [ { 'Image': 'busybox:latest', 'Id': '1', 'Name': '1' }, { 'Image': 'busybox:latest', 'Id': '2', 'Name': None }, { 'Image': 'busybox:latest', 'Id': '3' }, ] self.mock_client.inspect_container.return_value = { 'Id': '1', 'Config': { 'Labels': { LABEL_SERVICE: 'web', }, }, } project = Project.from_config( 'test', Config(None, [{ 'name': 'web', 'image': 'busybox:latest', }], None), self.mock_client, ) self.assertEqual([c.id for c in project.containers()], ['1'])
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( version=V2_0, services=[{ 'name': 'web', 'image': 'busybox:latest', 'command': 'top' }], volumes={vol_name: { 'driver': 'local' }}, networks={}, ) project = Project.from_config(name='composetest', config_data=config_data, client=self.client) project.up() self.assertEqual(len(project.containers()), 1) volume_data = self.client.inspect_volume(full_vol_name) self.assertEqual(volume_data['Name'], full_vol_name) self.assertEqual(volume_data['Driver'], 'local')
def test_use_volumes_from_container(self): container_id = 'aabbccddee' container_dict = dict(Name='aaa', Id=container_id) self.mock_client.inspect_container.return_value = container_dict project = Project.from_config( name='test', client=self.mock_client, config_data=Config( project_name='', version=V2_0, services=[{ 'name': 'test', 'image': BUSYBOX_IMAGE_WITH_TAG, 'volumes_from': [VolumeFromSpec('aaa', 'rw', 'container')] }], networks=None, volumes=None, secrets=None, configs=None, ), ) assert project.get_service('test')._get_volumes_from() == [ container_id + ":rw" ]
def test_use_net_from_container(self): container_id = 'aabbccddee' container_dict = dict(Name='aaa', Id=container_id) self.mock_client.inspect_container.return_value = container_dict project = Project.from_config( name='test', client=self.mock_client, config_data=Config( project_name='', version=V2_0, services=[ { 'name': 'test', 'image': BUSYBOX_IMAGE_WITH_TAG, 'network_mode': 'container:aaa' }, ], networks=None, volumes=None, secrets=None, configs=None, ), ) service = project.get_service('test') assert service.network_mode.mode == 'container:' + container_id
def test_project_up_starts_depends(self): project = Project.from_config( name='composetest', config_data=build_service_dicts({ 'console': { 'image': 'busybox:latest', 'command': ["top"], }, 'data': { 'image': 'busybox:latest', 'command': ["top"] }, 'db': { 'image': 'busybox:latest', 'command': ["top"], 'volumes_from': ['data'], }, 'web': { 'image': 'busybox:latest', 'command': ["top"], 'links': ['db'], }, }), client=self.client, ) project.start() self.assertEqual(len(project.containers()), 0) project.up(['web']) self.assertEqual(len(project.containers()), 3) self.assertEqual(len(project.get_service('web').containers()), 1) self.assertEqual(len(project.get_service('db').containers()), 1) self.assertEqual(len(project.get_service('data').containers()), 1) self.assertEqual(len(project.get_service('console').containers()), 0)
def test_error_parallel_pull(self, mock_write): project = Project.from_config( name='test', client=self.mock_client, config_data=Config( project_name='', version=V2_0, services=[{ 'name': 'web', 'image': BUSYBOX_IMAGE_WITH_TAG, }], networks=None, volumes=None, secrets=None, configs=None, ), ) self.mock_client.pull.side_effect = OperationFailedError('pull error') with pytest.raises(ProjectError): project.pull(parallel_pull=True) self.mock_client.pull.side_effect = OperationFailedError(b'pull error') with pytest.raises(ProjectError): project.pull(parallel_pull=True)
def test_project_up_networks(self): config_data = config.Config( version=V2_0, services=[{ 'name': 'web', 'image': 'busybox:latest', 'command': 'top', 'networks': ['foo', 'bar', 'baz'], }], volumes={}, networks={ 'foo': {'driver': 'bridge'}, 'bar': {'driver': None}, 'baz': {}, }, ) project = Project.from_config( client=self.client, name='composetest', config_data=config_data, ) project.up() self.assertEqual(len(project.containers()), 1) for net_name in ['foo', 'bar', 'baz']: full_net_name = 'composetest_{}'.format(net_name) network_data = self.client.inspect_network(full_net_name) self.assertEqual(network_data['Name'], full_net_name) foo_data = self.client.inspect_network('composetest_foo') self.assertEqual(foo_data['Driver'], 'bridge')
def test_initialize_volumes_external_volumes(self): # Use composetest_ prefix so it gets garbage-collected in tearDown() 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( version=V2_0, services=[{ 'name': 'web', 'image': 'busybox:latest', 'command': 'top' }], volumes={ vol_name: {'external': True, 'external_name': vol_name} }, networks=None, ) project = Project.from_config( name='composetest', config_data=config_data, client=self.client ) project.volumes.initialize() with self.assertRaises(NotFound): self.client.inspect_volume(full_vol_name)
def test_use_net_from_container(self): container_id = 'aabbccddee' container_dict = dict(Name='aaa', Id=container_id) self.mock_client.inspect_container.return_value = container_dict project = Project.from_config( name='test', client=self.mock_client, config_data=Config( version=None, services=[ { 'name': 'test', 'image': 'busybox:latest', 'network_mode': 'container:aaa' }, ], networks=None, volumes=None, secrets=None, configs=None, ), ) service = project.get_service('test') self.assertEqual(service.network_mode.mode, 'container:' + container_id)
def test_project_up_with_no_deps(self): project = Project.from_config( name='composetest', config_data=build_config({ 'console': { 'image': 'busybox:latest', 'command': ["top"], }, 'data': { 'image': 'busybox:latest', 'command': ["top"] }, 'db': { 'image': 'busybox:latest', 'command': ["top"], 'volumes_from': ['data'], }, 'web': { 'image': 'busybox:latest', 'command': ["top"], 'links': ['db'], }, }), client=self.client, ) project.start() self.assertEqual(len(project.containers()), 0) project.up(['db'], start_deps=False) self.assertEqual(len(project.containers(stopped=True)), 2) self.assertEqual(len(project.get_service('web').containers()), 0) self.assertEqual(len(project.get_service('db').containers()), 1) self.assertEqual(len(project.get_service('data').containers()), 0) self.assertEqual(len(project.get_service('data').containers(stopped=True)), 1) self.assertEqual(len(project.get_service('console').containers()), 0)
def test_build_container_operation_with_timeout_func_does_not_mutate_options_with_timeout(self): config_data = Config( version=V3_7, services=[ {'name': 'web', 'image': 'busybox:latest'}, {'name': 'db', 'image': 'busybox:latest', 'stop_grace_period': '1s'}, ], networks={}, volumes={}, secrets=None, configs=None, ) project = Project.from_config(name='test', client=self.mock_client, config_data=config_data) stop_op = project.build_container_operation_with_timeout_func('stop', options={}) web_container = mock.create_autospec(Container, service='web') db_container = mock.create_autospec(Container, service='db') # `stop_grace_period` is not set to 'web' service, # then it is stopped with the default timeout. stop_op(web_container) web_container.stop.assert_called_once_with(timeout=DEFAULT_TIMEOUT) # `stop_grace_period` is set to 'db' service, # then it is stopped with the specified timeout and # the value is not overridden by the previous function call. stop_op(db_container) db_container.stop.assert_called_once_with(timeout=1)
def test_up_with_network_link_local_ips(self): config_data = config.Config( version=V2_1, services=[{ 'name': 'web', 'image': 'busybox:latest', 'networks': { 'linklocaltest': { 'link_local_ips': ['169.254.8.8'] } } }], volumes={}, networks={ 'linklocaltest': {'driver': 'bridge'} } ) project = Project.from_config( client=self.client, name='composetest', config_data=config_data ) project.up(detached=True) service_container = project.get_service('web').containers(stopped=True)[0] ipam_config = service_container.inspect().get( 'NetworkSettings', {} ).get( 'Networks', {} ).get( 'composetest_linklocaltest', {} ).get('IPAMConfig', {}) assert 'LinkLocalIPs' in ipam_config assert ipam_config['LinkLocalIPs'] == ['169.254.8.8']
def test_from_config(self): config = Config( version=None, services=[ { 'name': 'web', 'image': 'busybox:latest', }, { 'name': 'db', 'image': 'busybox:latest', }, ], networks=None, volumes=None, ) project = Project.from_config( name='composetest', config_data=config, client=None, ) self.assertEqual(len(project.services), 2) self.assertEqual(project.get_service('web').name, 'web') self.assertEqual( project.get_service('web').options['image'], 'busybox:latest') self.assertEqual(project.get_service('db').name, 'db') self.assertEqual( project.get_service('db').options['image'], 'busybox:latest') self.assertFalse(project.networks.use_networking)
def test_project_up_with_network_label(self): self.require_api_version('1.23') network_name = 'network_with_label' config_data = config.Config( version=V2_0, services=[{ 'name': 'web', 'image': 'busybox:latest', 'networks': {network_name: None} }], volumes={}, networks={ network_name: {'labels': {'label_key': 'label_val'}} } ) project = Project.from_config( client=self.client, name='composetest', config_data=config_data ) project.up() networks = [ n for n in self.client.networks() if n['Name'].startswith('composetest_') ] assert [n['Name'] for n in networks] == ['composetest_{}'.format(network_name)] assert networks[0]['Labels'] == {'label_key': 'label_val'}
def test_command_manual_and_service_ports_together(self): project = Project.from_config( name='composetest', client=None, config_data=build_config({ 'service': { 'image': 'busybox' }, }), ) command = TopLevelCommand(project) with pytest.raises(UserError): command.run({ 'SERVICE': 'service', 'COMMAND': None, '-e': [], '--label': [], '--user': None, '--no-deps': None, '--detach': True, '-T': None, '--entrypoint': None, '--service-ports': True, '--use-aliases': None, '--publish': ['80:80'], '--rm': None, '--name': None, })
def test_initialize_volumes_external_volumes(self): # Use composetest_ prefix so it gets garbage-collected in tearDown() 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( version=V2_0, services=[{ 'name': 'web', 'image': 'busybox:latest', 'command': 'top' }], volumes={ vol_name: {'external': True, 'external_name': vol_name} }, networks=None, ) project = Project.from_config( name='composetest', config_data=config_data, client=self.client ) project.volumes.initialize() with self.assertRaises(NotFound): self.client.inspect_volume(full_vol_name)
def test_from_config(self): config = Config( version=None, services=[ { 'name': 'web', 'image': 'busybox:latest', }, { 'name': 'db', 'image': 'busybox:latest', }, ], networks=None, volumes=None, plugins=None, ) project = Project.from_config( name='composetest', config_data=config, client=None, ) self.assertEqual(len(project.services), 2) self.assertEqual(project.get_service('web').name, 'web') self.assertEqual(project.get_service('web').options['image'], 'busybox:latest') self.assertEqual(project.get_service('db').name, 'db') self.assertEqual(project.get_service('db').options['image'], 'busybox:latest') self.assertFalse(project.networks.use_networking)
def test_use_volumes_from_service_no_container(self): container_name = 'test_vol_1' self.mock_client.containers.return_value = [ { "Name": container_name, "Names": [container_name], "Id": container_name, "Image": 'busybox:latest' } ] project = Project.from_config( name='test', client=self.mock_client, config_data=Config( version=None, services=[ { 'name': 'vol', 'image': 'busybox:latest' }, { 'name': 'test', 'image': 'busybox:latest', 'volumes_from': [VolumeFromSpec('vol', 'rw', 'service')] } ], networks=None, volumes=None, plugins=None, ), ) assert project.get_service('test')._get_volumes_from() == [container_name + ":rw"]
def test_from_config_v1(self): config = Config( version=V1, services=[ { 'name': 'web', 'image': 'busybox:latest', }, { 'name': 'db', 'image': 'busybox:latest', }, ], networks=None, volumes=None, secrets=None, configs=None, ) project = Project.from_config( name='composetest', config_data=config, client=None, ) assert len(project.services) == 2 assert project.get_service('web').name == 'web' assert project.get_service('web').options['image'] == 'busybox:latest' assert project.get_service('db').name == 'db' assert project.get_service('db').options['image'] == 'busybox:latest' assert not project.networks.use_networking
def test_project_up_named_volumes_in_binds(self): vol_name = '{0:x}'.format(random.getrandbits(32)) full_vol_name = 'composetest_{0}'.format(vol_name) base_file = config.ConfigFile( 'base.yml', { 'version': V2_0, 'services': { 'simple': { 'image': 'busybox:latest', 'command': 'top', 'volumes': ['{0}:/data'.format(vol_name)] }, }, 'volumes': { vol_name: {'driver': 'local'} } }) config_details = config.ConfigDetails('.', [base_file]) config_data = config.load(config_details) project = Project.from_config( name='composetest', config_data=config_data, client=self.client ) service = project.services[0] self.assertEqual(service.name, 'simple') volumes = service.options.get('volumes') self.assertEqual(len(volumes), 1) self.assertEqual(volumes[0].external, full_vol_name) project.up() engine_volumes = self.client.volumes()['Volumes'] container = service.get_container() assert [mount['Name'] for mount in container.get('Mounts')] == [full_vol_name] assert next((v for v in engine_volumes if v['Name'] == vol_name), None) is None
def test_project_up_with_no_deps(self): project = Project.from_config( name='composetest', config_data=build_config({ 'console': { 'image': 'busybox:latest', 'command': ["top"], }, 'data': { 'image': 'busybox:latest', 'command': ["top"] }, 'db': { 'image': 'busybox:latest', 'command': ["top"], 'volumes_from': ['data'], }, 'web': { 'image': 'busybox:latest', 'command': ["top"], 'links': ['db'], }, }), client=self.client, ) project.start() self.assertEqual(len(project.containers()), 0) project.up(['db'], start_deps=False) self.assertEqual(len(project.containers(stopped=True)), 2) self.assertEqual(len(project.get_service('web').containers()), 0) self.assertEqual(len(project.get_service('db').containers()), 1) self.assertEqual(len(project.get_service('data').containers()), 0) self.assertEqual(len(project.get_service('data').containers(stopped=True)), 1) self.assertEqual(len(project.get_service('console').containers()), 0)
def test_project_up_networks(self): config_data = config.Config( version=V2_0, services=[{ 'name': 'web', 'image': 'busybox:latest', 'command': 'top', 'networks': {'foo': None, 'bar': None, 'baz': None}, }], volumes={}, networks={ 'foo': {'driver': 'bridge'}, 'bar': {'driver': None}, 'baz': {}, }, ) project = Project.from_config( client=self.client, name='composetest', config_data=config_data, ) project.up() self.assertEqual(len(project.containers()), 1) for net_name in ['foo', 'bar', 'baz']: full_net_name = 'composetest_{}'.format(net_name) network_data = self.client.inspect_network(full_net_name) self.assertEqual(network_data['Name'], full_net_name) foo_data = self.client.inspect_network('composetest_foo') self.assertEqual(foo_data['Driver'], 'bridge')
def test_run_interactive_passes_logs_false(self, mock_pseudo_terminal, mock_run_operation): mock_client = mock.create_autospec(docker.APIClient) project = Project.from_config( name='composetest', client=mock_client, config_data=build_config({ 'service': {'image': 'busybox'} }), ) plugin_manager = PluginManager('') command = TopLevelCommand(project, plugin_manager) with pytest.raises(SystemExit): command.run({ 'SERVICE': 'service', 'COMMAND': None, '-e': [], '--user': None, '--no-deps': None, '-d': False, '-T': None, '--entrypoint': None, '--service-ports': None, '--publish': [], '--rm': None, '--name': None, '--workdir': None, }) _, _, call_kwargs = mock_run_operation.mock_calls[0] assert call_kwargs['logs'] is False
def test_container_without_name(self): self.mock_client.containers.return_value = [ {'Image': BUSYBOX_IMAGE_WITH_TAG, 'Id': '1', 'Name': '1'}, {'Image': BUSYBOX_IMAGE_WITH_TAG, 'Id': '2', 'Name': None}, {'Image': BUSYBOX_IMAGE_WITH_TAG, 'Id': '3'}, ] self.mock_client.inspect_container.return_value = { 'Id': '1', 'Config': { 'Labels': { LABEL_SERVICE: 'web', }, }, } project = Project.from_config( name='test', client=self.mock_client, config_data=Config( version=V2_0, services=[{ 'name': 'web', 'image': BUSYBOX_IMAGE_WITH_TAG, }], networks=None, volumes=None, secrets=None, configs=None, ), ) assert [c.id for c in project.containers()] == ['1']
def test_build_container_operation_with_timeout_func_does_not_mutate_options_with_timeout(self): config_data = Config( version=V3_7, services=[ {'name': 'web', 'image': BUSYBOX_IMAGE_WITH_TAG}, {'name': 'db', 'image': BUSYBOX_IMAGE_WITH_TAG, 'stop_grace_period': '1s'}, ], networks={}, volumes={}, secrets=None, configs=None, ) project = Project.from_config(name='test', client=self.mock_client, config_data=config_data) stop_op = project.build_container_operation_with_timeout_func('stop', options={}) web_container = mock.create_autospec(Container, service='web') db_container = mock.create_autospec(Container, service='db') # `stop_grace_period` is not set to 'web' service, # then it is stopped with the default timeout. stop_op(web_container) web_container.stop.assert_called_once_with(timeout=DEFAULT_TIMEOUT) # `stop_grace_period` is set to 'db' service, # then it is stopped with the specified timeout and # the value is not overridden by the previous function call. stop_op(db_container) db_container.stop.assert_called_once_with(timeout=1)
def test_from_config_v1(self): config = Config( version=V1, services=[ { 'name': 'web', 'image': BUSYBOX_IMAGE_WITH_TAG, }, { 'name': 'db', 'image': BUSYBOX_IMAGE_WITH_TAG, }, ], networks=None, volumes=None, secrets=None, configs=None, ) project = Project.from_config( name='composetest', config_data=config, client=None, ) assert len(project.services) == 2 assert project.get_service('web').name == 'web' assert project.get_service('web').options['image'] == BUSYBOX_IMAGE_WITH_TAG assert project.get_service('db').name == 'db' assert project.get_service('db').options['image'] == BUSYBOX_IMAGE_WITH_TAG assert not project.networks.use_networking
def test_use_net_from_service(self): container_name = 'test_aaa_1' self.mock_client.containers.return_value = [ { "Name": container_name, "Names": [container_name], "Id": container_name, "Image": BUSYBOX_IMAGE_WITH_TAG } ] project = Project.from_config( name='test', client=self.mock_client, config_data=Config( version=V2_0, services=[ { 'name': 'aaa', 'image': BUSYBOX_IMAGE_WITH_TAG }, { 'name': 'test', 'image': BUSYBOX_IMAGE_WITH_TAG, 'network_mode': 'service:aaa' }, ], networks=None, volumes=None, secrets=None, configs=None, ), ) service = project.get_service('test') assert service.network_mode.mode == 'container:' + container_name
def test_use_volumes_from_service_container(self): container_ids = ['aabbccddee', '12345'] project = Project.from_config( name='test', client=None, config_data=Config( version=V2_0, services=[ { 'name': 'vol', 'image': BUSYBOX_IMAGE_WITH_TAG }, { 'name': 'test', 'image': BUSYBOX_IMAGE_WITH_TAG, 'volumes_from': [VolumeFromSpec('vol', 'rw', 'service')] } ], networks=None, volumes=None, secrets=None, configs=None, ), ) with mock.patch.object(Service, 'containers') as mock_return: mock_return.return_value = [ mock.Mock(id=container_id, spec=Container) for container_id in container_ids] assert ( project.get_service('test')._get_volumes_from() == [container_ids[0] + ':rw'] )
def test_use_volumes_from_service_no_container(self): container_name = 'test_vol_1' self.mock_client.containers.return_value = [ { "Name": container_name, "Names": [container_name], "Id": container_name, "Image": BUSYBOX_IMAGE_WITH_TAG } ] project = Project.from_config( name='test', client=self.mock_client, config_data=Config( version=V2_0, services=[ { 'name': 'vol', 'image': BUSYBOX_IMAGE_WITH_TAG }, { 'name': 'test', 'image': BUSYBOX_IMAGE_WITH_TAG, 'volumes_from': [VolumeFromSpec('vol', 'rw', 'service')] } ], networks=None, volumes=None, secrets=None, configs=None, ), ) assert project.get_service('test')._get_volumes_from() == [container_name + ":rw"]
def test_up_with_network_static_addresses_missing_subnet(self): config_data = config.Config( version=V2_0, services=[{ 'name': 'web', 'image': 'busybox:latest', 'networks': { 'static_test': { 'ipv4_address': '172.16.100.100', 'ipv6_address': 'fe80::1001:101' } }, }], volumes={}, networks={ 'static_test': { 'driver': 'bridge', 'driver_opts': { "com.docker.network.enable_ipv6": "true", }, 'ipam': { 'driver': 'default', }, }, }, ) project = Project.from_config( client=self.client, name='composetest', config_data=config_data, ) assert len(project.up()) == 0
def test_use_net_from_service(self): container_name = 'test_aaa_1' self.mock_client.containers.return_value = [ { "Name": container_name, "Names": [container_name], "Id": container_name, "Image": 'busybox:latest' } ] project = Project.from_config( name='test', client=self.mock_client, config_data=Config( version=None, services=[ { 'name': 'aaa', 'image': 'busybox:latest' }, { 'name': 'test', 'image': 'busybox:latest', 'network_mode': 'service:aaa' }, ], networks=None, volumes=None, plugins=None, ), ) service = project.get_service('test') self.assertEqual(service.network_mode.mode, 'container:' + container_name)
def test_network_mode_from_service(self): project = Project.from_config( name='composetest', client=self.client, config_data=build_config({ 'version': V2_0, 'services': { 'net': { 'image': 'busybox:latest', 'command': ["top"] }, 'web': { 'image': 'busybox:latest', 'network_mode': 'service:net', 'command': ["top"] }, }, }), ) project.up() web = project.get_service('web') net = project.get_service('net') self.assertEqual(web.network_mode.mode, 'container:' + net.containers()[0].id)
def test_container_without_name(self): self.mock_client.containers.return_value = [ {'Image': 'busybox:latest', 'Id': '1', 'Name': '1'}, {'Image': 'busybox:latest', 'Id': '2', 'Name': None}, {'Image': 'busybox:latest', 'Id': '3'}, ] self.mock_client.inspect_container.return_value = { 'Id': '1', 'Config': { 'Labels': { LABEL_SERVICE: 'web', }, }, } project = Project.from_config( name='test', client=self.mock_client, config_data=Config( version=None, services=[{ 'name': 'web', 'image': 'busybox:latest', }], networks=None, volumes=None, plugins=None, ), ) self.assertEqual([c.id for c in project.containers()], ['1'])
def test_project_up_with_network_internal(self): self.require_api_version('1.23') config_data = config.Config( version=V2_0, services=[{ 'name': 'web', 'image': 'busybox:latest', 'networks': {'internal': None}, }], volumes={}, networks={ 'internal': {'driver': 'bridge', 'internal': True}, }, ) project = Project.from_config( client=self.client, name='composetest', config_data=config_data, ) project.up() network = self.client.networks(names=['composetest_internal'])[0] assert network['Internal'] is True
def test_command_manual_and_service_ports_together(self): project = Project.from_config( name='composetest', client=None, config_data=build_config({ 'service': {'image': 'busybox'}, }), ) plugin_manager = PluginManager('') command = TopLevelCommand(project, plugin_manager) with self.assertRaises(UserError): command.run({ 'SERVICE': 'service', 'COMMAND': None, '-e': [], '--user': None, '--no-deps': None, '-d': True, '-T': None, '--entrypoint': None, '--service-ports': True, '--publish': ['80:80'], '--rm': None, '--name': None, })
def test_net_from_container(self): net_container = Container.create( self.client, image='busybox:latest', name='composetest_net_container', command='top', labels={LABEL_PROJECT: 'composetest'}, ) net_container.start() project = Project.from_config( name='composetest', config_data=build_service_dicts({ 'web': { 'image': 'busybox:latest', 'net': 'container:composetest_net_container' }, }), client=self.client, ) project.up() web = project.get_service('web') self.assertEqual(web.net.mode, 'container:' + net_container.id)
def test_project_up_starts_depends(self): project = Project.from_config( name='composetest', config_data=build_service_dicts({ 'console': { 'image': 'busybox:latest', 'command': ["top"], }, 'data': { 'image': 'busybox:latest', 'command': ["top"] }, 'db': { 'image': 'busybox:latest', 'command': ["top"], 'volumes_from': ['data'], }, 'web': { 'image': 'busybox:latest', 'command': ["top"], 'links': ['db'], }, }), client=self.client, ) project.start() self.assertEqual(len(project.containers()), 0) project.up(['web']) self.assertEqual(len(project.containers()), 3) self.assertEqual(len(project.get_service('web').containers()), 1) self.assertEqual(len(project.get_service('db').containers()), 1) self.assertEqual(len(project.get_service('data').containers()), 1) self.assertEqual(len(project.get_service('console').containers()), 0)
def test_project_up_port_mappings_with_multiple_files(self): base_file = config.ConfigFile( 'base.yml', { 'version': V2_0, 'services': { 'simple': { 'image': 'busybox:latest', 'command': 'top', 'ports': ['1234:1234'] }, }, }) override_file = config.ConfigFile( 'override.yml', { 'version': V2_0, 'services': { 'simple': { 'ports': ['1234:1234'] } } }) details = config.ConfigDetails('.', [base_file, override_file]) 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), 1)
def test_network_mode_from_service(self): project = Project.from_config( name='composetest', client=self.client, config_data=build_config({ 'version': V2_0, 'services': { 'net': { 'image': 'busybox:latest', 'command': ["top"] }, 'web': { 'image': 'busybox:latest', 'network_mode': 'service:net', 'command': ["top"] }, }, }), ) project.up() web = project.get_service('web') net = project.get_service('net') self.assertEqual(web.network_mode.mode, 'container:' + net.containers()[0].id)
def test_use_volumes_from_service_container(self): container_ids = ['aabbccddee', '12345'] project = Project.from_config( name='test', client=None, config_data=Config( version=None, services=[ { 'name': 'vol', 'image': 'busybox:latest' }, { 'name': 'test', 'image': 'busybox:latest', 'volumes_from': [VolumeFromSpec('vol', 'rw', 'service')] } ], networks=None, volumes=None, plugins=None, ), ) with mock.patch.object(Service, 'containers') as mock_return: mock_return.return_value = [ mock.Mock(id=container_id, spec=Container) for container_id in container_ids] assert ( project.get_service('test')._get_volumes_from() == [container_ids[0] + ':rw'] )
def test_run_service_with_restart_always(self): mock_client = mock.create_autospec(docker.APIClient) mock_client.api_version = DEFAULT_DOCKER_API_VERSION mock_client._general_configs = {} project = Project.from_config( name='composetest', client=mock_client, config_data=build_config({ 'service': { 'image': 'busybox', 'restart': 'always', } }), ) command = TopLevelCommand(project) command.run({ 'SERVICE': 'service', 'COMMAND': None, '-e': [], '--label': [], '--user': None, '--no-deps': None, '--detach': True, '-T': None, '--entrypoint': None, '--service-ports': None, '--use-aliases': None, '--publish': [], '--volume': [], '--rm': None, '--name': None, '--workdir': None, }) assert mock_client.create_host_config.call_args[1]['restart_policy']['Name'] == 'always' command = TopLevelCommand(project) command.run({ 'SERVICE': 'service', 'COMMAND': None, '-e': [], '--label': [], '--user': None, '--no-deps': None, '--detach': True, '-T': None, '--entrypoint': None, '--service-ports': None, '--use-aliases': None, '--publish': [], '--volume': [], '--rm': True, '--name': None, '--workdir': None, }) assert not mock_client.create_host_config.call_args[1].get('restart_policy')
def test_up_with_ipam_config(self): config_data = config.Config( version=V2_0, services=[{ 'name': 'web', 'image': 'busybox:latest', 'networks': {'front': None}, }], volumes={}, networks={ 'front': { 'driver': 'bridge', 'driver_opts': { "com.docker.network.bridge.enable_icc": "false", }, 'ipam': { 'driver': 'default', 'config': [{ "subnet": "172.28.0.0/16", "ip_range": "172.28.5.0/24", "gateway": "172.28.5.254", "aux_addresses": { "a": "172.28.1.5", "b": "172.28.1.6", "c": "172.28.1.7", }, }], }, }, }, ) project = Project.from_config( client=self.client, name='composetest', config_data=config_data, ) project.up() network = self.client.networks(names=['composetest_front'])[0] assert network['Options'] == { "com.docker.network.bridge.enable_icc": "false" } assert network['IPAM'] == { 'Driver': 'default', 'Options': None, 'Config': [{ 'Subnet': "172.28.0.0/16", 'IPRange': "172.28.5.0/24", 'Gateway': "172.28.5.254", 'AuxiliaryAddresses': { 'a': '172.28.1.5', 'b': '172.28.1.6', 'c': '172.28.1.7', }, }], }
def get_auxiliary_project(self): config_details = config.find(self.auxiliary_project, [], Environment(self.environment())) project_name = self.auxiliary_project_name config_data = dork_config_load([], config_details) client = get_client(self.environment(), version=API_VERSIONS[config_data.version]) return Project.from_config(project_name, config_data, client)
def make_project(self, cfg): details = config.ConfigDetails( 'working_dir', [config.ConfigFile(None, cfg)]) return Project.from_config( name='composetest', client=self.client, config_data=config.load(details))
def test_run_service_with_restart_always(self): mock_client = mock.create_autospec(docker.APIClient) project = Project.from_config( name='composetest', client=mock_client, config_data=build_config({ 'service': { 'image': 'busybox', 'restart': 'always', } }), ) command = TopLevelCommand(project) command.run({ 'SERVICE': 'service', 'COMMAND': None, '-e': [], '--user': None, '--no-deps': None, '-d': True, '-T': None, '--entrypoint': None, '--service-ports': None, '--publish': [], '--volume': [], '--rm': None, '--name': None, '--workdir': None, }) self.assertEqual( mock_client.create_host_config.call_args[1]['restart_policy']['Name'], 'always' ) command = TopLevelCommand(project) command.run({ 'SERVICE': 'service', 'COMMAND': None, '-e': [], '--user': None, '--no-deps': None, '-d': True, '-T': None, '--entrypoint': None, '--service-ports': None, '--publish': [], '--volume': [], '--rm': True, '--name': None, '--workdir': None, }) self.assertFalse( mock_client.create_host_config.call_args[1].get('restart_policy') )