Fix exception hierarchy for digital ocean and some cleanups of pep8 style
Fixes #4613
This commit is contained in:
parent
8e9befa5ba
commit
064c381608
5 changed files with 68 additions and 58 deletions
|
@ -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()
|
||||||
|
|
|
@ -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={}®ion={}'.format(volume_name, region)
|
url = 'volumes?name={}®ion={}'.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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue