From 7d3d51d6da9214a95923e870c2c5bd9627656ff2 Mon Sep 17 00:00:00 2001 From: Dimitri Savineau Date: Fri, 23 Oct 2020 14:50:52 -0400 Subject: [PATCH] library/ceph_key: add output format parameter The ceph_key module currently only supports the json output for the info state. When using this state on an entity then we something want the output as: - plain for copying it to another node. - json in order to get only a subset information of the entity (like the key or caps). This patch adds the output_format parameter which uses json as a default value for backward compatibility. It removes the internal and hardcoded variable also called output_format. In addition of json and plain outputs, there's also xml and yaml values available. Signed-off-by: Dimitri Savineau --- library/ceph_key.py | 19 ++++++++++--- tests/library/test_ceph_key.py | 49 ++++++++++++++++++++++++++-------- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/library/ceph_key.py b/library/ceph_key.py index 92a5a2528..2be37ed84 100644 --- a/library/ceph_key.py +++ b/library/ceph_key.py @@ -103,6 +103,12 @@ options: This command can ONLY run from a monitor node. required: false default: false + output_format: + description: + - The key output format when retrieving the information of an + entity. + required: false + default: json ''' EXAMPLES = ''' @@ -163,6 +169,13 @@ caps: name: "my_key"" state: info +- name: info cephx admin key (plain) + ceph_key: + name: client.admin + output_format: plain + state: info + register: client_admin_key + - name: list cephx keys ceph_key: state: list @@ -512,7 +525,8 @@ def run_module(): import_key=dict(type='bool', required=False, default=True), dest=dict(type='str', required=False, default='/etc/ceph/'), user=dict(type='str', required=False, default='client.admin'), - user_key=dict(type='str', required=False, default=None) + user_key=dict(type='str', required=False, default=None), + output_format=dict(type='str', required=False, default='json', choices=['json', 'plain', 'xml', 'yaml']) ) module = AnsibleModule( @@ -533,6 +547,7 @@ def run_module(): dest = module.params.get('dest') user = module.params.get('user') user_key = module.params.get('user_key') + output_format = module.params.get('output_format') changed = False @@ -568,8 +583,6 @@ def run_module(): else: user_key_path = user_key - output_format = "json" - if (state in ["present", "update"]): # if dest is not a directory, the user wants to change the file's name # (e,g: /etc/ceph/ceph.mgr.ceph-mon2.keyring) diff --git a/tests/library/test_ceph_key.py b/tests/library/test_ceph_key.py index 56eb89185..87c7ccac1 100644 --- a/tests/library/test_ceph_key.py +++ b/tests/library/test_ceph_key.py @@ -25,10 +25,18 @@ class AnsibleExitJson(Exception): pass +class AnsibleFailJson(Exception): + pass + + def exit_json(*args, **kwargs): raise AnsibleExitJson(kwargs) +def fail_json(*args, **kwargs): + raise AnsibleFailJson(kwargs) + + @mock.patch.dict(os.environ, {'CEPH_CONTAINER_BINARY': 'docker'}) class TestCephKeyModule(object): @@ -373,27 +381,27 @@ class TestCephKeyModule(object): fake_cluster, fake_user, fake_user_key, fake_name, fake_container_image) assert result == expected_command_list - def test_info_key_non_container(self): + @pytest.mark.parametrize('output_format', ['json', 'plain', 'xml', 'yaml']) + def test_info_key_non_container(self, output_format): fake_user = 'client.admin' fake_user_key = '/etc/ceph/fake.client.admin.keyring' fake_cluster = "fake" fake_name = "client.fake" fake_user = "fake-user" - fake_output_format = "json" expected_command_list = [ ['ceph', '-n', fake_user, '-k', fake_user_key, '--cluster', fake_cluster, 'auth', - 'get', fake_name, '-f', 'json'], + 'get', fake_name, '-f', output_format], ] result = ceph_key.info_key( - fake_cluster, fake_name, fake_user, fake_user_key, fake_output_format) + fake_cluster, fake_name, fake_user, fake_user_key, output_format) assert result == expected_command_list - def test_info_key_container(self): + @pytest.mark.parametrize('output_format', ['json', 'plain', 'xml', 'yaml']) + def test_info_key_container_json(self, output_format): fake_cluster = "fake" fake_name = "client.fake" fake_user = 'client.admin' fake_user_key = '/etc/ceph/fake.client.admin.keyring' - fake_output_format = "json" fake_container_image = "quay.ceph.io/ceph-ci/daemon:latest-luminous" expected_command_list = [['docker', # noqa E128 'run', @@ -408,9 +416,9 @@ class TestCephKeyModule(object): '-k', fake_user_key, '--cluster', fake_cluster, 'auth', 'get', fake_name, - '-f', 'json']] + '-f', output_format]] result = ceph_key.info_key( - fake_cluster, fake_name, fake_user, fake_user_key, fake_output_format, fake_container_image) # noqa E501 + fake_cluster, fake_name, fake_user, fake_user_key, output_format, fake_container_image) # noqa E501 assert result == expected_command_list def test_list_key_non_container(self): @@ -552,14 +560,16 @@ class TestCephKeyModule(object): @mock.patch('ansible.module_utils.basic.AnsibleModule.exit_json') @mock.patch('ceph_key.exec_commands') - def test_state_info(self, m_exec_commands, m_exit_json): + @pytest.mark.parametrize('output_format', ['json', 'plain', 'xml', 'yaml']) + def test_state_info(self, m_exec_commands, m_exit_json, output_format): set_module_args({"state": "info", "cluster": "ceph", - "name": "client.admin"} + "name": "client.admin", + "output_format": output_format} ) m_exit_json.side_effect = exit_json m_exec_commands.return_value = (0, - ['ceph', 'auth', 'get', 'client.admin', '-f', 'json'], + ['ceph', 'auth', 'get', 'client.admin', '-f', output_format], '[{"entity":"client.admin","key":"AQC1tw5fF156GhAAoJCvHGX/jl/k7/N4VZm8iQ==","caps":{"mds":"allow *","mgr":"allow *","mon":"allow *","osd":"allow *"}}]', # noqa: E501 'exported keyring for client.admin') @@ -568,6 +578,23 @@ class TestCephKeyModule(object): result = result.value.args[0] assert not result['changed'] + assert result['cmd'] == ['ceph', 'auth', 'get', 'client.admin', '-f', output_format] assert result['stdout'] == '[{"entity":"client.admin","key":"AQC1tw5fF156GhAAoJCvHGX/jl/k7/N4VZm8iQ==","caps":{"mds":"allow *","mgr":"allow *","mon":"allow *","osd":"allow *"}}]' # noqa: E501 assert result['stderr'] == 'exported keyring for client.admin' assert result['rc'] == 0 + + @mock.patch('ansible.module_utils.basic.AnsibleModule.fail_json') + def test_state_info_invalid_format(self, m_fail_json): + invalid_format = 'txt' + set_module_args({"state": "info", + "cluster": "ceph", + "name": "client.admin", + "output_format": invalid_format} + ) + m_fail_json.side_effect = fail_json + + with pytest.raises(AnsibleFailJson) as result: + ceph_key.run_module() + + result = result.value.args[0] + assert result['msg'] == 'value of output_format must be one of: json, plain, xml, yaml, got: {}'.format(invalid_format) -- 2.39.5