Fix exception hierarchy for digital ocean and some cleanups of pep8 style

Fixes #4613
This commit is contained in:
Toshio Kuratomi 2016-10-04 12:44:10 -07:00 committed by Matt Clay
parent 8e9befa5ba
commit 064c381608
5 changed files with 68 additions and 58 deletions

View file

@ -109,7 +109,7 @@ options:
notes: notes:
- Two environment variables can be used, DO_API_KEY and DO_API_TOKEN. They both refer to the v2 token. - Two environment variables can be used, DO_API_KEY and DO_API_TOKEN. They both refer to the v2 token.
- As of Ansible 1.9.5 and 2.0, Version 2 of the DigitalOcean API is used, this removes C(client_id) and C(api_key) options in favor of C(api_token). - As of Ansible 1.9.5 and 2.0, Version 2 of the DigitalOcean API is used, this removes C(client_id) and C(api_key) options in favor of C(api_token).
- If you are running Ansible 1.9.4 or earlier you might not be able to use the included version of this module as the API version used has been retired. - If you are running Ansible 1.9.4 or earlier you might not be able to use the included version of this module as the API version used has been retired.
Upgrade Ansible or, if unable to, try downloading the latest version of this module from github and putting it into a 'library' directory. Upgrade Ansible or, if unable to, try downloading the latest version of this module from github and putting it into a 'library' directory.
requirements: requirements:
- "python >= 2.6" - "python >= 2.6"
@ -180,6 +180,8 @@ EXAMPLES = '''
import os import os
import time import time
import traceback
from distutils.version import LooseVersion from distutils.version import LooseVersion
HAS_DOPY = True HAS_DOPY = True
@ -191,15 +193,21 @@ try:
except ImportError: except ImportError:
HAS_DOPY = False HAS_DOPY = False
class TimeoutError(DoError): from ansible.module_utils.basic import AnsibleModule
def __init__(self, msg, id): from ansible.module_utils._text import to_native
class TimeoutError(Exception):
def __init__(self, msg, id_):
super(TimeoutError, self).__init__(msg) super(TimeoutError, self).__init__(msg)
self.id = id self.id = id_
class JsonfyMixIn(object): class JsonfyMixIn(object):
def to_json(self): def to_json(self):
return self.__dict__ return self.__dict__
class Droplet(JsonfyMixIn): class Droplet(JsonfyMixIn):
manager = None manager = None
@ -283,6 +291,7 @@ class Droplet(JsonfyMixIn):
json = cls.manager.all_active_droplets() json = cls.manager.all_active_droplets()
return map(cls, json) return map(cls, json)
class SSH(JsonfyMixIn): class SSH(JsonfyMixIn):
manager = None manager = None
@ -318,6 +327,7 @@ class SSH(JsonfyMixIn):
json = cls.manager.new_ssh_key(name, key_pub) json = cls.manager.new_ssh_key(name, key_pub)
return cls(json) return cls(json)
def core(module): def core(module):
def getkeyordie(k): def getkeyordie(k):
v = module.params[k] v = module.params[k]
@ -385,7 +395,7 @@ def core(module):
if not droplet: if not droplet:
module.exit_json(changed=False, msg='The droplet is not found.') module.exit_json(changed=False, msg='The droplet is not found.')
event_json = droplet.destroy() droplet.destroy()
module.exit_json(changed=True) module.exit_json(changed=True)
elif command == 'ssh': elif command == 'ssh':
@ -446,12 +456,9 @@ def main():
try: try:
core(module) core(module)
except TimeoutError as e: except TimeoutError as e:
module.fail_json(msg=str(e), id=e.id) module.fail_json(msg=to_native(e), id=e.id)
except (DoError, Exception) as e: except (DoError, Exception) as e:
module.fail_json(msg=str(e)) module.fail_json(msg=to_native(e), exception=traceback.format_exc())
# import module snippets
from ansible.module_utils.basic import *
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -16,15 +16,12 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
import json
import time
DOCUMENTATION = ''' DOCUMENTATION = '''
--- ---
module: digital_ocean_block_storage module: digital_ocean_block_storage
short_description: Create/destroy or attach/detach Block Storage volumes in DigitalOcean short_description: Create/destroy or attach/detach Block Storage volumes in DigitalOcean
description: description:
- Create/destroy Block Storage volume in DigitalOcean, or attach/detach Block Storage volume to a droplet. - Create/destroy Block Storage volume in DigitalOcean, or attach/detach Block Storage volume to a droplet.
version_added: "2.2" version_added: "2.2"
options: options:
command: command:
@ -113,9 +110,19 @@ id:
sample: "69b25d9a-494c-12e6-a5af-001f53126b44" sample: "69b25d9a-494c-12e6-a5af-001f53126b44"
''' '''
import json
import os
import time
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.urls import fetch_url
class DOBlockStorageException(Exception): class DOBlockStorageException(Exception):
pass pass
class Response(object): class Response(object):
def __init__(self, resp, info): def __init__(self, resp, info):
@ -137,6 +144,7 @@ class Response(object):
def status_code(self): def status_code(self):
return self.info["status"] return self.info["status"]
class Rest(object): class Rest(object):
def __init__(self, module, headers): def __init__(self, module, headers):
@ -169,6 +177,7 @@ class Rest(object):
def delete(self, path, data=None, headers=None): def delete(self, path, data=None, headers=None):
return self.send('DELETE', path, data, headers) return self.send('DELETE', path, data, headers)
class DOBlockStorage(object): class DOBlockStorage(object):
def __init__(self, module): def __init__(self, module):
@ -206,9 +215,9 @@ class DOBlockStorage(object):
json = response.json json = response.json
if status == 200: if status == 200:
volumes = json['volumes'] volumes = json['volumes']
if len(volumes)>0: if len(volumes) > 0:
droplet_ids = volumes[0]['droplet_ids'] droplet_ids = volumes[0]['droplet_ids']
if len(droplet_ids)>0: if len(droplet_ids) > 0:
return droplet_ids[0] return droplet_ids[0]
return None return None
else: else:
@ -216,10 +225,10 @@ class DOBlockStorage(object):
def attach_detach_block_storage(self, method, volume_name, region, droplet_id): def attach_detach_block_storage(self, method, volume_name, region, droplet_id):
data = { data = {
'type' : method, 'type': method,
'volume_name' : volume_name, 'volume_name': volume_name,
'region' : region, 'region': region,
'droplet_id' : droplet_id 'droplet_id': droplet_id
} }
response = self.rest.post('volumes/actions', data=data) response = self.rest.post('volumes/actions', data=data)
status = response.status_code status = response.status_code
@ -239,10 +248,10 @@ class DOBlockStorage(object):
region = self.get_key_or_fail('region') region = self.get_key_or_fail('region')
description = self.module.params['description'] description = self.module.params['description']
data = { data = {
'size_gigabytes' : block_size, 'size_gigabytes': block_size,
'name' : volume_name, 'name': volume_name,
'description' : description, 'description': description,
'region' : region 'region': region
} }
response = self.rest.post("volumes", data=data) response = self.rest.post("volumes", data=data)
status = response.status_code status = response.status_code
@ -259,7 +268,7 @@ class DOBlockStorage(object):
region = self.get_key_or_fail('region') region = self.get_key_or_fail('region')
url = 'volumes?name={}&region={}'.format(volume_name, region) url = 'volumes?name={}&region={}'.format(volume_name, region)
attached_droplet_id = self.get_attached_droplet_ID(volume_name, region) attached_droplet_id = self.get_attached_droplet_ID(volume_name, region)
if attached_droplet_id != None: if attached_droplet_id is not None:
self.attach_detach_block_storage('detach', volume_name, region, attached_droplet_id) self.attach_detach_block_storage('detach', volume_name, region, attached_droplet_id)
response = self.rest.delete(url) response = self.rest.delete(url)
status = response.status_code status = response.status_code
@ -276,8 +285,8 @@ class DOBlockStorage(object):
region = self.get_key_or_fail('region') region = self.get_key_or_fail('region')
droplet_id = self.get_key_or_fail('droplet_id') droplet_id = self.get_key_or_fail('droplet_id')
attached_droplet_id = self.get_attached_droplet_ID(volume_name, region) attached_droplet_id = self.get_attached_droplet_ID(volume_name, region)
if attached_droplet_id != None: if attached_droplet_id is not None:
if attached_droplet_id==droplet_id: if attached_droplet_id == droplet_id:
self.module.exit_json(changed=False) self.module.exit_json(changed=False)
else: else:
self.attach_detach_block_storage('detach', volume_name, region, attached_droplet_id) self.attach_detach_block_storage('detach', volume_name, region, attached_droplet_id)
@ -291,6 +300,7 @@ class DOBlockStorage(object):
changed_status = self.attach_detach_block_storage('detach', volume_name, region, droplet_id) changed_status = self.attach_detach_block_storage('detach', volume_name, region, droplet_id)
self.module.exit_json(changed=changed_status) self.module.exit_json(changed=changed_status)
def handle_request(module): def handle_request(module):
block_storage = DOBlockStorage(module) block_storage = DOBlockStorage(module)
command = module.params['command'] command = module.params['command']
@ -301,11 +311,12 @@ def handle_request(module):
elif state == 'absent': elif state == 'absent':
block_storage.delete_block_storage() block_storage.delete_block_storage()
elif command == 'attach': elif command == 'attach':
if state =='present': if state == 'present':
block_storage.attach_block_storage() block_storage.attach_block_storage()
elif state == 'absent': elif state == 'absent':
block_storage.detach_block_storage() block_storage.detach_block_storage()
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec=dict( argument_spec=dict(
@ -329,7 +340,5 @@ def main():
e = get_exception() e = get_exception()
module.fail_json(msg='Unable to load %s' % e.message) module.fail_json(msg='Unable to load %s' % e.message)
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -46,7 +46,7 @@ options:
notes: notes:
- Two environment variables can be used, DO_API_KEY and DO_API_TOKEN. They both refer to the v2 token. - Two environment variables can be used, DO_API_KEY and DO_API_TOKEN. They both refer to the v2 token.
- As of Ansible 1.9.5 and 2.0, Version 2 of the DigitalOcean API is used, this removes C(client_id) and C(api_key) options in favor of C(api_token). - As of Ansible 1.9.5 and 2.0, Version 2 of the DigitalOcean API is used, this removes C(client_id) and C(api_key) options in favor of C(api_token).
- If you are running Ansible 1.9.4 or earlier you might not be able to use the included version of this module as the API version used has been retired. - If you are running Ansible 1.9.4 or earlier you might not be able to use the included version of this module as the API version used has been retired.
requirements: requirements:
- "python >= 2.6" - "python >= 2.6"
@ -82,7 +82,7 @@ EXAMPLES = '''
''' '''
import os import os
import time import traceback
try: try:
from dopy.manager import DoError, DoManager from dopy.manager import DoError, DoManager
@ -90,15 +90,14 @@ try:
except ImportError as e: except ImportError as e:
HAS_DOPY = False HAS_DOPY = False
class TimeoutError(DoError): from ansible.module_utils.basic import AnsibleModule
def __init__(self, msg, id):
super(TimeoutError, self).__init__(msg)
self.id = id
class JsonfyMixIn(object): class JsonfyMixIn(object):
def to_json(self): def to_json(self):
return self.__dict__ return self.__dict__
class DomainRecord(JsonfyMixIn): class DomainRecord(JsonfyMixIn):
manager = None manager = None
@ -106,7 +105,7 @@ class DomainRecord(JsonfyMixIn):
self.__dict__.update(json) self.__dict__.update(json)
update_attr = __init__ update_attr = __init__
def update(self, data = None, record_type = None): def update(self, data=None, record_type=None):
json = self.manager.edit_domain_record(self.domain_id, json = self.manager.edit_domain_record(self.domain_id,
self.id, self.id,
record_type if record_type is not None else self.record_type, record_type if record_type is not None else self.record_type,
@ -118,6 +117,7 @@ class DomainRecord(JsonfyMixIn):
json = self.manager.destroy_domain_record(self.domain_id, self.id) json = self.manager.destroy_domain_record(self.domain_id, self.id)
return json return json
class Domain(JsonfyMixIn): class Domain(JsonfyMixIn):
manager = None manager = None
@ -165,6 +165,7 @@ class Domain(JsonfyMixIn):
return False return False
def core(module): def core(module):
def getkeyordie(k): def getkeyordie(k):
v = module.params[k] v = module.params[k]
@ -236,12 +237,8 @@ def main():
try: try:
core(module) core(module)
except TimeoutError as e:
module.fail_json(msg=str(e), id=e.id)
except (DoError, Exception) as e: except (DoError, Exception) as e:
module.fail_json(msg=str(e)) module.fail_json(msg=str(e), exception=traceback.format_exc())
# import module snippets
from ansible.module_utils.basic import *
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -69,7 +69,7 @@ EXAMPLES = '''
''' '''
import os import os
import time import traceback
try: try:
from dopy.manager import DoError, DoManager from dopy.manager import DoError, DoManager
@ -77,15 +77,14 @@ try:
except ImportError: except ImportError:
HAS_DOPY = False HAS_DOPY = False
class TimeoutError(DoError): from ansible.module_utils.basic import AnsibleModule
def __init__(self, msg, id):
super(TimeoutError, self).__init__(msg)
self.id = id
class JsonfyMixIn(object): class JsonfyMixIn(object):
def to_json(self): def to_json(self):
return self.__dict__ return self.__dict__
class SSH(JsonfyMixIn): class SSH(JsonfyMixIn):
manager = None manager = None
@ -121,6 +120,7 @@ class SSH(JsonfyMixIn):
json = cls.manager.new_ssh_key(name, key_pub) json = cls.manager.new_ssh_key(name, key_pub)
return cls(json) return cls(json)
def core(module): def core(module):
def getkeyordie(k): def getkeyordie(k):
v = module.params[k] v = module.params[k]
@ -135,7 +135,6 @@ def core(module):
except KeyError as e: except KeyError as e:
module.fail_json(msg='Unable to load %s' % e.message) module.fail_json(msg='Unable to load %s' % e.message)
changed = True
state = module.params['state'] state = module.params['state']
SSH.setup(client_id, api_key) SSH.setup(client_id, api_key)
@ -154,6 +153,7 @@ def core(module):
key.destroy() key.destroy()
module.exit_json(changed=True) module.exit_json(changed=True)
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec = dict( argument_spec = dict(
@ -173,12 +173,8 @@ def main():
try: try:
core(module) core(module)
except TimeoutError as e:
module.fail_json(msg=str(e), id=e.id)
except (DoError, Exception) as e: except (DoError, Exception) as e:
module.fail_json(msg=str(e)) module.fail_json(msg=str(e), exception=traceback.format_exc())
# import module snippets
from ansible.module_utils.basic import *
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -105,6 +105,10 @@ data:
''' '''
import json import json
import os
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import fetch_url
class Response(object): class Response(object):
@ -123,7 +127,7 @@ class Response(object):
return None return None
try: try:
return json.loads(self.body) return json.loads(self.body)
except ValueError as e: except ValueError:
return None return None
@property @property
@ -250,8 +254,5 @@ def main():
except Exception as e: except Exception as e:
module.fail_json(msg=str(e)) module.fail_json(msg=str(e))
# import module snippets
from ansible.module_utils.basic import * # noqa
from ansible.module_utils.urls import *
if __name__ == '__main__': if __name__ == '__main__':
main() main()