mirror of https://github.com/docker/compose.git
Merge pull request #1658 from aanand/fix-smart-recreate-nonexistent-image
Fix smart recreate when 'image' is changed to something nonexistent
This commit is contained in:
commit
2bc10db545
|
@ -65,6 +65,10 @@ class NeedsBuildError(Exception):
|
||||||
self.service = service
|
self.service = service
|
||||||
|
|
||||||
|
|
||||||
|
class NoSuchImageError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
VolumeSpec = namedtuple('VolumeSpec', 'external internal mode')
|
VolumeSpec = namedtuple('VolumeSpec', 'external internal mode')
|
||||||
|
|
||||||
|
|
||||||
|
@ -225,8 +229,11 @@ class Service(object):
|
||||||
do_build=True,
|
do_build=True,
|
||||||
insecure_registry=False):
|
insecure_registry=False):
|
||||||
|
|
||||||
if self.image():
|
try:
|
||||||
|
self.image()
|
||||||
return
|
return
|
||||||
|
except NoSuchImageError:
|
||||||
|
pass
|
||||||
|
|
||||||
if self.can_be_built():
|
if self.can_be_built():
|
||||||
if do_build:
|
if do_build:
|
||||||
|
@ -241,7 +248,7 @@ class Service(object):
|
||||||
return self.client.inspect_image(self.image_name)
|
return self.client.inspect_image(self.image_name)
|
||||||
except APIError as e:
|
except APIError as e:
|
||||||
if e.response.status_code == 404 and e.explanation and 'No such image' in str(e.explanation):
|
if e.response.status_code == 404 and e.explanation and 'No such image' in str(e.explanation):
|
||||||
return None
|
raise NoSuchImageError("Image '{}' not found".format(self.image_name))
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@ -275,7 +282,17 @@ class Service(object):
|
||||||
return ConvergencePlan('recreate', containers)
|
return ConvergencePlan('recreate', containers)
|
||||||
|
|
||||||
def _containers_have_diverged(self, containers):
|
def _containers_have_diverged(self, containers):
|
||||||
|
config_hash = None
|
||||||
|
|
||||||
|
try:
|
||||||
config_hash = self.config_hash()
|
config_hash = self.config_hash()
|
||||||
|
except NoSuchImageError as e:
|
||||||
|
log.debug(
|
||||||
|
'Service %s has diverged: %s',
|
||||||
|
self.name, six.text_type(e),
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
has_diverged = False
|
has_diverged = False
|
||||||
|
|
||||||
for c in containers:
|
for c in containers:
|
||||||
|
|
|
@ -215,6 +215,13 @@ class ServiceStateTest(DockerClientTestCase):
|
||||||
web = self.create_service('web', command=["top", "-d", "1"])
|
web = self.create_service('web', command=["top", "-d", "1"])
|
||||||
self.assertEqual(('recreate', [container]), web.convergence_plan(smart_recreate=True))
|
self.assertEqual(('recreate', [container]), web.convergence_plan(smart_recreate=True))
|
||||||
|
|
||||||
|
def test_trigger_recreate_with_nonexistent_image_tag(self):
|
||||||
|
web = self.create_service('web', image="busybox:latest")
|
||||||
|
container = web.create_container()
|
||||||
|
|
||||||
|
web = self.create_service('web', image="nonexistent-image")
|
||||||
|
self.assertEqual(('recreate', [container]), web.convergence_plan(smart_recreate=True))
|
||||||
|
|
||||||
def test_trigger_recreate_with_image_change(self):
|
def test_trigger_recreate_with_image_change(self):
|
||||||
repo = 'composetest_myimage'
|
repo = 'composetest_myimage'
|
||||||
tag = 'latest'
|
tag = 'latest'
|
||||||
|
|
|
@ -12,6 +12,7 @@ from compose.const import LABEL_SERVICE, LABEL_PROJECT, LABEL_ONE_OFF
|
||||||
from compose.service import (
|
from compose.service import (
|
||||||
ConfigError,
|
ConfigError,
|
||||||
NeedsBuildError,
|
NeedsBuildError,
|
||||||
|
NoSuchImageError,
|
||||||
build_port_bindings,
|
build_port_bindings,
|
||||||
build_volume_binding,
|
build_volume_binding,
|
||||||
get_container_data_volumes,
|
get_container_data_volumes,
|
||||||
|
@ -245,7 +246,7 @@ class ServiceTest(unittest.TestCase):
|
||||||
images.append({'Id': 'abc123'})
|
images.append({'Id': 'abc123'})
|
||||||
return []
|
return []
|
||||||
|
|
||||||
service.image = lambda: images[0] if images else None
|
service.image = lambda *args, **kwargs: mock_get_image(images)
|
||||||
self.mock_client.pull = pull
|
self.mock_client.pull = pull
|
||||||
|
|
||||||
service.create_container(insecure_registry=True)
|
service.create_container(insecure_registry=True)
|
||||||
|
@ -294,7 +295,7 @@ class ServiceTest(unittest.TestCase):
|
||||||
images.append({'Id': 'abc123'})
|
images.append({'Id': 'abc123'})
|
||||||
return []
|
return []
|
||||||
|
|
||||||
service.image = lambda: images[0] if images else None
|
service.image = lambda *args, **kwargs: mock_get_image(images)
|
||||||
self.mock_client.pull = pull
|
self.mock_client.pull = pull
|
||||||
|
|
||||||
service.create_container()
|
service.create_container()
|
||||||
|
@ -304,7 +305,7 @@ class ServiceTest(unittest.TestCase):
|
||||||
service = Service('foo', client=self.mock_client, build='.')
|
service = Service('foo', client=self.mock_client, build='.')
|
||||||
|
|
||||||
images = []
|
images = []
|
||||||
service.image = lambda *args, **kwargs: images[0] if images else None
|
service.image = lambda *args, **kwargs: mock_get_image(images)
|
||||||
service.build = lambda: images.append({'Id': 'abc123'})
|
service.build = lambda: images.append({'Id': 'abc123'})
|
||||||
|
|
||||||
service.create_container(do_build=True)
|
service.create_container(do_build=True)
|
||||||
|
@ -319,7 +320,7 @@ class ServiceTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_create_container_no_build_but_needs_build(self):
|
def test_create_container_no_build_but_needs_build(self):
|
||||||
service = Service('foo', client=self.mock_client, build='.')
|
service = Service('foo', client=self.mock_client, build='.')
|
||||||
service.image = lambda: None
|
service.image = lambda *args, **kwargs: mock_get_image([])
|
||||||
|
|
||||||
with self.assertRaises(NeedsBuildError):
|
with self.assertRaises(NeedsBuildError):
|
||||||
service.create_container(do_build=False)
|
service.create_container(do_build=False)
|
||||||
|
@ -336,6 +337,13 @@ class ServiceTest(unittest.TestCase):
|
||||||
self.assertFalse(self.mock_client.build.call_args[1]['pull'])
|
self.assertFalse(self.mock_client.build.call_args[1]['pull'])
|
||||||
|
|
||||||
|
|
||||||
|
def mock_get_image(images):
|
||||||
|
if images:
|
||||||
|
return images[0]
|
||||||
|
else:
|
||||||
|
raise NoSuchImageError()
|
||||||
|
|
||||||
|
|
||||||
class ServiceVolumesTest(unittest.TestCase):
|
class ServiceVolumesTest(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
Loading…
Reference in New Issue