From 37f096a6bb3f75514e061efad19a64d7af7922b1 Mon Sep 17 00:00:00 2001 From: Matt Martz Date: Wed, 12 Feb 2014 21:51:36 -0600 Subject: [PATCH] rax modules improvements * Catch issues with invalid regions * Ensure we send string only data as meta values in the rax module * Add public_key/lookup example for rax_keypair * Clean up import statements --- library/cloud/rax | 31 +++++++++++++------- library/cloud/rax_clb | 15 ++++++---- library/cloud/rax_clb_nodes | 13 +++++---- library/cloud/rax_dns | 16 +++++++---- library/cloud/rax_dns_record | 16 +++++++---- library/cloud/rax_facts | 18 ++++++++---- library/cloud/rax_files | 48 ++++++++++++++++++++----------- library/cloud/rax_files_objects | 51 +++++++++++++++++++-------------- library/cloud/rax_identity | 16 +++++++---- library/cloud/rax_keypair | 32 +++++++++++++++++---- library/cloud/rax_network | 23 ++++++++------- library/cloud/rax_queue | 17 ++++++----- 12 files changed, 191 insertions(+), 105 deletions(-) diff --git a/library/cloud/rax b/library/cloud/rax index 248790037eb..af533bca126 100644 --- a/library/cloud/rax +++ b/library/cloud/rax @@ -1,4 +1,4 @@ -#!/usr/bin/python -tt +#!/usr/bin/python # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify @@ -175,18 +175,18 @@ EXAMPLES = ''' register: rax ''' -import sys -import time import os import re +import time + from uuid import UUID from types import NoneType try: import pyrax + HAS_PYRAX = True except ImportError: - print("failed=True msg='pyrax is required for this module'") - sys.exit(1) + HAS_PYRAX = False ACTIVE_STATUSES = ('ACTIVE', 'BUILD', 'HARD_REBOOT', 'MIGRATING', 'PASSWORD', 'REBOOT', 'REBUILD', 'RESCUE', 'RESIZE', 'REVERT_RESIZE') @@ -379,8 +379,16 @@ def cloudservers(module, state, name, flavor, image, meta, key_name, files, auto_increment, extra_create_args): cs = pyrax.cloudservers cnw = pyrax.cloud_networks + if not cnw: + module.fail_json(msg='Failed to instantiate client. This ' + 'typically indicates an invalid region or an ' + 'incorrectly capitalized region name.') + servers = [] + for key, value in meta.items(): + meta[key] = repr(value) + # Add the group meta key if group and 'group' not in meta: meta['group'] = group @@ -641,6 +649,9 @@ def main(): required_together=rax_required_together(), ) + if not HAS_PYRAX: + module.fail_json(msg='pyrax is required for this module') + service = module.params.get('service') if service is not None: @@ -672,11 +683,6 @@ def main(): setup_rax_module(module, pyrax) - if pyrax.cloudservers is None: - module.fail_json(msg='Failed to instantiate client. This ' - 'typically indicates an invalid region or an ' - 'incorrectly capitalized region name.') - if extra_client_args: pyrax.cloudservers = pyrax.connect_to_cloudservers( region=pyrax.cloudservers.client.region_name, @@ -685,6 +691,11 @@ def main(): if 'bypass_url' in extra_client_args: client.management_url = extra_client_args['bypass_url'] + if pyrax.cloudservers is None: + module.fail_json(msg='Failed to instantiate client. This ' + 'typically indicates an invalid region or an ' + 'incorrectly capitalized region name.') + cloudservers(module, state, name, flavor, image, meta, key_name, files, wait, wait_timeout, disk_config, count, group, instance_ids, exact_count, networks, count_offset, diff --git a/library/cloud/rax_clb b/library/cloud/rax_clb index dbc7f85b196..85700895c7c 100644 --- a/library/cloud/rax_clb +++ b/library/cloud/rax_clb @@ -1,4 +1,4 @@ -#!/usr/bin/python -tt +#!/usr/bin/python # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify @@ -130,15 +130,13 @@ EXAMPLES = ''' register: my_lb ''' -import sys - from types import NoneType try: import pyrax + HAS_PYRAX = True except ImportError: - print("failed=True msg='pyrax required for this module'") - sys.exit(1) + HAS_PYRAX = False NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) ALGORITHMS = ['RANDOM', 'LEAST_CONNECTIONS', 'ROUND_ROBIN', @@ -190,6 +188,10 @@ def cloud_load_balancer(module, state, name, meta, algorithm, port, protocol, balancers = [] clb = pyrax.cloud_loadbalancers + if not clb: + module.fail_json(msg='Failed to instantiate client. This ' + 'typically indicates an invalid region or an ' + 'incorrectly capitalized region name.') for balancer in clb.list(): if name != balancer.name and name != balancer.id: @@ -308,6 +310,9 @@ def main(): required_together=rax_required_together(), ) + if not HAS_PYRAX: + module.fail_json(msg='pyrax is required for this module') + algorithm = module.params.get('algorithm') meta = module.params.get('meta') name = module.params.get('name') diff --git a/library/cloud/rax_clb_nodes b/library/cloud/rax_clb_nodes index fb12967ec1d..04ec11fc94f 100644 --- a/library/cloud/rax_clb_nodes +++ b/library/cloud/rax_clb_nodes @@ -121,13 +121,12 @@ EXAMPLES = ''' ''' import os -import sys try: import pyrax + HAS_PYRAX = True except ImportError: - print("failed=True msg='pyrax is required for this module'") - sys.exit(1) + HAS_PYRAX = False def _activate_virtualenv(path): @@ -196,6 +195,9 @@ def main(): required_together=rax_required_together(), ) + if not HAS_PYRAX: + module.fail_json(msg='pyrax is required for this module') + address = module.params['address'] condition = (module.params['condition'] and module.params['condition'].upper()) @@ -219,8 +221,9 @@ def main(): setup_rax_module(module, pyrax) if not pyrax.cloud_loadbalancers: - module.fail_json(msg='Failed to instantiate load balancer client ' - '(possibly incorrect region)') + module.fail_json(msg='Failed to instantiate client. This ' + 'typically indicates an invalid region or an ' + 'incorrectly capitalized region name.') try: lb = pyrax.cloud_loadbalancers.get(load_balancer_id) diff --git a/library/cloud/rax_dns b/library/cloud/rax_dns index 7ed2c926d6f..c12d09fb1ad 100644 --- a/library/cloud/rax_dns +++ b/library/cloud/rax_dns @@ -1,4 +1,4 @@ -#!/usr/bin/python -tt +#!/usr/bin/python # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify @@ -62,16 +62,13 @@ EXAMPLES = ''' register: rax_dns ''' -import sys -import os - from types import NoneType try: import pyrax + HAS_PYRAX = True except ImportError: - print("failed=True msg='pyrax required for this module'") - sys.exit(1) + HAS_PYRAX = False NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) @@ -89,6 +86,10 @@ def rax_dns(module, comment, email, name, state, ttl): changed = False dns = pyrax.cloud_dns + if not dns: + module.fail_json(msg='Failed to instantiate client. This ' + 'typically indicates an invalid region or an ' + 'incorrectly capitalized region name.') if state == 'present': if not email: @@ -159,6 +160,9 @@ def main(): required_together=rax_required_together(), ) + if not HAS_PYRAX: + module.fail_json(msg='pyrax is required for this module') + comment = module.params.get('comment') email = module.params.get('email') name = module.params.get('name') diff --git a/library/cloud/rax_dns_record b/library/cloud/rax_dns_record index 51dc26b779f..d1e79983604 100644 --- a/library/cloud/rax_dns_record +++ b/library/cloud/rax_dns_record @@ -1,4 +1,4 @@ -#!/usr/bin/python -tt +#!/usr/bin/python # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify @@ -87,16 +87,13 @@ EXAMPLES = ''' register: rax_dns_record ''' -import sys -import os - from types import NoneType try: import pyrax + HAS_PYRAX = True except ImportError: - print("failed=True msg='pyrax required for this module'") - sys.exit(1) + HAS_PYRAX = False NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) @@ -115,6 +112,10 @@ def rax_dns_record(module, comment, data, domain, name, priority, record_type, changed = False dns = pyrax.cloud_dns + if not dns: + module.fail_json(msg='Failed to instantiate client. This ' + 'typically indicates an invalid region or an ' + 'incorrectly capitalized region name.') if state == 'present': if not priority and record_type in ['MX', 'SRV']: @@ -211,6 +212,9 @@ def main(): required_together=rax_required_together(), ) + if not HAS_PYRAX: + module.fail_json(msg='pyrax is required for this module') + comment = module.params.get('comment') data = module.params.get('data') domain = module.params.get('domain') diff --git a/library/cloud/rax_facts b/library/cloud/rax_facts index f71982f4243..64711f41519 100644 --- a/library/cloud/rax_facts +++ b/library/cloud/rax_facts @@ -1,4 +1,4 @@ -#!/usr/bin/python -tt +#!/usr/bin/python # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify @@ -55,16 +55,13 @@ EXAMPLES = ''' ansible_ssh_host: "{{ rax_accessipv4 }}" ''' -import sys -import os - from types import NoneType try: import pyrax + HAS_PYRAX = True except ImportError: - print("failed=True msg='pyrax required for this module'") - sys.exit(1) + HAS_PYRAX = False NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) @@ -87,6 +84,12 @@ def rax_facts(module, address, name, server_id): changed = False cs = pyrax.cloudservers + + if cs is None: + module.fail_json(msg='Failed to instantiate client. This ' + 'typically indicates an invalid region or an ' + 'incorrectly capitalized region name.') + ansible_facts = {} search_opts = {} @@ -139,6 +142,9 @@ def main(): required_one_of=[['address', 'id', 'name']], ) + if not HAS_PYRAX: + module.fail_json(msg='pyrax is required for this module') + address = module.params.get('address') server_id = module.params.get('id') name = module.params.get('name') diff --git a/library/cloud/rax_files b/library/cloud/rax_files index bdb11a661f5..68e28a07f74 100644 --- a/library/cloud/rax_files +++ b/library/cloud/rax_files @@ -1,4 +1,4 @@ -#!/usr/bin/python -tt +#!/usr/bin/python # (c) 2013, Paul Durivage # @@ -143,9 +143,9 @@ from ansible import __version__ try: import pyrax + HAS_PYRAX = True except ImportError, e: - print("failed=True msg='pyrax is required for this module'") - sys.exit(1) + HAS_PYRAX = False EXIT_DICT = dict(success=True) META_PREFIX = 'x-container-meta-' @@ -200,7 +200,8 @@ def meta(cf, module, container_, state, meta_, clear_meta): module.exit_json(**EXIT_DICT) -def container(cf, module, container_, state, meta_, clear_meta, ttl, public, private, web_index, web_error): +def container(cf, module, container_, state, meta_, clear_meta, ttl, public, + private, web_index, web_error): if public and private: module.fail_json(msg='container cannot be simultaneously ' 'set to public and private') @@ -297,9 +298,8 @@ def container(cf, module, container_, state, meta_, clear_meta, ttl, public, pri EXIT_DICT['container'] = c.name EXIT_DICT['objs_in_container'] = c.object_count EXIT_DICT['total_bytes'] = c.total_bytes - + _locals = locals().keys() - if ('cont_deleted' in _locals or 'meta_set' in _locals or 'cont_public' in _locals @@ -311,15 +311,23 @@ def container(cf, module, container_, state, meta_, clear_meta, ttl, public, pri module.exit_json(**EXIT_DICT) -def cloudfiles(module, container_, state, meta_, clear_meta, typ, ttl, public, private, web_index, web_error): - """ Dispatch from here to work with metadata or file objects """ - cf = pyrax.cloudfiles - cf.user_agent = USER_AGENT +def cloudfiles(module, container_, state, meta_, clear_meta, typ, ttl, public, + private, web_index, web_error): + """ Dispatch from here to work with metadata or file objects """ + cf = pyrax.cloudfiles - if typ == "container": - container(cf, module, container_, state, meta_, clear_meta, ttl, public, private, web_index, web_error) - else: - meta(cf, module, container_, state, meta_, clear_meta) + if cf is None: + module.fail_json(msg='Failed to instantiate client. This ' + '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) + else: + meta(cf, module, container_, state, meta_, clear_meta) def main(): @@ -327,7 +335,8 @@ def main(): argument_spec.update( dict( container=dict(), - state=dict(choices=['present', 'absent', 'list'], default='present'), + state=dict(choices=['present', 'absent', 'list'], + default='present'), meta=dict(type='dict', default=dict()), clear_meta=dict(default=False, type='bool'), type=dict(choices=['container', 'meta'], default='container'), @@ -344,6 +353,9 @@ def main(): required_together=rax_required_together() ) + if not HAS_PYRAX: + module.fail_json(msg='pyrax is required for this module') + container_ = module.params.get('container') state = module.params.get('state') meta_ = module.params.get('meta') @@ -358,10 +370,12 @@ def main(): if state in ['present', 'absent'] and not container_: module.fail_json(msg='please specify a container name') if clear_meta and not typ == 'meta': - module.fail_json(msg='clear_meta can only be used when setting metadata') + module.fail_json(msg='clear_meta can only be used when setting ' + 'metadata') setup_rax_module(module, pyrax) - cloudfiles(module, container_, state, meta_, clear_meta, typ, ttl, public, private, web_index, web_error) + cloudfiles(module, container_, state, meta_, clear_meta, typ, ttl, public, + private, web_index, web_error) from ansible.module_utils.basic import * diff --git a/library/cloud/rax_files_objects b/library/cloud/rax_files_objects index 9002291ceff..d7f11900ab9 100644 --- a/library/cloud/rax_files_objects +++ b/library/cloud/rax_files_objects @@ -1,4 +1,4 @@ -#!/usr/bin/python -tt +#!/usr/bin/python # (c) 2013, Paul Durivage # @@ -187,9 +187,9 @@ import os try: import pyrax -except ImportError, e: - print("failed=True msg='pyrax is required for this module'") - sys.exit(1) + HAS_PYRAX = True +except ImportError: + HAS_PYRAX = False EXIT_DICT = dict(success=False) META_PREFIX = 'x-object-meta-' @@ -433,7 +433,6 @@ def get_meta(module, cf, container, src, dest): meta_key = k.split(META_PREFIX)[-1] results[obj][meta_key] = v - EXIT_DICT['container'] = c.name if results: EXIT_DICT['meta_results'] = results @@ -530,28 +529,33 @@ def delete_meta(module, cf, container, src, dest, meta): def cloudfiles(module, container, src, dest, method, typ, meta, clear_meta, structure, expires): - """ Dispatch from here to work with metadata or file objects """ - cf = pyrax.cloudfiles + """ Dispatch from here to work with metadata or file objects """ + cf = pyrax.cloudfiles - if typ == "file": - if method == 'put': - upload(module, cf, container, src, dest, meta, expires) + if cf is None: + module.fail_json(msg='Failed to instantiate client. This ' + 'typically indicates an invalid region or an ' + 'incorrectly capitalized region name.') - elif method == 'get': - download(module, cf, container, src, dest, structure) + if typ == "file": + if method == 'put': + upload(module, cf, container, src, dest, meta, expires) - elif method == 'delete': - delete(module, cf, container, src, dest) + elif method == 'get': + download(module, cf, container, src, dest, structure) - else: - if method == 'get': - get_meta(module, cf, container, src, dest) + elif method == 'delete': + delete(module, cf, container, src, dest) - if method == 'put': - put_meta(module, cf, container, src, dest, meta, clear_meta) + else: + if method == 'get': + get_meta(module, cf, container, src, dest) - if method == 'delete': - delete_meta(module, cf, container, src, dest, meta) + if method == 'put': + put_meta(module, cf, container, src, dest, meta, clear_meta) + + if method == 'delete': + delete_meta(module, cf, container, src, dest, meta) def main(): @@ -575,6 +579,9 @@ def main(): required_together=rax_required_together() ) + if not HAS_PYRAX: + module.fail_json(msg='pyrax is required for this module') + container = module.params.get('container') src = module.params.get('src') dest = module.params.get('dest') @@ -595,4 +602,4 @@ def main(): from ansible.module_utils.basic import * from ansible.module_utils.rax import * -main() \ No newline at end of file +main() diff --git a/library/cloud/rax_identity b/library/cloud/rax_identity index 2890e40d160..b9b82f13f16 100644 --- a/library/cloud/rax_identity +++ b/library/cloud/rax_identity @@ -1,4 +1,4 @@ -#!/usr/bin/python -tt +#!/usr/bin/python # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify @@ -68,15 +68,13 @@ EXAMPLES = ''' register: rackspace_identity ''' -import sys - from types import NoneType try: import pyrax + HAS_PYRAX = True except ImportError: - print("failed=True msg='pyrax required for this module'") - sys.exit(1) + HAS_PYRAX = False NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) @@ -118,10 +116,18 @@ def main(): required_together=rax_required_together() ) + if not HAS_PYRAX: + module.fail_json(msg='pyrax is required for this module') + state = module.params.get('state') setup_rax_module(module, pyrax) + if pyrax.identity is None: + module.fail_json(msg='Failed to instantiate client. This ' + 'typically indicates an invalid region or an ' + 'incorrectly capitalized region name.') + cloud_identity(module, state, pyrax.identity) # import module snippets diff --git a/library/cloud/rax_keypair b/library/cloud/rax_keypair index 6a42e3c99f9..458ec5713c4 100644 --- a/library/cloud/rax_keypair +++ b/library/cloud/rax_keypair @@ -1,4 +1,4 @@ -#!/usr/bin/python -tt +#!/usr/bin/python # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify @@ -48,7 +48,7 @@ extends_documentation_fragment: rackspace.openstack EXAMPLES = ''' - name: Create a keypair - hosts: local + hosts: localhost gather_facts: False tasks: - name: keypair request @@ -68,17 +68,28 @@ EXAMPLES = ''' module: copy content: "{{ keypair.keypair.private_key }}" dest: "{{ inventory_dir }}/{{ keypair.keypair.name }}" -''' -import sys +- name: Create a keypair + hosts: localhost + gather_facts: False + tasks: + - name: keypair request + local_action: + module: rax_keypair + credentials: ~/.raxpub + name: my_keypair + public_key: "{{ lookup('file', 'authorized_keys/id_rsa.pub') }}" + region: DFW + register: keypair +''' from types import NoneType try: import pyrax + HAS_PYRAX = True except ImportError: - print("failed=True msg='pyrax required for this module'") - sys.exit(1) + HAS_PYRAX = False NON_CALLABLES = (basestring, bool, dict, int, list, NoneType) @@ -96,6 +107,12 @@ def rax_keypair(module, name, public_key, state): changed = False cs = pyrax.cloudservers + + if cs is None: + module.fail_json(msg='Failed to instantiate client. This ' + 'typically indicates an invalid region or an ' + 'incorrectly capitalized region name.') + keypair = {} if state == 'present': @@ -141,6 +158,9 @@ def main(): required_together=rax_required_together(), ) + if not HAS_PYRAX: + module.fail_json(msg='pyrax is required for this module') + name = module.params.get('name') public_key = module.params.get('public_key') state = module.params.get('state') diff --git a/library/cloud/rax_network b/library/cloud/rax_network index ac3aca6991e..bc4745a7a84 100644 --- a/library/cloud/rax_network +++ b/library/cloud/rax_network @@ -1,4 +1,4 @@ -#!/usr/bin/python -tt +#!/usr/bin/python # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify @@ -57,16 +57,11 @@ EXAMPLES = ''' state: present ''' -import sys -import os - try: import pyrax - import pyrax.utils - from pyrax import exc + HAS_PYRAX = True except ImportError: - print("failed=True msg='pyrax required for this module'") - sys.exit(1) + HAS_PYRAX = False def cloud_network(module, state, label, cidr): @@ -78,10 +73,15 @@ def cloud_network(module, state, label, cidr): network = None networks = [] + if not pyrax.cloud_networks: + module.fail_json(msg='Failed to instantiate client. This ' + 'typically indicates an invalid region or an ' + 'incorrectly capitalized region name.') + if state == 'present': try: network = pyrax.cloud_networks.find_network_by_label(label) - except exc.NetworkNotFound: + except pyrax.exceptions.NetworkNotFound: try: network = pyrax.cloud_networks.create(label, cidr=cidr) changed = True @@ -95,7 +95,7 @@ def cloud_network(module, state, label, cidr): network = pyrax.cloud_networks.find_network_by_label(label) network.delete() changed = True - except exc.NetworkNotFound: + except pyrax.exceptions.NetworkNotFound: pass except Exception, e: module.fail_json(msg='%s' % e.message) @@ -125,6 +125,9 @@ def main(): required_together=rax_required_together(), ) + if not HAS_PYRAX: + module.fail_json(msg='pyrax is required for this module') + state = module.params.get('state') label = module.params.get('label') cidr = module.params.get('cidr') diff --git a/library/cloud/rax_queue b/library/cloud/rax_queue index 7388c4ed81d..d3e5ac3f81e 100644 --- a/library/cloud/rax_queue +++ b/library/cloud/rax_queue @@ -1,4 +1,4 @@ -#!/usr/bin/python -tt +#!/usr/bin/python # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify @@ -55,15 +55,11 @@ EXAMPLES = ''' register: my_queue ''' -import sys -import os - - try: import pyrax + HAS_PYRAX = True except ImportError: - print("failed=True msg='pyrax is required for this module'") - sys.exit(1) + HAS_PYRAX = False def cloud_queue(module, state, name): @@ -76,6 +72,10 @@ def cloud_queue(module, state, name): instance = {} cq = pyrax.queues + if not cq: + module.fail_json(msg='Failed to instantiate client. This ' + 'typically indicates an invalid region or an ' + 'incorrectly capitalized region name.') for queue in cq.list(): if name != queue.name: @@ -126,6 +126,9 @@ def main(): required_together=rax_required_together() ) + if not HAS_PYRAX: + module.fail_json(msg='pyrax is required for this module') + name = module.params.get('name') state = module.params.get('state')