From 279264f4c934b6d66fa620f3736c4a69b95bd258 Mon Sep 17 00:00:00 2001 From: Mark Goddard Date: Fri, 25 Sep 2020 09:49:50 +0000 Subject: [PATCH] Add support to kolla_docker for tmpfs mounts Partial-Bug: #1897276 Change-Id: Ia06da456a7f26f0f2ceebc35eb88c0da0767e1c6 --- ansible/library/kolla_docker.py | 26 +++++++++ .../notes/docker-tmpfs-2599b2785edeecd2.yaml | 5 ++ tests/test_kolla_docker.py | 53 ++++++++++++++++++- 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/docker-tmpfs-2599b2785edeecd2.yaml diff --git a/ansible/library/kolla_docker.py b/ansible/library/kolla_docker.py index 224c424587..c76392eda6 100644 --- a/ansible/library/kolla_docker.py +++ b/ansible/library/kolla_docker.py @@ -176,6 +176,11 @@ options: - How many times to attempt a restart if 'on-failure' policy is set type: int default: 10 + tmpfs: + description: + - List of paths to mount as tmpfs. + required: False + type: list volumes: description: - Set volumes for docker to use @@ -342,6 +347,7 @@ class DockerWorker(object): self.compare_labels(container_info) or self.compare_privileged(container_info) or self.compare_pid_mode(container_info) or + self.compare_tmpfs(container_info) or self.compare_volumes(container_info) or self.compare_volumes_from(container_info) or self.compare_environment(container_info) or @@ -433,6 +439,17 @@ class DockerWorker(object): if new_labels != current_labels: return True + def compare_tmpfs(self, container_info): + new_tmpfs = self.generate_tmpfs() + current_tmpfs = container_info['HostConfig'].get('Tmpfs') + if not new_tmpfs: + new_tmpfs = [] + if not current_tmpfs: + current_tmpfs = [] + + if set(current_tmpfs).symmetric_difference(set(new_tmpfs)): + return True + def compare_volumes_from(self, container_info): new_vols_from = self.params.get('volumes_from') current_vols_from = container_info['HostConfig'].get('VolumesFrom') @@ -637,6 +654,13 @@ class DockerWorker(object): if self.check_container(): raise + def generate_tmpfs(self): + tmpfs = self.params.get('tmpfs') + if tmpfs: + # NOTE(mgoddard): Filter out any empty strings. + tmpfs = [t for t in tmpfs if t] + return tmpfs + def generate_volumes(self): volumes = self.params.get('volumes') if not volumes: @@ -711,6 +735,7 @@ class DockerWorker(object): 'security_opt': self.params.get('security_opt'), 'pid_mode': self.params.get('pid_mode'), 'privileged': self.params.get('privileged'), + 'tmpfs': self.generate_tmpfs(), 'volumes_from': self.params.get('volumes_from') } @@ -1066,6 +1091,7 @@ def generate_module(): tls_cert=dict(required=False, type='str'), tls_key=dict(required=False, type='str'), tls_cacert=dict(required=False, type='str'), + tmpfs=dict(required=False, type='list'), volumes=dict(required=False, type='list'), volumes_from=dict(required=False, type='list'), dimensions=dict(required=False, type='dict', default=dict()), diff --git a/releasenotes/notes/docker-tmpfs-2599b2785edeecd2.yaml b/releasenotes/notes/docker-tmpfs-2599b2785edeecd2.yaml new file mode 100644 index 0000000000..a82aac14b6 --- /dev/null +++ b/releasenotes/notes/docker-tmpfs-2599b2785edeecd2.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Adds support to the ``kolla_docker`` module for creating ``tmpfs`` mounts + for containers. diff --git a/tests/test_kolla_docker.py b/tests/test_kolla_docker.py index c8dca3572e..fb724aad8d 100644 --- a/tests/test_kolla_docker.py +++ b/tests/test_kolla_docker.py @@ -88,6 +88,7 @@ class ModuleArgsTest(base.BaseTestCase): tls_cert=dict(required=False, type='str'), tls_key=dict(required=False, type='str'), tls_cacert=dict(required=False, type='str'), + tmpfs=dict(required=False, type='list'), volumes=dict(required=False, type='list'), volumes_from=dict(required=False, type='list'), dimensions=dict(required=False, type='dict', default=dict()), @@ -136,6 +137,7 @@ FAKE_DATA = { 'security_opt': None, 'pid_mode': '', 'privileged': False, + 'tmpfs': None, 'volumes_from': None, 'restart_policy': 'unless-stopped', 'restart_retries': 10}, @@ -276,7 +278,7 @@ class TestContainer(base.BaseTestCase): **{k: self.fake_data['params'][k] for k in expected_args}) self.dw.dc.create_host_config.assert_called_with( cap_add=None, network_mode='host', ipc_mode=None, - pid_mode=None, volumes_from=None, blkio_weight=10, + pid_mode=None, tmpfs=None, volumes_from=None, blkio_weight=10, security_opt=None, privileged=None) def test_create_container_wrong_dimensions(self): @@ -303,6 +305,25 @@ class TestContainer(base.BaseTestCase): self.dw.dc.create_container.assert_called_once_with( **{k: self.fake_data['params'][k] for k in expected_args}) + def test_create_container_with_tmpfs(self): + self.fake_data['params']['tmpfs'] = ['/tmp'] # nosec: B108 + self.dw = get_DockerWorker(self.fake_data['params']) + self.dw.dc.create_host_config = mock.MagicMock( + return_value=self.fake_data['params']['host_config']) + self.dw.create_container() + self.assertTrue(self.dw.changed) + self.assertEqual(['/tmp'], # nosec: B108 + self.dw.dc.create_host_config.call_args[1]['tmpfs']) + + def test_create_container_with_tmpfs_empty_string(self): + self.fake_data['params']['tmpfs'] = [''] + self.dw = get_DockerWorker(self.fake_data['params']) + self.dw.dc.create_host_config = mock.MagicMock( + return_value=self.fake_data['params']['host_config']) + self.dw.create_container() + self.assertTrue(self.dw.changed) + self.assertFalse(self.dw.dc.create_host_config.call_args[1]['tmpfs']) + def test_start_container_without_pull(self): self.fake_data['params'].update({'auth_username': 'fake_user', 'auth_password': 'fake_psw', @@ -979,6 +1000,36 @@ class TestAttrComp(base.BaseTestCase): Labels={'kolla_version': '1.0.1'})) self.assertTrue(self.dw.compare_labels(container_info)) + def test_compare_tmpfs_neg(self): + container_info = {'HostConfig': dict(Tmpfs=['foo'])} + self.dw = get_DockerWorker({'tmpfs': ['foo']}) + + self.assertFalse(self.dw.compare_tmpfs(container_info)) + + def test_compare_tmpfs_neg_empty_string(self): + container_info = {'HostConfig': dict()} + self.dw = get_DockerWorker({'tmpfs': ['']}) + + self.assertFalse(self.dw.compare_tmpfs(container_info)) + + def test_compare_tmpfs_pos_different(self): + container_info = {'HostConfig': dict(Tmpfs=['foo'])} + self.dw = get_DockerWorker({'tmpfs': ['bar']}) + + self.assertTrue(self.dw.compare_tmpfs(container_info)) + + def test_compare_tmpfs_pos_empty_new(self): + container_info = {'HostConfig': dict(Tmpfs=['foo'])} + self.dw = get_DockerWorker({}) + + self.assertTrue(self.dw.compare_tmpfs(container_info)) + + def test_compare_tmpfs_pos_empty_current(self): + container_info = {'HostConfig': dict()} + self.dw = get_DockerWorker({'tmpfs': ['bar']}) + + self.assertTrue(self.dw.compare_tmpfs(container_info)) + def test_compare_volumes_from_neg(self): container_info = {'HostConfig': dict(VolumesFrom=['777f7dc92da7'])} self.dw = get_DockerWorker({'volumes_from': ['777f7dc92da7']})