From 4a61309e637be4d3ba8e4bc19172447155146c81 Mon Sep 17 00:00:00 2001 From: Bogdan Dobrelya Date: Tue, 30 Oct 2018 17:05:18 +0100 Subject: [PATCH] W/a Label filter is broken for podman vs docker Related https://github.com/containers/libpod/issues/1729 Use the format that currently works for podman, but is not compatible to docker CLI. Closes-Bug: #1798785 Change-Id: Ibd9ce9c2e21eaff1404f37a680fccbec0c212223 Signed-off-by: Bogdan Dobrelya --- paunch/runner.py | 16 ++++- paunch/tests/test_runner.py | 117 ++++++++++++++++++++++++++++++++++-- 2 files changed, 126 insertions(+), 7 deletions(-) diff --git a/paunch/runner.py b/paunch/runner.py index 14abbf8..ef787d4 100644 --- a/paunch/runner.py +++ b/paunch/runner.py @@ -51,10 +51,16 @@ class BaseRunner(object): def current_config_ids(self): # List all config_id labels for managed containers + # FIXME(bogdando): remove once we have it fixed: + # https://github.com/containers/libpod/issues/1729 + if self.cont_cmd == 'docker': + fmt = '{{.Label "config_id"}}' + else: + fmt = '{{.Labels.config_id}}' cmd = [ self.cont_cmd, 'ps', '-a', '--filter', 'label=managed_by=%s' % self.managed_by, - '--format', '{{.Label "config_id"}}' + '--format', fmt ] cmd_stdout, cmd_stderr, returncode = self.execute(cmd, self.log) if returncode != 0: @@ -138,6 +144,12 @@ class BaseRunner(object): def container_names(self, conf_id=None): # list every container name, and its container_name label + # FIXME(bogdando): remove once we have it fixed: + # https://github.com/containers/libpod/issues/1729 + if self.cont_cmd == 'docker': + fmt = '{{.Label "container_name"}}' + else: + fmt = '{{.Labels.container_name}}' cmd = [ self.cont_cmd, 'ps', '-a', '--filter', 'label=managed_by=%s' % self.managed_by @@ -147,7 +159,7 @@ class BaseRunner(object): '--filter', 'label=config_id=%s' % conf_id )) cmd.extend(( - '--format', '{{.Names}} {{.Label "container_name"}}' + '--format', '{{.Names}} %s' % fmt )) cmd_stdout, cmd_stderr, returncode = self.execute(cmd, self.log) if returncode != 0: diff --git a/paunch/tests/test_runner.py b/paunch/tests/test_runner.py index 0a71e16..bc7fee4 100644 --- a/paunch/tests/test_runner.py +++ b/paunch/tests/test_runner.py @@ -23,6 +23,7 @@ class TestBaseRunner(base.TestCase): def setUp(self): super(TestBaseRunner, self).setUp() self.runner = runner.DockerRunner('tester') + self.podman_runner = runner.PodmanRunner('tester') def mock_execute(self, popen, stdout, stderr, returncode): subproc = mock.Mock() @@ -45,7 +46,7 @@ class TestBaseRunner(base.TestCase): self.assert_execute(popen, ['ls', '-l']) @mock.patch('subprocess.Popen') - def test_current_config_ids(self, popen): + def test_current_config_ids_docker(self, popen): self.mock_execute(popen, 'one\ntwo\nthree', '', 0) self.assertEqual( @@ -58,6 +59,19 @@ class TestBaseRunner(base.TestCase): '--format', '{{.Label "config_id"}}'] ) + @mock.patch('subprocess.Popen') + def test_current_config_ids_podman(self, popen): + self.mock_execute(popen, 'one\ntwo\nthree', '', 0) + self.assertEqual( + set(('one', 'two', 'three')), + self.podman_runner.current_config_ids() + ) + self.assert_execute( + popen, ['podman', 'ps', '-a', '--filter', + 'label=managed_by=tester', + '--format', '{{.Labels.config_id}}'] + ) + @mock.patch('subprocess.Popen') def test_containers_in_config(self, popen): self.mock_execute(popen, 'one\ntwo\nthree', '', 0) @@ -142,7 +156,7 @@ class TestBaseRunner(base.TestCase): ) @mock.patch('subprocess.Popen') - def test_delete_missing_configs(self, popen): + def test_delete_missing_configs_docker(self, popen): self.mock_execute(popen, 'one\ntwo\nthree\nfour', '', 0) self.runner.remove_containers = mock.Mock() @@ -159,7 +173,24 @@ class TestBaseRunner(base.TestCase): ], any_order=True) @mock.patch('subprocess.Popen') - def test_list_configs(self, popen): + def test_delete_missing_configs_podman(self, popen): + self.mock_execute(popen, 'one\ntwo\nthree\nfour', '', 0) + self.podman_runner.remove_containers = mock.Mock() + + self.podman_runner.delete_missing_configs(['two', 'three']) + self.assert_execute( + popen, ['podman', 'ps', '-a', '--filter', + 'label=managed_by=tester', + '--format', '{{.Labels.config_id}}'] + ) + + # containers one and four will be deleted + self.podman_runner.remove_containers.assert_has_calls([ + mock.call('one'), mock.call('four') + ], any_order=True) + + @mock.patch('subprocess.Popen') + def test_list_configs_docker(self, popen): self.mock_execute(popen, 'one\ntwo\nthree', '', 0) self.runner.inspect = mock.Mock( return_value={'e': 'f'}) @@ -187,6 +218,35 @@ class TestBaseRunner(base.TestCase): 'three': [{'e': 'f'}, {'e': 'f'}, {'e': 'f'}] }, result) + @mock.patch('subprocess.Popen') + def test_list_configs_podman(self, popen): + self.mock_execute(popen, 'one\ntwo\nthree', '', 0) + self.podman_runner.inspect = mock.Mock( + return_value={'e': 'f'}) + self.podman_runner.containers_in_config = mock.Mock( + return_value=['a', 'b', 'c']) + + result = self.podman_runner.list_configs() + + self.assert_execute( + popen, ['podman', 'ps', '-a', '--filter', + 'label=managed_by=tester', + '--format', '{{.Labels.config_id}}'] + ) + self.podman_runner.containers_in_config.assert_has_calls([ + mock.call('one'), mock.call('two'), mock.call('three') + ], any_order=True) + self.podman_runner.inspect.assert_has_calls([ + mock.call('a'), mock.call('b'), mock.call('c'), + mock.call('a'), mock.call('b'), mock.call('c'), + mock.call('a'), mock.call('b'), mock.call('c') + ]) + self.assertEqual({ + 'one': [{'e': 'f'}, {'e': 'f'}, {'e': 'f'}], + 'two': [{'e': 'f'}, {'e': 'f'}, {'e': 'f'}], + 'three': [{'e': 'f'}, {'e': 'f'}, {'e': 'f'}] + }, result) + @mock.patch('subprocess.Popen') def test_remove_containers(self, popen): self.mock_execute(popen, 'one\ntwo\nthree', '', 0) @@ -231,7 +291,7 @@ class TestBaseRunner(base.TestCase): ) @mock.patch('subprocess.Popen') - def test_container_names(self, popen): + def test_container_names_docker(self, popen): ps_result = '''one one two-12345678 two two two @@ -257,7 +317,33 @@ four-12345678 four ], names) @mock.patch('subprocess.Popen') - def test_container_names_by_conf_id(self, popen): + def test_container_names_podman(self, popen): + ps_result = '''one one +two-12345678 two +two two +three-12345678 three +four-12345678 four +''' + + self.mock_execute(popen, ps_result, '', 0) + + names = list(self.podman_runner.container_names()) + + self.assert_execute( + popen, ['podman', 'ps', '-a', + '--filter', 'label=managed_by=tester', + '--format', '{{.Names}} {{.Labels.container_name}}'] + ) + self.assertEqual([ + ['one', 'one'], + ['two-12345678', 'two'], + ['two', 'two'], + ['three-12345678', 'three'], + ['four-12345678', 'four'] + ], names) + + @mock.patch('subprocess.Popen') + def test_container_names_by_conf_id_docker(self, popen): ps_result = '''one one two-12345678 two ''' @@ -277,6 +363,27 @@ two-12345678 two ['two-12345678', 'two'] ], names) + @mock.patch('subprocess.Popen') + def test_container_names_by_conf_id_podman(self, popen): + ps_result = '''one one +two-12345678 two +''' + + self.mock_execute(popen, ps_result, '', 0) + + names = list(self.podman_runner.container_names('abc')) + + self.assert_execute( + popen, ['podman', 'ps', '-a', + '--filter', 'label=managed_by=tester', + '--filter', 'label=config_id=abc', + '--format', '{{.Names}} {{.Labels.container_name}}'] + ) + self.assertEqual([ + ['one', 'one'], + ['two-12345678', 'two'] + ], names) + class TestDockerRunner(TestBaseRunner):