From c1730c21ce8b7902718bcf81b732243b76cc5c11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Moser?= Date: Sun, 5 Mar 2017 22:47:19 +0100 Subject: [PATCH] cloudstack: cs_sshkeypair: fix fingerprint not used as identifier (#22276) * cloudstack: cs_sshkeypair: fix fingerprint not used as identifier * remove from legacy * fix for 2 keys, one with name and one with fingerprint --- .../modules/cloud/cloudstack/cs_sshkeypair.py | 121 +++++++++++------- test/sanity/pep8/legacy-files.txt | 1 - 2 files changed, 72 insertions(+), 50 deletions(-) diff --git a/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py b/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py index 1ca4f66f4bb..721c5d1c512 100644 --- a/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py +++ b/lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py @@ -109,102 +109,126 @@ private_key: description: Private key of generated SSH keypair. returned: changed type: string - sample: "-----BEGIN RSA PRIVATE KEY-----\nMIICXQIBAAKBgQCkeFYjI+4k8bWfIRMzp4pCzhlopNydbbwRu824P5ilD4ATWMUG\nvEtuCQ2Mp5k5Bma30CdYHgh2/SbxC5RxXSUKTUJtTKpoJUy8PAhb1nn9dnfkC2oU\naRVi9NRUgypTIZxMpgooHOxvAzWxbZCyh1W+91Ld3FNaGxTLqTgeevY84wIDAQAB\nAoGAcwQwgLyUwsNB1vmjWwE0QEmvHS4FlhZyahhi4hGfZvbzAxSWHIK7YUT1c8KU\n9XsThEIN8aJ3GvcoL3OAqNKRnoNb14neejVHkYRadhxqc0GVN6AUIyCqoEMpvhFI\nQrinM572ORzv5ffRjCTbvZcYlW+sqFKNo5e8pYIB8TigpFECQQDu7bg9vkvg8xPs\nkP1K+EH0vsR6vUfy+m3euXjnbJtiP7RoTkZk0JQMOmexgy1qQhISWT0e451wd62v\nJ7M0trl5AkEAsDivJnMIlCCCypwPN4tdNUYpe9dtidR1zLmb3SA7wXk5xMUgLZI9\ncWPjBCMt0KKShdDhQ+hjXAyKQLF7iAPuOwJABjdHCMwvmy2XwhrPjCjDRoPEBtFv\n0sFzJE08+QBZVogDwIbwy+SlRWArnHGmN9J6N+H8dhZD3U4vxZPJ1MBAOQJBAJxO\nCv1dt1Q76gbwmYa49LnWO+F+2cgRTVODpr5iYt5fOmBQQRRqzFkRMkFvOqn+KVzM\nQ6LKM6dn8BEl295vLhUCQQCVDWzoSk3GjL3sOjfAUTyAj8VAXM69llaptxWWySPM\nE9pA+8rYmHfohYFx7FD5/KWCO+sfmxTNB48X0uwyE8tO\n-----END RSA PRIVATE KEY-----\n" + sample: "-----BEGIN RSA PRIVATE KEY-----\nMII...8tO\n-----END RSA PRIVATE KEY-----\n" ''' try: import sshpubkeys - has_lib_sshpubkeys = True + HAS_LIB_SSHPUBKEYS = True except ImportError: - has_lib_sshpubkeys = False + HAS_LIB_SSHPUBKEYS = False + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.cloudstack import ( + AnsibleCloudStack, + CloudStackException, + cs_required_together, + cs_argument_spec +) -from ansible.module_utils.cloudstack import * class AnsibleCloudStackSshKey(AnsibleCloudStack): def __init__(self, module): super(AnsibleCloudStackSshKey, self).__init__(module) self.returns = { - 'privatekey': 'private_key', - 'fingerprint': 'fingerprint', + 'privatekey': 'private_key', + 'fingerprint': 'fingerprint', } self.ssh_key = None - def register_ssh_key(self, public_key): ssh_key = self.get_ssh_key() - args = {} - args['domainid'] = self.get_domain('id') - args['account'] = self.get_account('name') - args['projectid'] = self.get_project('id') - args['name'] = self.module.params.get('name') + args = self._get_common_args() + name = self.module.params.get('name') res = None if not ssh_key: self.result['changed'] = True args['publickey'] = public_key if not self.module.check_mode: + args['name'] = name res = self.cs.registerSSHKeyPair(**args) - else: fingerprint = self._get_ssh_fingerprint(public_key) if ssh_key['fingerprint'] != fingerprint: self.result['changed'] = True if not self.module.check_mode: + # delete the ssh key with matching name but wrong fingerprint + args['name'] = name self.cs.deleteSSHKeyPair(**args) - args['publickey'] = public_key - res = self.cs.registerSSHKeyPair(**args) + + elif ssh_key['name'].lower() != name.lower(): + self.result['changed'] = True + if not self.module.check_mode: + # delete the ssh key with matching fingerprint but wrong name + args['name'] = ssh_key['name'] + self.cs.deleteSSHKeyPair(**args) + # First match for key retrievment will be the fingerprint. + # We need to make another lookup if there is a key with identical name. + self.ssh_key = None + ssh_key = self.get_ssh_key() + if ssh_key['fingerprint'] != fingerprint: + args['name'] = name + self.cs.deleteSSHKeyPair(**args) + + if not self.module.check_mode and self.result['changed']: + args['publickey'] = public_key + args['name'] = name + res = self.cs.registerSSHKeyPair(**args) if res and 'keypair' in res: ssh_key = res['keypair'] return ssh_key - def create_ssh_key(self): ssh_key = self.get_ssh_key() if not ssh_key: self.result['changed'] = True - args = {} - args['domainid'] = self.get_domain('id') - args['account'] = self.get_account('name') - args['projectid'] = self.get_project('id') - args['name'] = self.module.params.get('name') + args = self._get_common_args() + args['name'] = self.module.params.get('name') if not self.module.check_mode: res = self.cs.createSSHKeyPair(**args) ssh_key = res['keypair'] return ssh_key - - def remove_ssh_key(self): + def remove_ssh_key(self, name=None): ssh_key = self.get_ssh_key() if ssh_key: self.result['changed'] = True - args = {} - args['domainid'] = self.get_domain('id') - args['account'] = self.get_account('name') - args['projectid'] = self.get_project('id') - args['name'] = self.module.params.get('name') + args = self._get_common_args() + args['name'] = name or self.module.params.get('name') if not self.module.check_mode: - res = self.cs.deleteSSHKeyPair(**args) + self.cs.deleteSSHKeyPair(**args) return ssh_key + def _get_common_args(self): + return { + 'domainid': self.get_domain('id'), + 'account': self.get_account('name'), + 'projectid': self.get_project('id') + } def get_ssh_key(self): if not self.ssh_key: - args = {} - args['domainid'] = self.get_domain('id') - args['account'] = self.get_account('name') - args['projectid'] = self.get_project('id') - args['name'] = self.module.params.get('name') - - ssh_keys = self.cs.listSSHKeyPairs(**args) - if ssh_keys and 'sshkeypair' in ssh_keys: - self.ssh_key = ssh_keys['sshkeypair'][0] + public_key = self.module.params.get('public_key') + if public_key: + # Query by fingerprint of the public key + args_fingerprint = self._get_common_args() + args_fingerprint['fingerprint'] = self._get_ssh_fingerprint(public_key) + ssh_keys = self.cs.listSSHKeyPairs(**args_fingerprint) + if ssh_keys and 'sshkeypair' in ssh_keys: + self.ssh_key = ssh_keys['sshkeypair'][0] + # When key has not been found by fingerprint, use the name + if not self.ssh_key: + args_name = self._get_common_args() + args_name['name'] = self.module.params.get('name') + ssh_keys = self.cs.listSSHKeyPairs(**args_name) + if ssh_keys and 'sshkeypair' in ssh_keys: + self.ssh_key = ssh_keys['sshkeypair'][0] return self.ssh_key - - def _get_ssh_fingerprint(self, public_key): key = sshpubkeys.SSHKey(public_key) return key.hash() @@ -213,12 +237,12 @@ class AnsibleCloudStackSshKey(AnsibleCloudStack): def main(): argument_spec = cs_argument_spec() argument_spec.update(dict( - name = dict(required=True), - public_key = dict(default=None), - domain = dict(default=None), - account = dict(default=None), - project = dict(default=None), - state = dict(choices=['present', 'absent'], default='present'), + name=dict(required=True), + public_key=dict(), + domain=dict(), + account=dict(), + project=dict(), + state=dict(choices=['present', 'absent'], default='present'), )) module = AnsibleModule( @@ -227,7 +251,7 @@ def main(): supports_check_mode=True ) - if not has_lib_sshpubkeys: + if not HAS_LIB_SSHPUBKEYS: module.fail_json(msg="python library sshpubkeys required: pip install sshpubkeys") try: @@ -249,7 +273,6 @@ def main(): module.exit_json(**result) -# import module snippets -from ansible.module_utils.basic import * + if __name__ == '__main__': main() diff --git a/test/sanity/pep8/legacy-files.txt b/test/sanity/pep8/legacy-files.txt index 931907cff28..25d19676394 100644 --- a/test/sanity/pep8/legacy-files.txt +++ b/test/sanity/pep8/legacy-files.txt @@ -78,7 +78,6 @@ lib/ansible/modules/cloud/cloudstack/cs_host.py lib/ansible/modules/cloud/cloudstack/cs_instance.py lib/ansible/modules/cloud/cloudstack/cs_iso.py lib/ansible/modules/cloud/cloudstack/cs_portforward.py -lib/ansible/modules/cloud/cloudstack/cs_sshkeypair.py lib/ansible/modules/cloud/digital_ocean/digital_ocean.py lib/ansible/modules/cloud/google/gc_storage.py lib/ansible/modules/cloud/google/gce_tag.py