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 <dsavinea@redhat.com>
(cherry picked from commit 7d3d51d6da)
pull/7347/head
Dimitri Savineau 2020-10-23 14:50:52 -04:00 committed by Guillaume Abrioux
parent a8fe484e15
commit c1dd0a6cbe
2 changed files with 55 additions and 15 deletions

View File

@ -113,6 +113,12 @@ options:
This command can ONLY run from a monitor node. This command can ONLY run from a monitor node.
required: false required: false
default: false default: false
output_format:
description:
- The key output format when retrieving the information of an
entity.
required: false
default: json
''' '''
EXAMPLES = ''' EXAMPLES = '''
@ -173,6 +179,13 @@ caps:
name: "my_key"" name: "my_key""
state: info 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 - name: list cephx keys
ceph_key: ceph_key:
state: list state: list
@ -512,7 +525,8 @@ def run_module():
import_key=dict(type='bool', required=False, default=True), import_key=dict(type='bool', required=False, default=True),
dest=dict(type='str', required=False, default='/etc/ceph/'), dest=dict(type='str', required=False, default='/etc/ceph/'),
user=dict(type='str', required=False, default='client.admin'), 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( module = AnsibleModule(
@ -533,6 +547,7 @@ def run_module():
dest = module.params.get('dest') dest = module.params.get('dest')
user = module.params.get('user') user = module.params.get('user')
user_key = module.params.get('user_key') user_key = module.params.get('user_key')
output_format = module.params.get('output_format')
changed = False changed = False
@ -568,8 +583,6 @@ def run_module():
else: else:
user_key_path = user_key user_key_path = user_key
output_format = "json"
if (state in ["present", "update"]): if (state in ["present", "update"]):
# if dest is not a directory, the user wants to change the file's name # if dest is not a directory, the user wants to change the file's name
# (e,g: /etc/ceph/ceph.mgr.ceph-mon2.keyring) # (e,g: /etc/ceph/ceph.mgr.ceph-mon2.keyring)

View File

@ -25,10 +25,18 @@ class AnsibleExitJson(Exception):
pass pass
class AnsibleFailJson(Exception):
pass
def exit_json(*args, **kwargs): def exit_json(*args, **kwargs):
raise AnsibleExitJson(kwargs) raise AnsibleExitJson(kwargs)
def fail_json(*args, **kwargs):
raise AnsibleFailJson(kwargs)
@mock.patch.dict(os.environ, {'CEPH_CONTAINER_BINARY': 'docker'}) @mock.patch.dict(os.environ, {'CEPH_CONTAINER_BINARY': 'docker'})
class TestCephKeyModule(object): class TestCephKeyModule(object):
@ -373,29 +381,29 @@ class TestCephKeyModule(object):
fake_cluster, fake_user, fake_user_key, fake_name, fake_container_image) fake_cluster, fake_user, fake_user_key, fake_name, fake_container_image)
assert result == expected_command_list 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 = 'client.admin'
fake_user_key = '/etc/ceph/fake.client.admin.keyring' fake_user_key = '/etc/ceph/fake.client.admin.keyring'
fake_cluster = "fake" fake_cluster = "fake"
fake_name = "client.fake" fake_name = "client.fake"
fake_user = "fake-user" fake_user = "fake-user"
fake_output_format = "json"
expected_command_list = [ expected_command_list = [
['ceph', '-n', fake_user, '-k', fake_user_key, '--cluster', fake_cluster, 'auth', ['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( 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 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_cluster = "fake"
fake_name = "client.fake" fake_name = "client.fake"
fake_user = 'client.admin' fake_user = 'client.admin'
fake_user_key = '/etc/ceph/fake.client.admin.keyring' fake_user_key = '/etc/ceph/fake.client.admin.keyring'
fake_output_format = "json"
fake_container_image = "quay.ceph.io/ceph-ci/daemon:latest-nautilus" fake_container_image = "quay.ceph.io/ceph-ci/daemon:latest-nautilus"
expected_command_list = [['docker', expected_command_list = [['docker', # noqa E128
'run', 'run',
'--rm', '--rm',
'--net=host', '--net=host',
@ -408,9 +416,9 @@ class TestCephKeyModule(object):
'-k', fake_user_key, '-k', fake_user_key,
'--cluster', fake_cluster, '--cluster', fake_cluster,
'auth', 'get', fake_name, 'auth', 'get', fake_name,
'-f', 'json']] '-f', output_format]]
result = ceph_key.info_key( 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 assert result == expected_command_list
def test_list_key_non_container(self): 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('ansible.module_utils.basic.AnsibleModule.exit_json')
@mock.patch('ceph_key.exec_commands') @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", set_module_args({"state": "info",
"cluster": "ceph", "cluster": "ceph",
"name": "client.admin"} "name": "client.admin",
"output_format": output_format}
) )
m_exit_json.side_effect = exit_json m_exit_json.side_effect = exit_json
m_exec_commands.return_value = (0, 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 '[{"entity":"client.admin","key":"AQC1tw5fF156GhAAoJCvHGX/jl/k7/N4VZm8iQ==","caps":{"mds":"allow *","mgr":"allow *","mon":"allow *","osd":"allow *"}}]', # noqa: E501
'exported keyring for client.admin') 'exported keyring for client.admin')
@ -568,6 +578,7 @@ class TestCephKeyModule(object):
result = result.value.args[0] result = result.value.args[0]
assert not result['changed'] 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['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['stderr'] == 'exported keyring for client.admin'
assert result['rc'] == 0 assert result['rc'] == 0
@ -583,3 +594,19 @@ class TestCephKeyModule(object):
with pytest.raises(AnsibleExitJson) as result: with pytest.raises(AnsibleExitJson) as result:
ceph_key.run_module() ceph_key.run_module()
assert result.value.args[0]['stdout'] == fake_secret.decode() assert result.value.args[0]['stdout'] == fake_secret.decode()
@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)