diff --git a/lib/ansible/module_utils/digital_ocean.py b/lib/ansible/module_utils/digital_ocean.py new file mode 100644 index 0000000000..564a7df296 --- /dev/null +++ b/lib/ansible/module_utils/digital_ocean.py @@ -0,0 +1,102 @@ +# This code is part of Ansible, but is an independent component. +# This particular file snippet, and this file snippet only, is BSD licensed. +# Modules you write using this snippet, which is embedded dynamically by Ansible +# still belong to the author of the module, and may assign their own license +# to the complete work. +# +# Copyright (c), Ansible Project 2017 +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import json +import os +from ansible.module_utils.urls import fetch_url +from ansible.module_utils._text import to_text + + +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(to_text(self.info["body"])) + return None + try: + return json.loads(to_text(self.body)) + except ValueError: + return None + + @property + def status_code(self): + return self.info["status"] + + +class DigitalOceanHelper: + + def __init__(self, module): + self.module = module + self.baseurl = 'https://api.digitalocean.com/v2' + self.oauth_token = None + self.get_do_oauth_token() + self.headers = {'Authorization': 'Bearer {0}'.format(self.oauth_token), + 'Content-type': 'application/json'} + + def _url_builder(self, path): + if path[0] == '/': + path = path[1:] + return '%s/%s' % (self.baseurl, path) + + def send(self, method, path, data=None): + url = self._url_builder(path) + data = self.module.jsonify(data) + + resp, info = fetch_url(self.module, url, data=data, headers=self.headers, method=method) + + return Response(resp, info) + + def get(self, path, data=None): + return self.send('GET', path, data) + + def put(self, path, data=None): + return self.send('PUT', path, data) + + def post(self, path, data=None): + return self.send('POST', path, data) + + def delete(self, path, data=None): + return self.send('DELETE', path, data) + + def get_do_oauth_token(self): + try: + self.oauth_token = self.module.params['oauth_token'] or \ + self.module.params['api_token'] or \ + os.environ['DO_API_TOKEN'] or \ + os.environ['DO_API_KEY'] or \ + os.environ['OAUTH_TOKEN'] + except KeyError as e: + self.module.fail_json(msg='Unable to load %s' % e.message) diff --git a/lib/ansible/modules/cloud/digital_ocean/digital_ocean_block_storage.py b/lib/ansible/modules/cloud/digital_ocean/digital_ocean_block_storage.py index df1c1c5ef7..d65b755b12 100644 --- a/lib/ansible/modules/cloud/digital_ocean/digital_ocean_block_storage.py +++ b/lib/ansible/modules/cloud/digital_ocean/digital_ocean_block_storage.py @@ -107,82 +107,21 @@ id: sample: "69b25d9a-494c-12e6-a5af-001f53126b44" ''' -import json -import os import time import traceback from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.urls import fetch_url +from ansible.module_utils.digital_ocean import DigitalOceanHelper class DOBlockStorageException(Exception): pass -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 self.body: - return json.loads(self.body) - elif "body" in self.info: - return json.loads(self.info["body"]) - else: - 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) - - resp, info = fetch_url(self.module, url, data=data, headers=self.headers, method=method) - - 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) - - class DOBlockStorage(object): - def __init__(self, module): - api_token = module.params['api_token'] or \ - os.environ['DO_API_TOKEN'] or os.environ['DO_API_KEY'] self.module = module - self.rest = Rest(module, {'Authorization': 'Bearer {}'.format(api_token), - 'Content-type': 'application/json'}) + self.rest = DigitalOceanHelper(module) def get_key_or_fail(self, k): v = self.module.params[k] @@ -335,6 +274,5 @@ def main(): except KeyError as e: module.fail_json(msg='Unable to load %s' % e.message, exception=traceback.format_exc()) - if __name__ == '__main__': main() diff --git a/lib/ansible/modules/cloud/digital_ocean/digital_ocean_tag.py b/lib/ansible/modules/cloud/digital_ocean/digital_ocean_tag.py index 3a8eed3c5c..aed042a203 100644 --- a/lib/ansible/modules/cloud/digital_ocean/digital_ocean_tag.py +++ b/lib/ansible/modules/cloud/digital_ocean/digital_ocean_tag.py @@ -103,85 +103,19 @@ data: } ''' -import json -import os - +from traceback import format_exc from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.urls import fetch_url -from ansible.module_utils._text import to_text - - -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(to_text(self.info["body"], errors='surrogate_or_strict')) - return None - try: - return json.loads(to_text(self.body, errors='surrogate_or_strict')) - 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): - url = self._url_builder(path) - data = self.module.jsonify(data) - - resp, info = fetch_url(self.module, url, data=data, headers=self.headers, method=method) - - return Response(resp, info) - - def get(self, path, data=None): - return self.send('GET', path, data) - - def put(self, path, data=None): - return self.send('PUT', path, data) - - def post(self, path, data=None): - return self.send('POST', path, data) - - def delete(self, path, data=None): - return self.send('DELETE', path, data) +from ansible.module_utils.digital_ocean import DigitalOceanHelper +from ansible.module_utils._text import to_native def core(module): - try: - api_token = module.params['api_token'] or \ - os.environ['DO_API_TOKEN'] or os.environ['DO_API_KEY'] - except KeyError as e: - module.fail_json(msg='Unable to load %s' % e.message) - state = module.params['state'] name = module.params['name'] resource_id = module.params['resource_id'] resource_type = module.params['resource_type'] - rest = Rest(module, {'Authorization': 'Bearer {0}'.format(api_token), - 'Content-type': 'application/json'}) + rest = DigitalOceanHelper(module) # Check if api_token is valid or not response = rest.get('account') @@ -274,7 +208,7 @@ def main(): try: core(module) except Exception as e: - module.fail_json(msg=str(e)) + module.fail_json(msg=to_native(e), exception=format_exc()) if __name__ == '__main__':