Merge "Check config when checking the containers"
This commit is contained in:
commit
851f2c799c
@ -264,6 +264,9 @@ EXAMPLES = '''
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
COMPARE_CONFIG_CMD = ['/usr/local/bin/kolla_set_configs', '--check']
|
||||||
|
|
||||||
|
|
||||||
def get_docker_client():
|
def get_docker_client():
|
||||||
return docker.APIClient
|
return docker.APIClient
|
||||||
|
|
||||||
@ -348,7 +351,9 @@ class DockerWorker(object):
|
|||||||
|
|
||||||
def compare_container(self):
|
def compare_container(self):
|
||||||
container = self.check_container()
|
container = self.check_container()
|
||||||
if not container or self.check_container_differs():
|
if (not container or
|
||||||
|
self.check_container_differs() or
|
||||||
|
self.compare_config()):
|
||||||
self.changed = True
|
self.changed = True
|
||||||
return self.changed
|
return self.changed
|
||||||
|
|
||||||
@ -614,6 +619,43 @@ class DockerWorker(object):
|
|||||||
if current_healthcheck:
|
if current_healthcheck:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def compare_config(self):
|
||||||
|
try:
|
||||||
|
job = self.dc.exec_create(
|
||||||
|
self.params['name'],
|
||||||
|
COMPARE_CONFIG_CMD,
|
||||||
|
user='root',
|
||||||
|
)
|
||||||
|
output = self.dc.exec_start(job)
|
||||||
|
exec_inspect = self.dc.exec_inspect(job)
|
||||||
|
except docker.errors.APIError as e:
|
||||||
|
# NOTE(yoctozepto): If we have a client error, then the container
|
||||||
|
# cannot be used for config check (e.g., is restarting, or stopped
|
||||||
|
# in the mean time) - assume config is stale = return True.
|
||||||
|
# Else, propagate the server error back.
|
||||||
|
if e.is_client_error():
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
# Exit codes:
|
||||||
|
# 0: not changed
|
||||||
|
# 1: changed
|
||||||
|
# 137: abrupt exit -> changed
|
||||||
|
# else: error
|
||||||
|
if exec_inspect['ExitCode'] == 0:
|
||||||
|
return False
|
||||||
|
elif exec_inspect['ExitCode'] == 1:
|
||||||
|
return True
|
||||||
|
elif exec_inspect['ExitCode'] == 137:
|
||||||
|
# NOTE(yoctozepto): This is Docker's command exit due to container
|
||||||
|
# exit. It means the container is unstable so we are better off
|
||||||
|
# marking it as requiring a restart due to config update.
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise Exception('Failed to compare container configuration: '
|
||||||
|
'ExitCode: %s Message: %s' %
|
||||||
|
(exec_inspect['ExitCode'], output))
|
||||||
|
|
||||||
def parse_image(self):
|
def parse_image(self):
|
||||||
full_image = self.params.get('image')
|
full_image = self.params.get('image')
|
||||||
|
|
||||||
|
8
releasenotes/notes/bug-1848775-b0625b7586adac96.yaml
Normal file
8
releasenotes/notes/bug-1848775-b0625b7586adac96.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Fixes an issue where configuration in containers could become stale.
|
||||||
|
This prevented containers with updated configuration from being
|
||||||
|
restarted, e.g., if the ``kolla-ansible genconfig`` and
|
||||||
|
``kolla-ansible deploy-containers`` commands were used together.
|
||||||
|
`LP#1848775 <https://launchpad.net/bugs/1848775>`__
|
@ -721,6 +721,104 @@ class TestImage(base.BaseTestCase):
|
|||||||
self.dw.dc.images.assert_called_once_with()
|
self.dw.dc.images.assert_called_once_with()
|
||||||
self.assertTrue(return_data)
|
self.assertTrue(return_data)
|
||||||
|
|
||||||
|
def test_compare_config_unchanged(self):
|
||||||
|
self.dw = get_DockerWorker(FAKE_DATA['params'])
|
||||||
|
job = mock.MagicMock()
|
||||||
|
self.dw.dc.exec_create.return_value = job
|
||||||
|
self.dw.dc.exec_start.return_value = 'fake output'
|
||||||
|
self.dw.dc.exec_inspect.return_value = {'ExitCode': 0}
|
||||||
|
return_data = self.dw.compare_config()
|
||||||
|
self.dw.dc.exec_create.assert_called_once_with(
|
||||||
|
FAKE_DATA['params']['name'],
|
||||||
|
kd.COMPARE_CONFIG_CMD,
|
||||||
|
user='root')
|
||||||
|
self.dw.dc.exec_start.assert_called_once_with(job)
|
||||||
|
self.dw.dc.exec_inspect.assert_called_once_with(job)
|
||||||
|
self.assertFalse(return_data)
|
||||||
|
|
||||||
|
def test_compare_config_changed(self):
|
||||||
|
self.dw = get_DockerWorker(FAKE_DATA['params'])
|
||||||
|
job = mock.MagicMock()
|
||||||
|
self.dw.dc.exec_create.return_value = job
|
||||||
|
self.dw.dc.exec_start.return_value = 'fake output'
|
||||||
|
self.dw.dc.exec_inspect.return_value = {'ExitCode': 1}
|
||||||
|
return_data = self.dw.compare_config()
|
||||||
|
self.dw.dc.exec_create.assert_called_once_with(
|
||||||
|
FAKE_DATA['params']['name'],
|
||||||
|
kd.COMPARE_CONFIG_CMD,
|
||||||
|
user='root')
|
||||||
|
self.dw.dc.exec_start.assert_called_once_with(job)
|
||||||
|
self.dw.dc.exec_inspect.assert_called_once_with(job)
|
||||||
|
self.assertTrue(return_data)
|
||||||
|
|
||||||
|
def test_compare_config_changed_container_exited(self):
|
||||||
|
self.dw = get_DockerWorker(FAKE_DATA['params'])
|
||||||
|
job = mock.MagicMock()
|
||||||
|
self.dw.dc.exec_create.return_value = job
|
||||||
|
self.dw.dc.exec_start.return_value = 'fake output'
|
||||||
|
self.dw.dc.exec_inspect.return_value = {'ExitCode': 137}
|
||||||
|
return_data = self.dw.compare_config()
|
||||||
|
self.dw.dc.exec_create.assert_called_once_with(
|
||||||
|
FAKE_DATA['params']['name'],
|
||||||
|
kd.COMPARE_CONFIG_CMD,
|
||||||
|
user='root')
|
||||||
|
self.dw.dc.exec_start.assert_called_once_with(job)
|
||||||
|
self.dw.dc.exec_inspect.assert_called_once_with(job)
|
||||||
|
self.assertTrue(return_data)
|
||||||
|
|
||||||
|
def test_compare_config_changed_client_failure(self):
|
||||||
|
self.dw = get_DockerWorker(FAKE_DATA['params'])
|
||||||
|
job = mock.MagicMock()
|
||||||
|
self.dw.dc.exec_create.return_value = job
|
||||||
|
self.dw.dc.exec_start.return_value = 'fake output'
|
||||||
|
failure_response = mock.MagicMock()
|
||||||
|
failure_response.status_code = 409 # any client error should do here
|
||||||
|
self.dw.dc.exec_inspect.side_effect = docker_error.APIError(
|
||||||
|
message="foo",
|
||||||
|
response=failure_response,
|
||||||
|
)
|
||||||
|
return_data = self.dw.compare_config()
|
||||||
|
self.dw.dc.exec_create.assert_called_once_with(
|
||||||
|
FAKE_DATA['params']['name'],
|
||||||
|
kd.COMPARE_CONFIG_CMD,
|
||||||
|
user='root')
|
||||||
|
self.dw.dc.exec_start.assert_called_once_with(job)
|
||||||
|
self.dw.dc.exec_inspect.assert_called_once_with(job)
|
||||||
|
self.assertTrue(return_data)
|
||||||
|
|
||||||
|
def test_compare_config_error(self):
|
||||||
|
self.dw = get_DockerWorker(FAKE_DATA['params'])
|
||||||
|
job = mock.MagicMock()
|
||||||
|
self.dw.dc.exec_create.return_value = job
|
||||||
|
self.dw.dc.exec_start.return_value = 'fake output'
|
||||||
|
self.dw.dc.exec_inspect.return_value = {'ExitCode': -1}
|
||||||
|
self.assertRaises(Exception, self.dw.compare_config) # noqa: H202
|
||||||
|
self.dw.dc.exec_create.assert_called_once_with(
|
||||||
|
FAKE_DATA['params']['name'],
|
||||||
|
kd.COMPARE_CONFIG_CMD,
|
||||||
|
user='root')
|
||||||
|
self.dw.dc.exec_start.assert_called_once_with(job)
|
||||||
|
self.dw.dc.exec_inspect.assert_called_once_with(job)
|
||||||
|
|
||||||
|
def test_compare_config_error_server_failure(self):
|
||||||
|
self.dw = get_DockerWorker(FAKE_DATA['params'])
|
||||||
|
job = mock.MagicMock()
|
||||||
|
self.dw.dc.exec_create.return_value = job
|
||||||
|
self.dw.dc.exec_start.return_value = 'fake output'
|
||||||
|
failure_response = mock.MagicMock()
|
||||||
|
failure_response.status_code = 500 # any server error should do here
|
||||||
|
self.dw.dc.exec_inspect.side_effect = docker_error.APIError(
|
||||||
|
message="foo",
|
||||||
|
response=failure_response,
|
||||||
|
)
|
||||||
|
self.assertRaises(docker_error.APIError, self.dw.compare_config)
|
||||||
|
self.dw.dc.exec_create.assert_called_once_with(
|
||||||
|
FAKE_DATA['params']['name'],
|
||||||
|
kd.COMPARE_CONFIG_CMD,
|
||||||
|
user='root')
|
||||||
|
self.dw.dc.exec_start.assert_called_once_with(job)
|
||||||
|
self.dw.dc.exec_inspect.assert_called_once_with(job)
|
||||||
|
|
||||||
def test_get_image_id_not_exists(self):
|
def test_get_image_id_not_exists(self):
|
||||||
self.dw = get_DockerWorker(
|
self.dw = get_DockerWorker(
|
||||||
{'image': 'myregistrydomain.com:5000/ubuntu:16.04'})
|
{'image': 'myregistrydomain.com:5000/ubuntu:16.04'})
|
||||||
|
Loading…
Reference in New Issue
Block a user