From 3056ae4be329333e0f63568fc7d20a1d379b4172 Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Sun, 26 Oct 2014 13:23:15 -0400 Subject: [PATCH] Add a no-build option to fig up, to save time when services were already freshly built. Signed-off-by: Daniel Nephin --- fig/cli/main.py | 4 +++- fig/project.py | 18 +++++++++++++++--- fig/service.py | 20 ++++++++++++++------ tests/integration/service_test.py | 28 ++++++++++++++-------------- tests/unit/service_test.py | 17 +++++++++++++++++ 5 files changed, 63 insertions(+), 24 deletions(-) diff --git a/fig/cli/main.py b/fig/cli/main.py index c367266bb..8cdaee620 100644 --- a/fig/cli/main.py +++ b/fig/cli/main.py @@ -425,6 +425,7 @@ class TopLevelCommand(Command): --no-color Produce monochrome output. --no-deps Don't start linked services. --no-recreate If containers already exist, don't recreate them. + --no-build Don't build an image, even if it's missing """ insecure_registry = options['--allow-insecure-ssl'] detached = options['-d'] @@ -440,7 +441,8 @@ class TopLevelCommand(Command): start_links=start_links, recreate=recreate, insecure_registry=insecure_registry, - detach=options['-d'] + detach=options['-d'], + do_build=not options['--no-build'], ) to_attach = [c for s in project.get_services(service_names) for c in s.containers()] diff --git a/fig/project.py b/fig/project.py index 8d71a4c29..e013da4e9 100644 --- a/fig/project.py +++ b/fig/project.py @@ -167,14 +167,26 @@ class Project(object): else: log.info('%s uses an image, skipping' % service.name) - def up(self, service_names=None, start_links=True, recreate=True, insecure_registry=False, detach=False): + def up(self, + service_names=None, + start_links=True, + recreate=True, + insecure_registry=False, + detach=False, + do_build=True): running_containers = [] for service in self.get_services(service_names, include_links=start_links): if recreate: - for (_, container) in service.recreate_containers(insecure_registry=insecure_registry, detach=detach): + for (_, container) in service.recreate_containers( + insecure_registry=insecure_registry, + detach=detach, + do_build=do_build): running_containers.append(container) else: - for container in service.start_or_create_containers(insecure_registry=insecure_registry, detach=detach): + for container in service.start_or_create_containers( + insecure_registry=insecure_registry, + detach=detach, + do_build=do_build): running_containers.append(container) return running_containers diff --git a/fig/service.py b/fig/service.py index 461bc1fe5..d06d271f6 100644 --- a/fig/service.py +++ b/fig/service.py @@ -54,7 +54,7 @@ DOCKER_START_KEYS = [ 'cap_add', 'cap_drop', 'dns', - 'dns_search', + 'dns_search', 'env_file', 'net', 'privileged', @@ -236,7 +236,7 @@ class Service(object): return Container.create(self.client, **container_options) raise - def recreate_containers(self, insecure_registry=False, **override_options): + def recreate_containers(self, insecure_registry=False, do_build=True, **override_options): """ If a container for this service doesn't exist, create and start one. If there are any, stop them, create+start new ones, and remove the old containers. @@ -244,7 +244,10 @@ class Service(object): containers = self.containers(stopped=True) if not containers: log.info("Creating %s..." % self._next_container_name(containers)) - container = self.create_container(insecure_registry=insecure_registry, **override_options) + container = self.create_container( + insecure_registry=insecure_registry, + do_build=do_build, + **override_options) self.start_container(container) return [(None, container)] else: @@ -283,7 +286,7 @@ class Service(object): container.remove() options = dict(override_options) - new_container = self.create_container(**options) + new_container = self.create_container(do_build=False, **options) self.start_container(new_container, intermediate_container=intermediate_container) intermediate_container.remove() @@ -330,14 +333,19 @@ class Service(object): ) return container - def start_or_create_containers(self, insecure_registry=False, detach=False): + def start_or_create_containers( + self, + insecure_registry=False, + detach=False, + do_build=True): containers = self.containers(stopped=True) if not containers: log.info("Creating %s..." % self._next_container_name(containers)) new_container = self.create_container( insecure_registry=insecure_registry, - detach=detach + detach=detach, + do_build=do_build, ) return [self.start_container(new_container)] else: diff --git a/tests/integration/service_test.py b/tests/integration/service_test.py index 0e08ac1cb..fca4da67d 100644 --- a/tests/integration/service_test.py +++ b/tests/integration/service_test.py @@ -391,34 +391,34 @@ class ServiceTest(DockerClientTestCase): def test_restart_always_value(self): service = self.create_service('web', restart='always') - container = service.start_container().inspect() - self.assertEqual(container['HostConfig']['RestartPolicy']['Name'], 'always') + container = create_and_start_container(service) + self.assertEqual(container.get('HostConfig.RestartPolicy.Name'), 'always') def test_restart_on_failure_value(self): service = self.create_service('web', restart='on-failure:5') - container = service.start_container().inspect() - self.assertEqual(container['HostConfig']['RestartPolicy']['Name'], 'on-failure') - self.assertEqual(container['HostConfig']['RestartPolicy']['MaximumRetryCount'], 5) + container = create_and_start_container(service) + self.assertEqual(container.get('HostConfig.RestartPolicy.Name'), 'on-failure') + self.assertEqual(container.get('HostConfig.RestartPolicy.MaximumRetryCount'), 5) def test_cap_add_list(self): service = self.create_service('web', cap_add=['SYS_ADMIN', 'NET_ADMIN']) - container = service.start_container().inspect() - self.assertEqual(container['HostConfig']['CapAdd'], ['SYS_ADMIN', 'NET_ADMIN']) + container = create_and_start_container(service) + self.assertEqual(container.get('HostConfig.CapAdd'), ['SYS_ADMIN', 'NET_ADMIN']) def test_cap_drop_list(self): service = self.create_service('web', cap_drop=['SYS_ADMIN', 'NET_ADMIN']) - container = service.start_container().inspect() - self.assertEqual(container['HostConfig']['CapDrop'], ['SYS_ADMIN', 'NET_ADMIN']) + container = create_and_start_container(service) + self.assertEqual(container.get('HostConfig.CapDrop'), ['SYS_ADMIN', 'NET_ADMIN']) def test_dns_search_single_value(self): service = self.create_service('web', dns_search='example.com') - container = service.start_container().inspect() - self.assertEqual(container['HostConfig']['DnsSearch'], ['example.com']) + container = create_and_start_container(service) + self.assertEqual(container.get('HostConfig.DnsSearch'), ['example.com']) def test_dns_search_list(self): service = self.create_service('web', dns_search=['dc1.example.com', 'dc2.example.com']) - container = service.start_container().inspect() - self.assertEqual(container['HostConfig']['DnsSearch'], ['dc1.example.com', 'dc2.example.com']) + container = create_and_start_container(service) + self.assertEqual(container.get('HostConfig.DnsSearch'), ['dc1.example.com', 'dc2.example.com']) def test_working_dir_param(self): service = self.create_service('container', working_dir='/working/dir/sample') @@ -433,7 +433,7 @@ class ServiceTest(DockerClientTestCase): def test_env_from_file_combined_with_env(self): service = self.create_service('web', environment=['ONE=1', 'TWO=2', 'THREE=3'], env_file=['tests/fixtures/env/one.env', 'tests/fixtures/env/two.env']) - env = service.start_container().environment + env = create_and_start_container(service).environment for k,v in {'ONE': '1', 'TWO': '2', 'THREE': '3', 'FOO': 'baz', 'DOO': 'dah'}.iteritems(): self.assertEqual(env[k], v) diff --git a/tests/unit/service_test.py b/tests/unit/service_test.py index 88ebd1d6b..68dcf06ab 100644 --- a/tests/unit/service_test.py +++ b/tests/unit/service_test.py @@ -228,6 +228,23 @@ class ServiceTest(unittest.TestCase): service.create_container() self.assertEqual(Container.create.call_args[1]['image'], 'someimage:latest') + def test_create_container_with_build(self): + self.mock_client.images.return_value = [] + service = Service('foo', client=self.mock_client, build='.') + service.build = mock.create_autospec(service.build) + service.create_container(do_build=True) + + self.mock_client.images.assert_called_once_with(name=service.full_name) + service.build.assert_called_once_with() + + def test_create_container_no_build(self): + self.mock_client.images.return_value = [] + service = Service('foo', client=self.mock_client, build='.') + service.create_container(do_build=False) + + self.assertFalse(self.mock_client.images.called) + self.assertFalse(self.mock_client.build.called) + class ServiceVolumesTest(unittest.TestCase):