From 07d80b5f1ef0ff7e4b9bd3fdece460473eb1f04f Mon Sep 17 00:00:00 2001 From: Matt Martz Date: Tue, 10 Jun 2014 10:08:12 -0500 Subject: [PATCH] Move additional rackspace common code into module_utils/rax.py --- cloud/rax | 83 ++++----------------------------------- cloud/rax_cbs | 20 +--------- cloud/rax_cbs_attachments | 48 ++-------------------- cloud/rax_clb | 46 +++------------------- cloud/rax_clb_nodes | 18 +-------- cloud/rax_dns | 15 +------ cloud/rax_dns_record | 21 ++-------- cloud/rax_facts | 20 +--------- cloud/rax_files | 5 --- cloud/rax_files_objects | 2 - cloud/rax_identity | 5 --- cloud/rax_keypair | 15 +------ cloud/rax_scaling_group | 67 +++---------------------------- cloud/rax_scaling_policy | 19 +-------- 14 files changed, 31 insertions(+), 353 deletions(-) diff --git a/cloud/rax b/cloud/rax index f7ea8e9c276..35156a01db2 100644 --- a/cloud/rax +++ b/cloud/rax @@ -194,44 +194,12 @@ EXAMPLES = ''' register: rax ''' -import os -import re -import time - -from uuid import UUID -from types import NoneType - try: import pyrax HAS_PYRAX = True except ImportError: HAS_PYRAX = False -ACTIVE_STATUSES = ('ACTIVE', 'BUILD', 'HARD_REBOOT', 'MIGRATING', 'PASSWORD', - 'REBOOT', 'REBUILD', 'RESCUE', 'RESIZE', 'REVERT_RESIZE') -FINAL_STATUSES = ('ACTIVE', 'ERROR') -NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) -PUBLIC_NET_ID = "00000000-0000-0000-0000-000000000000" -SERVICE_NET_ID = "11111111-1111-1111-1111-111111111111" - - -def rax_slugify(value): - return 'rax_%s' % (re.sub('[^\w-]', '_', value).lower().lstrip('_')) - - -def server_to_dict(obj): - instance = {} - for key in dir(obj): - value = getattr(obj, key) - if (isinstance(value, NON_CALLABLES) and not key.startswith('_')): - key = rax_slugify(key) - instance[key] = value - - for attr in ['id', 'accessIPv4', 'name', 'status']: - instance[attr] = instance.get(rax_slugify(attr)) - - return instance - def create(module, names=[], flavor=None, image=None, meta={}, key_name=None, files={}, wait=True, wait_timeout=300, disk_config=None, @@ -299,7 +267,7 @@ def create(module, names=[], flavor=None, image=None, meta={}, key_name=None, server.get() except: server.status == 'ERROR' - instance = server_to_dict(server) + instance = rax_to_dict(server, 'server') if server.status == 'ACTIVE' or not wait: success.append(instance) elif server.status == 'ERROR': @@ -307,7 +275,7 @@ def create(module, names=[], flavor=None, image=None, meta={}, key_name=None, elif wait: timeout.append(instance) - untouched = [server_to_dict(s) for s in existing] + untouched = [rax_to_dict(s, 'server') for s in existing] instances = success + untouched results = { @@ -354,7 +322,7 @@ def delete(module, instance_ids=[], wait=True, wait_timeout=300, kept=[]): else: changed = True - instance = server_to_dict(server) + instance = rax_to_dict(server, 'server') instances[instance['id']] = instance # If requested, wait for server deletion @@ -384,7 +352,7 @@ def delete(module, instance_ids=[], wait=True, wait_timeout=300, kept=[]): success = filter(lambda s: s['status'] in ('', 'DELETED'), instances.values()) - instances = [server_to_dict(s) for s in kept] + instances = [rax_to_dict(s, 'server') for s in kept] results = { 'changed': changed, @@ -451,48 +419,13 @@ def cloudservers(module, state=None, name=None, flavor=None, image=None, state = 'present' was_absent = True - # Check if the provided image is a UUID and if not, search for an - # appropriate image using human_id and name if image: - try: - UUID(image) - except ValueError: - try: - image = cs.images.find(human_id=image) - except(cs.exceptions.NotFound, - cs.exceptions.NoUniqueMatch): - try: - image = cs.images.find(name=image) - except (cs.exceptions.NotFound, - cs.exceptions.NoUniqueMatch): - module.fail_json(msg='No matching image found (%s)' % - image) - - image = pyrax.utils.get_id(image) + image = rax_find_image(module, pyrax, image) - # Check if the provided network is a UUID and if not, search for an - # appropriate network using label nics = [] if networks: for network in networks: - try: - UUID(network) - except ValueError: - if network.lower() == 'public': - nics.extend(cnw.get_server_networks(PUBLIC_NET_ID)) - elif network.lower() == 'private': - nics.extend(cnw.get_server_networks(SERVICE_NET_ID)) - else: - try: - network_obj = cnw.find_network_by_label(network) - except (pyrax.exceptions.NetworkNotFound, - pyrax.exceptions.NetworkLabelNotUnique): - module.fail_json(msg='No matching network found (%s)' % - network) - else: - nics.extend(cnw.get_server_networks(network_obj)) - else: - nics.extend(cnw.get_server_networks(network)) + nics.extend(rax_find_network(module, pyrax, network)) # act on the state if state == 'present': @@ -568,7 +501,7 @@ def cloudservers(module, state=None, name=None, flavor=None, image=None, instances = [] instance_ids = [] for server in servers: - instances.append(server_to_dict(server)) + instances.append(rax_to_dict(server, 'server')) instance_ids.append(server.id) module.exit_json(changed=False, action=None, instances=instances, @@ -623,7 +556,7 @@ def cloudservers(module, state=None, name=None, flavor=None, image=None, if len(servers) >= count: instances = [] for server in servers: - instances.append(server_to_dict(server)) + instances.append(rax_to_dict(server, 'server')) instance_ids = [i['id'] for i in instances] module.exit_json(changed=False, action=None, diff --git a/cloud/rax_cbs b/cloud/rax_cbs index ade2b83eacf..a1b6ce46a6e 100644 --- a/cloud/rax_cbs +++ b/cloud/rax_cbs @@ -99,21 +99,12 @@ EXAMPLES = ''' register: my_volume ''' -import sys - -from uuid import UUID -from types import NoneType - try: import pyrax HAS_PYRAX = True except ImportError: HAS_PYRAX = False -NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) -VOLUME_STATUS = ('available', 'attaching', 'creating', 'deleting', 'in-use', - 'error', 'error_deleting') - def cloud_block_storage(module, state, name, description, meta, size, snapshot_id, volume_type, wait, wait_timeout): @@ -135,16 +126,7 @@ def cloud_block_storage(module, state, name, description, meta, size, 'typically indicates an invalid region or an ' 'incorrectly capitalized region name.') - try: - UUID(name) - volume = cbs.get(name) - except ValueError: - try: - volume = cbs.find(name=name) - except pyrax.exc.NotFound: - pass - except Exception, e: - module.fail_json(msg='%s' % e) + volume = rax_find_volume(module, pyrax, name) if state == 'present': if not volume: diff --git a/cloud/rax_cbs_attachments b/cloud/rax_cbs_attachments index bc7dba9eec2..365f93cd6e2 100644 --- a/cloud/rax_cbs_attachments +++ b/cloud/rax_cbs_attachments @@ -81,19 +81,12 @@ EXAMPLES = ''' register: my_volume ''' -import sys - -from uuid import UUID -from types import NoneType - try: import pyrax HAS_PYRAX = True except ImportError: HAS_PYRAX = False -NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) - def cloud_block_storage_attachments(module, state, volume, server, device, wait, wait_timeout): @@ -113,34 +106,13 @@ def cloud_block_storage_attachments(module, state, volume, server, device, changed = False instance = {} - try: - UUID(volume) - volume = cbs.get(volume) - except ValueError: - try: - volume = cbs.find(name=volume) - except Exception, e: - module.fail_json(msg='%s' % e) + volume = rax_find_volume(module, pyrax, volume) if not volume: module.fail_json(msg='No matching storage volumes were found') if state == 'present': - try: - UUID(server) - server = cs.servers.get(server) - except ValueError: - servers = cs.servers.list(search_opts=dict(name='^%s$' % server)) - if not servers: - module.fail_json(msg='No Server was matched by name, ' - 'try using the Server ID instead') - if len(servers) > 1: - module.fail_json(msg='Multiple servers matched by name, ' - 'try using the Server ID instead') - - # We made it this far, grab the first and hopefully only server - # in the list - server = servers[0] + server = rax_find_server(module, pyrax, server) if (volume.attachments and volume.attachments[0]['server_id'] == server.id): @@ -176,21 +148,7 @@ def cloud_block_storage_attachments(module, state, volume, server, device, module.exit_json(**result) elif state == 'absent': - try: - UUID(server) - server = cs.servers.get(server) - except ValueError: - servers = cs.servers.list(search_opts=dict(name='^%s$' % server)) - if not servers: - module.fail_json(msg='No Server was matched by name, ' - 'try using the Server ID instead') - if len(servers) > 1: - module.fail_json(msg='Multiple servers matched by name, ' - 'try using the Server ID instead') - - # We made it this far, grab the first and hopefully only server - # in the list - server = servers[0] + server = rax_find_server(module, pyrax, server) if (volume.attachments and volume.attachments[0]['server_id'] == server.id): diff --git a/cloud/rax_clb b/cloud/rax_clb index 85700895c7c..7a2699709da 100644 --- a/cloud/rax_clb +++ b/cloud/rax_clb @@ -130,7 +130,6 @@ EXAMPLES = ''' register: my_lb ''' -from types import NoneType try: import pyrax @@ -138,42 +137,6 @@ try: except ImportError: HAS_PYRAX = False -NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) -ALGORITHMS = ['RANDOM', 'LEAST_CONNECTIONS', 'ROUND_ROBIN', - 'WEIGHTED_LEAST_CONNECTIONS', 'WEIGHTED_ROUND_ROBIN'] -PROTOCOLS = ['DNS_TCP', 'DNS_UDP', 'FTP', 'HTTP', 'HTTPS', 'IMAPS', 'IMAPv4', - 'LDAP', 'LDAPS', 'MYSQL', 'POP3', 'POP3S', 'SMTP', 'TCP', - 'TCP_CLIENT_FIRST', 'UDP', 'UDP_STREAM', 'SFTP'] - - -def node_to_dict(obj): - node = obj.to_dict() - node['id'] = obj.id - return node - - -def to_dict(obj): - instance = {} - for key in dir(obj): - value = getattr(obj, key) - if key == 'virtual_ips': - instance[key] = [] - for vip in value: - vip_dict = {} - for vip_key, vip_value in vars(vip).iteritems(): - if isinstance(vip_value, NON_CALLABLES): - vip_dict[vip_key] = vip_value - instance[key].append(vip_dict) - elif key == 'nodes': - instance[key] = [] - for node in value: - instance[key].append(node_to_dict(node)) - elif (isinstance(value, NON_CALLABLES) and - not key.startswith('_')): - instance[key] = value - - return instance - def cloud_load_balancer(module, state, name, meta, algorithm, port, protocol, vip_type, timeout, wait, wait_timeout, vip_id): @@ -252,7 +215,7 @@ def cloud_load_balancer(module, state, name, meta, algorithm, port, protocol, pyrax.utils.wait_for_build(balancer, interval=5, attempts=attempts) balancer.get() - instance = to_dict(balancer) + instance = rax_to_dict(balancer, 'clb') result = dict(changed=changed, balancer=instance) @@ -275,7 +238,7 @@ def cloud_load_balancer(module, state, name, meta, algorithm, port, protocol, except Exception, e: module.fail_json(msg='%s' % e.message) - instance = to_dict(balancer) + instance = rax_to_dict(balancer, 'clb') if wait: attempts = wait_timeout / 5 @@ -291,11 +254,12 @@ def main(): argument_spec = rax_argument_spec() argument_spec.update( dict( - algorithm=dict(choices=ALGORITHMS, default='LEAST_CONNECTIONS'), + algorithm=dict(choices=CLB_ALGORITHMS, + default='LEAST_CONNECTIONS'), meta=dict(type='dict', default={}), name=dict(), port=dict(type='int', default=80), - protocol=dict(choices=PROTOCOLS, default='HTTP'), + protocol=dict(choices=CLB_PROTOCOLS, default='HTTP'), state=dict(default='present', choices=['present', 'absent']), timeout=dict(type='int', default=30), type=dict(choices=['PUBLIC', 'SERVICENET'], default='PUBLIC'), diff --git a/cloud/rax_clb_nodes b/cloud/rax_clb_nodes index dc0950dca58..24325b44597 100644 --- a/cloud/rax_clb_nodes +++ b/cloud/rax_clb_nodes @@ -120,8 +120,6 @@ EXAMPLES = ''' credentials: /path/to/credentials ''' -import os - try: import pyrax HAS_PYRAX = True @@ -167,20 +165,6 @@ def _get_primary_nodes(lb): return nodes -def _node_to_dict(node): - """Return a dictionary containing node details""" - if not node: - return {} - return { - 'address': node.address, - 'condition': node.condition, - 'id': node.id, - 'port': node.port, - 'type': node.type, - 'weight': node.weight, - } - - def main(): argument_spec = rax_argument_spec() argument_spec.update( @@ -241,7 +225,7 @@ def main(): node = _get_node(lb, node_id, address, port) - result = _node_to_dict(node) + result = rax_clb_node_to_dict(node) if state == 'absent': if not node: # Removing a non-existent node diff --git a/cloud/rax_dns b/cloud/rax_dns index 57bc75acf5a..e726851d609 100644 --- a/cloud/rax_dns +++ b/cloud/rax_dns @@ -66,25 +66,12 @@ EXAMPLES = ''' register: rax_dns ''' -from types import NoneType - try: import pyrax HAS_PYRAX = True except ImportError: HAS_PYRAX = False -NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) - - -def to_dict(obj): - instance = {} - for key in dir(obj): - value = getattr(obj, key) - if (isinstance(value, NON_CALLABLES) and not key.startswith('_')): - instance[key] = value - return instance - def rax_dns(module, comment, email, name, state, ttl): changed = False @@ -144,7 +131,7 @@ def rax_dns(module, comment, email, name, state, ttl): except Exception, e: module.fail_json(msg='%s' % e.message) - module.exit_json(changed=changed, domain=to_dict(domain)) + module.exit_json(changed=changed, domain=rax_to_dict(domain)) def main(): diff --git a/cloud/rax_dns_record b/cloud/rax_dns_record index dc85f2ef45d..05c7a8fc054 100644 --- a/cloud/rax_dns_record +++ b/cloud/rax_dns_record @@ -113,30 +113,15 @@ EXAMPLES = ''' register: ptr_record ''' -from uuid import UUID - try: import pyrax HAS_PYRAX = True except ImportError: HAS_PYRAX = False -NON_CALLABLES = (basestring, bool, dict, int, list, type(None)) - - -def to_dict(obj): - instance = {} - for key in dir(obj): - value = getattr(obj, key) - if (isinstance(value, NON_CALLABLES) and not key.startswith('_')): - instance[key] = value - return instance - - -def rax_dns_record_ptr(module, data=None, comment=None, loadbalancer=None, - name=None, server=None, state='present', ttl=7200): - """Function for manipulating DNS PTR records""" +def rax_dns_record(module, data=None, comment=None, loadbalancer=None, + name=None, server=None, state='present', ttl=7200): changed = False results = [] @@ -301,7 +286,7 @@ def rax_dns_record(module, comment=None, data=None, domain=None, name=None, except Exception, e: module.fail_json(msg='%s' % e.message) - module.exit_json(changed=changed, record=to_dict(record)) + module.exit_json(changed=changed, record=rax_to_dict(record)) def main(): diff --git a/cloud/rax_facts b/cloud/rax_facts index 64711f41519..68ef446f760 100644 --- a/cloud/rax_facts +++ b/cloud/rax_facts @@ -55,30 +55,12 @@ EXAMPLES = ''' ansible_ssh_host: "{{ rax_accessipv4 }}" ''' -from types import NoneType - try: import pyrax HAS_PYRAX = True except ImportError: HAS_PYRAX = False -NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) - - -def rax_slugify(value): - return 'rax_%s' % (re.sub('[^\w-]', '_', value).lower().lstrip('_')) - - -def pyrax_object_to_dict(obj): - instance = {} - for key in dir(obj): - value = getattr(obj, key) - if (isinstance(value, NON_CALLABLES) and not key.startswith('_')): - key = rax_slugify(key) - instance[key] = value - return instance - def rax_facts(module, address, name, server_id): changed = False @@ -120,7 +102,7 @@ def rax_facts(module, address, name, server_id): module.fail_json(msg='Multiple servers found matching provided ' 'search parameters') elif len(servers) == 1: - ansible_facts = pyrax_object_to_dict(servers[0]) + ansible_facts = rax_to_dict(servers[0], 'server') module.exit_json(changed=changed, ansible_facts=ansible_facts) diff --git a/cloud/rax_files b/cloud/rax_files index 68e28a07f74..3c54b0a9e2f 100644 --- a/cloud/rax_files +++ b/cloud/rax_files @@ -139,8 +139,6 @@ EXAMPLES = ''' file_for: "" ''' -from ansible import __version__ - try: import pyrax HAS_PYRAX = True @@ -149,7 +147,6 @@ except ImportError, e: EXIT_DICT = dict(success=True) META_PREFIX = 'x-container-meta-' -USER_AGENT = "Ansible/%s via pyrax" % __version__ def _get_container(module, cf, container): @@ -321,8 +318,6 @@ def cloudfiles(module, container_, state, meta_, clear_meta, typ, ttl, public, 'typically indicates an invalid region or an ' 'incorrectly capitalized region name.') - cf.user_agent = USER_AGENT - if typ == "container": container(cf, module, container_, state, meta_, clear_meta, ttl, public, private, web_index, web_error) diff --git a/cloud/rax_files_objects b/cloud/rax_files_objects index d7f11900ab9..de8400c5c52 100644 --- a/cloud/rax_files_objects +++ b/cloud/rax_files_objects @@ -183,8 +183,6 @@ EXAMPLES = ''' rax_files_objects: container=testcont type=meta ''' -import os - try: import pyrax HAS_PYRAX = True diff --git a/cloud/rax_identity b/cloud/rax_identity index 591cd018e70..9de4db96611 100644 --- a/cloud/rax_identity +++ b/cloud/rax_identity @@ -47,8 +47,6 @@ EXAMPLES = ''' register: rackspace_identity ''' -from types import NoneType - try: import pyrax HAS_PYRAX = True @@ -56,9 +54,6 @@ except ImportError: HAS_PYRAX = False -NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) - - def cloud_identity(module, state, identity): for arg in (state, identity): if not arg: diff --git a/cloud/rax_keypair b/cloud/rax_keypair index 2e347268a6b..591ad8c3597 100644 --- a/cloud/rax_keypair +++ b/cloud/rax_keypair @@ -84,25 +84,12 @@ EXAMPLES = ''' register: keypair ''' -from types import NoneType - try: import pyrax HAS_PYRAX = True except ImportError: HAS_PYRAX = False -NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) - - -def to_dict(obj): - instance = {} - for key in dir(obj): - value = getattr(obj, key) - if (isinstance(value, NON_CALLABLES) and not key.startswith('_')): - instance[key] = value - return instance - def rax_keypair(module, name, public_key, state): changed = False @@ -149,7 +136,7 @@ def rax_keypair(module, name, public_key, state): except Exception, e: module.fail_json(msg='%s' % e.message) - module.exit_json(changed=changed, keypair=to_dict(keypair)) + module.exit_json(changed=changed, keypair=rax_to_dict(keypair)) def main(): diff --git a/cloud/rax_scaling_group b/cloud/rax_scaling_group index 2c635592b77..d884d3c1303 100644 --- a/cloud/rax_scaling_group +++ b/cloud/rax_scaling_group @@ -118,34 +118,12 @@ EXAMPLES = ''' register: asg ''' -import os - -from uuid import UUID - try: import pyrax HAS_PYRAX = True except ImportError: HAS_PYRAX = False -NON_CALLABLES = (basestring, bool, dict, int, list, type(None)) -PUBLIC_NET_ID = "00000000-0000-0000-0000-000000000000" -SERVICE_NET_ID = "11111111-1111-1111-1111-111111111111" - - -def asg_to_dict(obj): - instance = {} - for key in dir(obj): - value = getattr(obj, key) - if key == 'policies' and isinstance(value, list): - policies = [] - for policy in value: - policies.append(asg_to_dict(policy)) - instance[key] = policies - elif (isinstance(value, NON_CALLABLES) and not key.startswith('_')): - instance[key] = value - return instance - def rax_asg(module, cooldown=300, disk_config=None, files={}, flavor=None, image=None, key_name=None, loadbalancers=[], meta={}, @@ -172,48 +150,13 @@ def rax_asg(module, cooldown=300, disk_config=None, files={}, flavor=None, elif not isinstance(v, basestring): meta[k] = '%s' % v - # Check if the provided image is a UUID and if not, search for an - # appropriate image using human_id and name if image: - try: - UUID(image) - except ValueError: - try: - image = cs.images.find(human_id=image) - except(cs.exceptions.NotFound, - cs.exceptions.NoUniqueMatch): - try: - image = cs.images.find(name=image) - except (cs.exceptions.NotFound, - cs.exceptions.NoUniqueMatch): - module.fail_json(msg='No matching image found (%s)' % - image) - - image = pyrax.utils.get_id(image) - - # Check if the provided network is a UUID and if not, search for an - # appropriate network using label + image = rax_find_image(module, pyrax, image) + nics = [] if networks: for network in networks: - try: - UUID(network) - except ValueError: - if network.lower() == 'public': - nics.extend(cnw.get_server_networks(PUBLIC_NET_ID)) - elif network.lower() == 'private': - nics.extend(cnw.get_server_networks(SERVICE_NET_ID)) - else: - try: - network_obj = cnw.find_network_by_label(network) - except (pyrax.exceptions.NetworkNotFound, - pyrax.exceptions.NetworkLabelNotUnique): - module.fail_json(msg='No matching network found ' - '(%s)' % network) - else: - nics.extend(cnw.get_server_networks(network_obj)) - else: - nics.extend(cnw.get_server_networks(network)) + nics.extend(rax_find_network(module, pyrax, network)) for nic in nics: # pyrax is currently returning net-id, but we need uuid @@ -322,7 +265,7 @@ def rax_asg(module, cooldown=300, disk_config=None, files={}, flavor=None, sg.get() - module.exit_json(changed=changed, autoscale_group=asg_to_dict(sg)) + module.exit_json(changed=changed, autoscale_group=rax_to_dict(sg)) else: try: @@ -334,7 +277,7 @@ def rax_asg(module, cooldown=300, disk_config=None, files={}, flavor=None, except Exception, e: module.fail_json(msg='%s' % e.message) - module.exit_json(changed=changed, autoscale_group=asg_to_dict(sg)) + module.exit_json(changed=changed, autoscale_group=rax_to_dict(sg)) def main(): diff --git a/cloud/rax_scaling_policy b/cloud/rax_scaling_policy index 19174ba370c..b3da82460d8 100644 --- a/cloud/rax_scaling_policy +++ b/cloud/rax_scaling_policy @@ -118,27 +118,12 @@ EXAMPLES = ''' register: asp_webhook ''' -from uuid import UUID - try: import pyrax HAS_PYRAX = True except ImportError: HAS_PYRAX = False -NON_CALLABLES = (basestring, bool, dict, int, list, type(None)) -PUBLIC_NET_ID = "00000000-0000-0000-0000-000000000000" -SERVICE_NET_ID = "11111111-1111-1111-1111-111111111111" - - -def to_dict(obj): - instance = {} - for key in dir(obj): - value = getattr(obj, key) - if (isinstance(value, NON_CALLABLES) and not key.startswith('_')): - instance[key] = value - return instance - def rax_asp(module, at=None, change=0, cron=None, cooldown=300, desired_capacity=0, is_percent=False, name=None, @@ -220,7 +205,7 @@ def rax_asp(module, at=None, change=0, cron=None, cooldown=300, policy.get() - module.exit_json(changed=changed, autoscale_policy=to_dict(policy)) + module.exit_json(changed=changed, autoscale_policy=rax_to_dict(policy)) else: try: @@ -235,7 +220,7 @@ def rax_asp(module, at=None, change=0, cron=None, cooldown=300, except Exception, e: module.fail_json(msg='%s' % e.message) - module.exit_json(changed=changed, autoscale_policy=to_dict(policy)) + module.exit_json(changed=changed, autoscale_policy=rax_to_dict(policy)) def main():