1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00
community.general/plugins/modules/cloud/digital_ocean/digital_ocean_sshkey.py

263 lines
7.8 KiB
Python
Raw Normal View History

2020-03-09 10:11:07 +01:00
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: digital_ocean_sshkey
short_description: Manage DigitalOcean SSH keys
description:
- Create/delete DigitalOcean SSH keys.
author: "Patrick Marques (@pmarques)"
options:
state:
description:
- Indicate desired state of the target.
default: present
choices: ['present', 'absent']
fingerprint:
description:
- This is a unique identifier for the SSH key used to delete a key
aliases: ['id']
name:
description:
- The name for the SSH key
ssh_pub_key:
description:
- The Public SSH key to add.
oauth_token:
description:
- DigitalOcean OAuth token.
required: true
notes:
- Version 2 of DigitalOcean API is used.
requirements:
- "python >= 2.6"
'''
EXAMPLES = '''
- name: "Create ssh key"
digital_ocean_sshkey:
oauth_token: "{{ oauth_token }}"
name: "My SSH Public Key"
ssh_pub_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQDDHr/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example"
state: present
register: result
- name: "Delete ssh key"
digital_ocean_sshkey:
oauth_token: "{{ oauth_token }}"
state: "absent"
fingerprint: "3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa"
'''
RETURN = '''
# Digital Ocean API info https://developers.digitalocean.com/documentation/v2/#list-all-keys
data:
description: This is only present when C(state=present)
returned: when C(state=present)
type: dict
sample: {
"ssh_key": {
"id": 512189,
"fingerprint": "3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa",
"name": "My SSH Public Key",
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQDDHr/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example"
}
}
'''
import json
import hashlib
import base64
from ansible.module_utils.basic import env_fallback
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
class Response(object):
def __init__(self, resp, info):
self.body = None
if resp:
self.body = resp.read()
self.info = info
@property
def json(self):
if not self.body:
if "body" in self.info:
return json.loads(self.info["body"])
return None
try:
return json.loads(self.body)
except ValueError:
return None
@property
def status_code(self):
return self.info["status"]
class Rest(object):
def __init__(self, module, headers):
self.module = module
self.headers = headers
self.baseurl = 'https://api.digitalocean.com/v2'
def _url_builder(self, path):
if path[0] == '/':
path = path[1:]
return '%s/%s' % (self.baseurl, path)
def send(self, method, path, data=None, headers=None):
url = self._url_builder(path)
data = self.module.jsonify(data)
timeout = self.module.params['timeout']
resp, info = fetch_url(self.module, url, data=data, headers=self.headers, method=method, timeout=timeout)
# Exceptions in fetch_url may result in a status -1, the ensures a
if info['status'] == -1:
self.module.fail_json(msg=info['msg'])
return Response(resp, info)
def get(self, path, data=None, headers=None):
return self.send('GET', path, data, headers)
def put(self, path, data=None, headers=None):
return self.send('PUT', path, data, headers)
def post(self, path, data=None, headers=None):
return self.send('POST', path, data, headers)
def delete(self, path, data=None, headers=None):
return self.send('DELETE', path, data, headers)
def core(module):
api_token = module.params['oauth_token']
state = module.params['state']
fingerprint = module.params['fingerprint']
name = module.params['name']
ssh_pub_key = module.params['ssh_pub_key']
rest = Rest(module, {'Authorization': 'Bearer {0}'.format(api_token),
'Content-type': 'application/json'})
fingerprint = fingerprint or ssh_key_fingerprint(ssh_pub_key)
response = rest.get('account/keys/{0}'.format(fingerprint))
status_code = response.status_code
json = response.json
if status_code not in (200, 404):
module.fail_json(msg='Error getting ssh key [{0}: {1}]'.format(
status_code, response.json['message']), fingerprint=fingerprint)
if state in ('present'):
if status_code == 404:
# IF key not found create it!
if module.check_mode:
module.exit_json(changed=True)
payload = {
'name': name,
'public_key': ssh_pub_key
}
response = rest.post('account/keys', data=payload)
status_code = response.status_code
json = response.json
if status_code == 201:
module.exit_json(changed=True, data=json)
module.fail_json(msg='Error creating ssh key [{0}: {1}]'.format(
status_code, response.json['message']))
elif status_code == 200:
# If key found was found, check if name needs to be updated
if name is None or json['ssh_key']['name'] == name:
module.exit_json(changed=False, data=json)
if module.check_mode:
module.exit_json(changed=True)
payload = {
'name': name,
}
response = rest.put('account/keys/{0}'.format(fingerprint), data=payload)
status_code = response.status_code
json = response.json
if status_code == 200:
module.exit_json(changed=True, data=json)
module.fail_json(msg='Error updating ssh key name [{0}: {1}]'.format(
status_code, response.json['message']), fingerprint=fingerprint)
elif state in ('absent'):
if status_code == 404:
module.exit_json(changed=False)
if module.check_mode:
module.exit_json(changed=True)
response = rest.delete('account/keys/{0}'.format(fingerprint))
status_code = response.status_code
json = response.json
if status_code == 204:
module.exit_json(changed=True)
module.fail_json(msg='Error creating ssh key [{0}: {1}]'.format(
status_code, response.json['message']))
def ssh_key_fingerprint(ssh_pub_key):
key = ssh_pub_key.split(None, 2)[1]
fingerprint = hashlib.md5(base64.b64decode(key)).hexdigest()
return ':'.join(a + b for a, b in zip(fingerprint[::2], fingerprint[1::2]))
def main():
module = AnsibleModule(
argument_spec=dict(
state=dict(choices=['present', 'absent'], default='present'),
fingerprint=dict(aliases=['id'], required=False),
name=dict(required=False),
ssh_pub_key=dict(required=False),
oauth_token=dict(
no_log=True,
# Support environment variable for DigitalOcean OAuth Token
fallback=(env_fallback, ['DO_API_TOKEN', 'DO_API_KEY', 'DO_OAUTH_TOKEN']),
required=True,
),
validate_certs=dict(type='bool', default=True),
timeout=dict(type='int', default=30),
),
required_one_of=(
('fingerprint', 'ssh_pub_key'),
),
supports_check_mode=True,
)
core(module)
if __name__ == '__main__':
main()