From 585fd5a138fa1664f4b594b7656a53e5a90ad95b Mon Sep 17 00:00:00 2001
From: Matt Martz <matt@sivel.net>
Date: Tue, 10 Jun 2014 10:08:12 -0500
Subject: [PATCH] Move additional rackspace common code into module_utils/rax.py

---
 lib/ansible/module_utils/rax.py   | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 library/cloud/rax                 |  83 ++++++++---------------------------------------------------------------------------
 library/cloud/rax_cbs             |  20 +-------------------
 library/cloud/rax_cbs_attachments |  48 +++---------------------------------------------
 library/cloud/rax_clb             |  46 +++++-----------------------------------------
 library/cloud/rax_clb_nodes       |  18 +-----------------
 library/cloud/rax_dns             |  15 +--------------
 library/cloud/rax_dns_record      |  21 +++------------------
 library/cloud/rax_facts           |  20 +-------------------
 library/cloud/rax_files           |   5 -----
 library/cloud/rax_files_objects   |   2 --
 library/cloud/rax_identity        |   5 -----
 library/cloud/rax_keypair         |  15 +--------------
 library/cloud/rax_scaling_group   |  67 +++++--------------------------------------------------------------
 library/cloud/rax_scaling_policy  |  19 ++-----------------
 15 files changed, 175 insertions(+), 354 deletions(-)

diff --git a/lib/ansible/module_utils/rax.py b/lib/ansible/module_utils/rax.py
index 98623c7..9c02bd3 100644
--- a/lib/ansible/module_utils/rax.py
+++ b/lib/ansible/module_utils/rax.py
@@ -26,7 +26,147 @@
 # 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 os
