From 691f373543d96d26b1af61c4ff7731fd888a9ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Han?= Date: Wed, 21 Nov 2018 16:17:04 +0100 Subject: [PATCH] ceph_key: add a get_key function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When checking if a key exists we also have to ensure that the key exists on the filesystem, the key can change on Ceph but still have an outdated version on the filesystem. This solves this issue. Signed-off-by: Sébastien Han --- library/ceph_key.py | 61 +++++++++++++++++++++++++++++++--------- library/test_ceph_key.py | 43 +++++++++++++++++++++++----- 2 files changed, 83 insertions(+), 21 deletions(-) diff --git a/library/ceph_key.py b/library/ceph_key.py index b566ee63f..60df45edd 100644 --- a/library/ceph_key.py +++ b/library/ceph_key.py @@ -138,7 +138,7 @@ caps: secret: AQAin8tUMICVFBAALRHNrV0Z4MXupRw4v9JQ6Q== caps: mon: allow * - dest: "/var/lib/ceph/tmp/keyring.mon" + dest: "/var/lib/ceph/tmp/" import_key: False - name: create cephx key @@ -268,13 +268,10 @@ def generate_ceph_authtool_cmd(cluster, name, secret, caps, auid, dest, containe Generate 'ceph-authtool' command line to execute ''' - file_destination = os.path.join( - dest + "/" + cluster + "." + name + ".keyring") - cmd = [ 'ceph-authtool', '--create-keyring', - file_destination, + dest, '--name', name, '--add-key', @@ -297,12 +294,10 @@ def create_key(module, result, cluster, name, secret, caps, import_key, auid, de Create a CephX key ''' - file_path = os.path.join(dest + "/" + cluster + "." + name + ".keyring") - args = [ 'import', '-i', - file_path, + dest, ] cmd_list = [] @@ -366,6 +361,29 @@ def delete_key(cluster, name, containerized=None): return cmd_list +def get_key(cluster, name, dest, containerized=None): + ''' + Get a CephX key (write on the filesystem) + ''' + + cmd_list = [] + + args = [ + 'get', + name, + '-o', + dest, + ] + + user = "client.admin" + user_key = os.path.join( + "/etc/ceph/" + cluster + ".client.admin.keyring") + cmd_list.append(generate_ceph_cmd( + cluster, args, user, user_key, containerized)) + + return cmd_list + + def info_key(cluster, name, user, user_key, output_format, containerized=None): ''' Get information about a CephX key @@ -478,7 +496,7 @@ def run_module(): secret=dict(type='str', required=False, default=None), import_key=dict(type='bool', required=False, default=True), auid=dict(type='str', required=False, default=None), - dest=dict(type='str', required=False, default='/etc/ceph/'), + dest=dict(type='str', required=False, default='/etc/ceph'), ) module = AnsibleModule( @@ -528,21 +546,30 @@ def run_module(): if not caps: fatal("Capabilities must be provided when state is 'present'", module) # noqa E501 + # Build a different path for bootstrap keys as there are stored as + # /var/lib/ceph/bootstrap-rbd/ceph.keyring + if 'bootstrap' in dest: + file_path = os.path.join(dest + "/" + cluster + ".keyring") + else: + file_path = os.path.join(dest + "/" + cluster + + "." + name + ".keyring") + # We allow 'present' to override any existing key # ONLY if a secret is provided # if not we skip the creation if import_key: if rc == 0 and not secret: - result["stdout"] = "skipped, since {0} already exists, if you want to update a key use 'state: update'".format( # noqa E501 - name) + # If the key exists in Ceph we must fetch it on the system + # because nothing tells us it exists on the fs or not + rc, cmd, out, err = exec_commands(module, get_key(cluster, name, file_path, containerized)) # noqa E501 + result["stdout"] = "skipped, since {0} already exists, we only fetched the key at {1}. If you want to update a key use 'state: update'".format( # noqa E501 + name, file_path) result['rc'] = rc module.exit_json(**result) rc, cmd, out, err = exec_commands(module, create_key( - module, result, cluster, name, secret, caps, import_key, auid, dest, containerized)) # noqa E501 + module, result, cluster, name, secret, caps, import_key, auid, file_path, containerized)) # noqa E501 - file_path = os.path.join( - dest + "/" + cluster + "." + name + ".keyring") file_args = module.load_file_common_arguments(module.params) file_args['path'] = file_path module.set_fs_attributes_if_different(file_args, False) @@ -557,6 +584,8 @@ def run_module(): rc, cmd, out, err = exec_commands( module, update_key(cluster, name, caps, containerized)) + # After the update we don't need to overwrite the key on the filesystem + # since the secret has not changed elif state == "absent": rc, cmd, out, err = exec_commands( @@ -625,6 +654,10 @@ def run_module(): module, info_cmd) # noqa E501 # apply ceph:ceph ownership and mode 0400 on keys + # FIXME by using + # file_args = module.load_file_common_arguments(module.params) + # file_args['path'] = dest + # module.set_fs_attributes_if_different(file_args, False) try: os.chown(key_path, ceph_uid, ceph_grp) os.chmod(key_path, stat.S_IRUSR) diff --git a/library/test_ceph_key.py b/library/test_ceph_key.py index 113c1d5d4..b8761fac3 100644 --- a/library/test_ceph_key.py +++ b/library/test_ceph_key.py @@ -120,7 +120,7 @@ class TestCephKeyModule(object): 'allow rwx', ] result = ceph_key.generate_ceph_authtool_cmd( - fake_cluster, fake_name, fake_secret, fake_caps, fake_auid, fake_dest) # noqa E501 + fake_cluster, fake_name, fake_secret, fake_caps, fake_auid, fake_file_destination) # noqa E501 assert result == expected_command_list def test_generate_ceph_authtool_cmd_non_container_auid(self): @@ -153,7 +153,7 @@ class TestCephKeyModule(object): 'allow rwx', ] result = ceph_key.generate_ceph_authtool_cmd( - fake_cluster, fake_name, fake_secret, fake_caps, fake_auid, fake_dest) # noqa E501 + fake_cluster, fake_name, fake_secret, fake_caps, fake_auid, fake_file_destination) # noqa E501 assert result == expected_command_list def test_generate_ceph_authtool_cmd_container(self): @@ -189,7 +189,7 @@ class TestCephKeyModule(object): 'allow rwx' ] result = ceph_key.generate_ceph_authtool_cmd( - fake_cluster, fake_name, fake_secret, fake_caps, fake_auid, fake_dest, fake_containerized) # noqa E501 + fake_cluster, fake_name, fake_secret, fake_caps, fake_auid, fake_file_destination, fake_containerized) # noqa E501 assert result == expected_command_list def test_create_key_non_container(self): @@ -214,7 +214,7 @@ class TestCephKeyModule(object): 'import', '-i', fake_file_destination], ] result = ceph_key.create_key(fake_module, fake_result, fake_cluster, - fake_name, fake_secret, fake_caps, fake_import_key, fake_auid, fake_dest) # noqa E501 + fake_name, fake_secret, fake_caps, fake_import_key, fake_auid, fake_file_destination) # noqa E501 assert result == expected_command_list def test_create_key_container(self): @@ -240,7 +240,7 @@ class TestCephKeyModule(object): fake_cluster, 'auth', 'import', '-i', fake_file_destination], ] result = ceph_key.create_key(fake_module, fake_result, fake_cluster, fake_name, # noqa E501 - fake_secret, fake_caps, fake_import_key, fake_auid, fake_dest, fake_containerized) # noqa E501 + fake_secret, fake_caps, fake_import_key, fake_auid, fake_file_destination, fake_containerized) # noqa E501 assert result == expected_command_list def test_create_key_non_container_no_import(self): @@ -275,7 +275,7 @@ class TestCephKeyModule(object): 'allow rwx', ] ] result = ceph_key.create_key(fake_module, fake_result, fake_cluster, - fake_name, fake_secret, fake_caps, fake_import_key, fake_auid, fake_dest) # noqa E501 + fake_name, fake_secret, fake_caps, fake_import_key, fake_auid, fake_file_destination) # noqa E501 assert result == expected_command_list def test_create_key_container_no_import(self): @@ -315,7 +315,7 @@ class TestCephKeyModule(object): 'allow rwx', ] ] result = ceph_key.create_key(fake_module, fake_result, fake_cluster, fake_name, # noqa E501 - fake_secret, fake_caps, fake_import_key, fake_auid, fake_dest, fake_containerized) # noqa E501 + fake_secret, fake_caps, fake_import_key, fake_auid, fake_file_destination, fake_containerized) # noqa E501 assert result == expected_command_list def test_update_key_non_container(self): @@ -410,6 +410,35 @@ class TestCephKeyModule(object): result = ceph_key.list_keys(fake_cluster, fake_user, fake_key) assert result == expected_command_list + def test_get_key_container(self): + fake_cluster = "fake" + fake_name = "client.fake" + fake_containerized = "docker exec -ti ceph-mon" + fake_dest = "/fake/ceph" + fake_file_destination = os.path.join( + fake_dest + "/" + fake_cluster + "." + fake_name + ".keyring") + expected_command_list = [ + ['docker', 'exec', '-ti', 'ceph-mon', 'ceph', '-n', "client.admin", '-k', "/etc/ceph/fake.client.admin.keyring", '--cluster', # noqa E501 + fake_cluster, 'auth', 'get', fake_name, '-o', fake_file_destination], # noqa E501 + ] + result = ceph_key.get_key( + fake_cluster, fake_name, fake_file_destination, fake_containerized) # noqa E501 + assert result == expected_command_list + + def test_get_key_non_container(self): + fake_cluster = "fake" + fake_dest = "/fake/ceph" + fake_name = "client.fake" + fake_file_destination = os.path.join( + fake_dest + "/" + fake_cluster + "." + fake_name + ".keyring") + expected_command_list = [ + ['ceph', '-n', "client.admin", '-k', "/etc/ceph/fake.client.admin.keyring", # noqa E501 + '--cluster', fake_cluster, 'auth', 'get', fake_name, '-o', fake_file_destination], # noqa E501 + ] + result = ceph_key.get_key( + fake_cluster, fake_name, fake_file_destination) # noqa E501 + assert result == expected_command_list + def test_list_key_non_container_with_mon_key(self): fake_hostname = "mon01" fake_cluster = "fake"