diff --git a/ansible/library/kolla_docker.py b/ansible/library/kolla_docker.py index 00946302a0..c177c00864 100644 --- a/ansible/library/kolla_docker.py +++ b/ansible/library/kolla_docker.py @@ -40,6 +40,7 @@ options: - get_container_state - pull_image - remove_container + - remove_image - remove_volume - recreate_or_restart_container - restart_container @@ -199,6 +200,10 @@ EXAMPLES = ''' kolla_docker: action: remove_volume name: name_of_volume + - name: Remove image + kolla_docker: + action: remove_image + image: name_of_image ''' import json @@ -767,6 +772,26 @@ class DockerWorker(object): ) raise + def remove_image(self): + if self.check_image(): + self.changed = True + try: + self.dc.remove_image(image=self.params.get('image')) + except docker.errors.APIError as e: + if e.response.status_code == 409: + self.module.fail_json( + failed=True, + msg="Image '{}' is currently in-use".format( + self.params.get('image') + ) + ) + elif e.response.status_code == 500: + self.module.fail_json( + failed=True, + msg="Server error" + ) + raise + def generate_module(): # NOTE(jeffrey4l): add empty string '' to choices let us use @@ -778,9 +803,9 @@ def generate_module(): 'create_volume', 'get_container_env', 'get_container_state', 'pull_image', 'recreate_or_restart_container', - 'remove_container', 'remove_volume', - 'restart_container', 'start_container', - 'stop_container']), + 'remove_container', 'remove_image', + 'remove_volume', 'restart_container', + 'start_container', 'stop_container']), api_version=dict(required=False, type='str', default='auto'), auth_email=dict(required=False, type='str'), auth_password=dict(required=False, type='str', no_log=True), @@ -830,6 +855,7 @@ def generate_module(): ['action', 'get_container_state', ['name']], ['action', 'recreate_or_restart_container', ['name']], ['action', 'remove_container', ['name']], + ['action', 'remove_image', ['image']], ['action', 'remove_volume', ['name']], ['action', 'restart_container', ['name']], ['action', 'stop_container', ['name']] diff --git a/tests/test_kolla_docker.py b/tests/test_kolla_docker.py index d2e7a9de72..aab7a1b343 100644 --- a/tests/test_kolla_docker.py +++ b/tests/test_kolla_docker.py @@ -44,7 +44,7 @@ class ModuleArgsTest(base.BaseTestCase): choices=['compare_container', 'compare_image', 'create_volume', 'get_container_env', 'get_container_state', 'pull_image', 'recreate_or_restart_container', - 'remove_container', 'remove_volume', + 'remove_container', 'remove_image', 'remove_volume', 'restart_container', 'start_container', 'stop_container']), api_version=dict(required=False, type='str', default='auto'), @@ -96,6 +96,7 @@ class ModuleArgsTest(base.BaseTestCase): ['action', 'get_container_state', ['name']], ['action', 'recreate_or_restart_container', ['name']], ['action', 'remove_container', ['name']], + ['action', 'remove_image', ['image']], ['action', 'remove_volume', ['name']], ['action', 'restart_container', ['name']], ['action', 'stop_container', ['name']] @@ -606,6 +607,61 @@ class TestImage(base.BaseTestCase): msg="Unknown error message: unexpected error", failed=True) + def test_remove_image(self): + self.dw = get_DockerWorker( + {'image': 'myregistrydomain.com:5000/ubuntu:16.04', + 'action': 'remove_image'}) + self.dw.dc.images.return_value = self.fake_data['images'] + + self.dw.remove_image() + self.assertTrue(self.dw.changed) + self.dw.dc.remove_image.assert_called_once_with( + image='myregistrydomain.com:5000/ubuntu:16.04') + + def test_remove_image_not_exists(self): + self.dw = get_DockerWorker( + {'image': 'myregistrydomain.com:5000/non_existing:16.04', + 'action': 'remove_image'}) + self.dw.dc.images.return_value = self.fake_data['images'] + + self.dw.remove_image() + self.assertFalse(self.dw.changed) + + def test_remove_image_exception_409(self): + resp = mock.MagicMock() + resp.status_code = 409 + docker_except = docker_error.APIError('test error', resp) + self.dw = get_DockerWorker( + {'image': 'myregistrydomain.com:5000/ubuntu:16.04', + 'action': 'remove_image'}) + self.dw.dc.images.return_value = self.fake_data['images'] + self.dw.dc.remove_image.side_effect = docker_except + + self.assertRaises(docker_error.APIError, self.dw.remove_image) + self.assertTrue(self.dw.changed) + self.dw.module.fail_json.assert_called_once_with( + failed=True, + msg=("Image 'myregistrydomain.com:5000/ubuntu:16.04' " + "is currently in-use") + ) + + def test_remove_image_exception_500(self): + resp = mock.MagicMock() + resp.status_code = 500 + docker_except = docker_error.APIError('test error', resp) + self.dw = get_DockerWorker( + {'image': 'myregistrydomain.com:5000/ubuntu:16.04', + 'action': 'remove_image'}) + self.dw.dc.images.return_value = self.fake_data['images'] + self.dw.dc.remove_image.side_effect = docker_except + + self.assertRaises(docker_error.APIError, self.dw.remove_image) + self.assertTrue(self.dw.changed) + self.dw.module.fail_json.assert_called_once_with( + failed=True, + msg=("Server error") + ) + class TestVolume(base.BaseTestCase):