+from uuid import UUID
+
+
+FINAL_STATUSES = ('ACTIVE', 'ERROR')
+VOLUME_STATUS = ('available', 'attaching', 'creating', 'deleting', 'in-use',
+                 'error', 'error_deleting')
+
+CLB_ALGORITHMS = ['RANDOM', 'LEAST_CONNECTIONS', 'ROUND_ROBIN',
+              'WEIGHTED_LEAST_CONNECTIONS', 'WEIGHTED_ROUND_ROBIN']
+CLB_PROTOCOLS = ['DNS_TCP', 'DNS_UDP', 'FTP', 'HTTP', 'HTTPS', 'IMAPS',
+                 'IMAPv4', 'LDAP', 'LDAPS', 'MYSQL', 'POP3', 'POP3S', 'SMTP',
+                 'TCP', 'TCP_CLIENT_FIRST', 'UDP', 'UDP_STREAM', 'SFTP']
+
+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 rax_slugify(value):
+    """Prepend a key with rax_ and normalize the key name"""
+    return 'rax_%s' % (re.sub('[^\w-]', '_', value).lower().lstrip('_'))
+
+
+def rax_clb_node_to_dict(obj):
+    """Function to convert a CLB Node object to a dict"""
+    if not obj:
+        return {}
+    node = obj.to_dict()
+    node['id'] = obj.id
+    node['weight'] = obj.weight
+    return node
+
+
+def rax_to_dict(obj, obj_type='standard'):
+    """Generic function to convert a pyrax object to a dict
+
+    obj_type values:
+        standard
+        clb
+        server
+
+    """
+    instance = {}
+    for key in dir(obj):
+        value = getattr(obj, key)
+        if obj_type == 'clb' and key == 'nodes':
+            instance[key] = []
+            for node in value:
+                instance[key].append(rax_clb_node_to_dict(node))
+        elif (isinstance(value, list) and len(value) > 0 and
+                not isinstance(value[0], NON_CALLABLES)):
+            instance[key] = []
+            for item in value:
+                instance[key].append(rax_to_dict(item))
+        elif (isinstance(value, NON_CALLABLES) and not key.startswith('_')):
+            if obj_type == 'server':
+                key = rax_slugify(key)
+            instance[key] = value
+
+    if obj_type == 'server':
+        for attr in ['id', 'accessIPv4', 'name', 'status']:
+            instance[attr] = instance.get(rax_slugify(attr))
+
+    return instance
+
+
+def rax_find_image(module, rax_module, image):
+    cs = rax_module.cloudservers
+    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)
+
+    return rax_module.utils.get_id(image)
+
+
+def rax_find_volume(module, rax_module, name):
+    cbs = rax_module.cloud_blockstorage
+    try:
+        UUID(name)
+        volume = cbs.get(name)
+    except ValueError:
+        try:
+            volume = cbs.find(name=name)
+        except rax_module.exc.NotFound:
+            volume = None
+        except Exception, e:
+            module.fail_json(msg='%s' % e)
+    return volume
+
+
+def rax_find_network(module, rax_module, network):
+    cnw = rax_module.cloud_networks
+    try:
+        UUID(network)
+    except ValueError:
+        if network.lower() == 'public':
+            return cnw.get_server_networks(PUBLIC_NET_ID)
+        elif network.lower() == 'private':
+            return cnw.get_server_networks(SERVICE_NET_ID)
+        else:
+            try:
+                network_obj = cnw.find_network_by_label(network)
+            except (rax_module.exceptions.NetworkNotFound,
+                    rax_module.exceptions.NetworkLabelNotUnique):
+                module.fail_json(msg='No matching network found (%s)' %
+                                     network)
+            else:
+                return cnw.get_server_networks(network_obj)
+    else:
+        return cnw.get_server_networks(network)
+
+
+def rax_find_server(module, rax_module, server):
+    cs = rax_module.cloudservers
+    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]
+    return server
+
 
 def rax_argument_spec():
     return dict(
@@ -48,6 +188,9 @@ def rax_required_together():
 
 
 def setup_rax_module(module, rax_module):
+    rax_module.USER_AGENT = 'ansible/%s %s' % (ANSIBLE_VERSION,
+                                               rax_module.USER_AGENT)
+
     api_key = module.params.get('api_key')
     auth_endpoint = module.params.get('auth_endpoint')
     credentials = module.params.get('credentials')
diff --git a/library/cloud/rax b/library/cloud/rax
index f7ea8e9..35156a0 100644
--- a/library/cloud/rax
+++ b/library/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/library/cloud/rax_cbs b/library/cloud/rax_cbs
index ade2b83..a1b6ce4 100644
--- a/library/cloud/rax_cbs
+++ b/library/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/library/cloud/rax_cbs_attachments b/library/cloud/rax_cbs_attachments
index bc7dba9..365f93c 100644
--- a/library/cloud/rax_cbs_attachments
+++ b/library/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/library/cloud/rax_clb b/library/cloud/rax_clb
index 8570089..7a26997 100644
--- a/library/cloud/rax_clb
+++ b/library/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/library/cloud/rax_clb_nodes b/library/cloud/rax_clb_nodes
index dc0950d..24325b4 100644
--- a/library/cloud/rax_clb_nodes
+++ b/library/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/library/cloud/rax_dns b/library/cloud/rax_dns
index 57bc75a..e726851 100644
--- a/library/cloud/rax_dns
+++ b/library/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/library/cloud/rax_dns_record b/library/cloud/rax_dns_record
index dc85f2e..05c7a8f 100644
--- a/library/cloud/rax_dns_record
+++ b/library/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/library/cloud/rax_facts b/library/cloud/rax_facts
index 64711f4..68ef446 100644
--- a/library/cloud/rax_facts
+++ b/library/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/library/cloud/rax_files b/library/cloud/rax_files
index 68e28a0..3c54b0a 100644
--- a/library/cloud/rax_files
+++ b/library/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/library/cloud/rax_files_objects b/library/cloud/rax_files_objects
index d7f1190..de8400c 100644
--- a/library/cloud/rax_files_objects
+++ b/library/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/library/cloud/rax_identity b/library/cloud/rax_identity
index 591cd01..9de4db9 100644
--- a/library/cloud/rax_identity
+++ b/library/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/library/cloud/rax_keypair b/library/cloud/rax_keypair
index 2e34726..591ad8c 100644
--- a/library/cloud/rax_keypair
+++ b/library/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/library/cloud/rax_scaling_group b/library/cloud/rax_scaling_group
index 2c63559..d884d3c 100644
--- a/library/cloud/rax_scaling_group
+++ b/library/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/library/cloud/rax_scaling_policy b/library/cloud/rax_scaling_policy
index 19174ba..b3da824 100644
--- a/library/cloud/rax_scaling_policy
+++ b/library/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():
--
libgit2 0.26.0