From dc30f4c1bf2c564db4cc466900930c4bfa84726f Mon Sep 17 00:00:00 2001 From: "Christopher H. Laco" Date: Sat, 19 Oct 2013 09:36:55 -0400 Subject: [PATCH 1/2] Add rax_network module Based on the refactor work @sivel is doing, adding a rax_network module to create/delete networks in the Rackspace Public Cloud. See: https://github.com/ansible/ansible/issues/4577 --- cloud/rax_network | 181 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 cloud/rax_network diff --git a/cloud/rax_network b/cloud/rax_network new file mode 100644 index 00000000000..c7b6bb56a82 --- /dev/null +++ b/cloud/rax_network @@ -0,0 +1,181 @@ +#!/usr/bin/python -tt +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +DOCUMENTATION = ''' +--- +module: rax_network +short_description: create / delete an isolated network in Rackspace Public Cloud +description: + - creates / deletes a Rackspace Public Cloud isolated network. +version_added: "1.4" +options: + state: + description: + - Indicate desired state of the resource + choices: ['present', 'absent', 'deleted'] + default: present + credentials: + description: + - File to find the Rackspace credentials in (ignored if C(api_key) and + C(username) are provided) + default: null + aliases: ['creds_file'] + api_key: + description: + - Rackspace API key (overrides C(credentials)) + username: + description: + - Rackspace username (overrides C(credentials)) + label: + description: + - Label (name) to give the network + default: null + cidr: + description: + - cidr of the network being created + default: null + region: + description: + - Region to create the network in + default: DFW +requirements: [ "pyrax" ] +author: Christopher H. Laco, Jesse Keating +notes: + - The following environment variables can be used, C(RAX_USERNAME), + C(RAX_API_KEY), C(RAX_CREDS), C(RAX_CREDENTIALS), C(RAX_REGION). + - C(RAX_CREDENTIALS) and C(RAX_CREDS) points to a credentials file + appropriate for pyrax + - C(RAX_USERNAME) and C(RAX_API_KEY) obviate the use of a credentials file + - C(RAX_REGION) defines a Rackspace Public Cloud region (DFW, ORD, LON, ...) +''' + +EXAMPLES = ''' +- name: Build an Isolated Network + gather_facts: False + + tasks: + - name: Network create request + local_action: + module: rax_network + credentials: ~/.raxpub + label: my-net + cidr: 192.168.3.0/24 + state: present +''' + +import sys +import os + +try: + import pyrax + import pyrax.utils + from pyrax import exc +except ImportError: + print("failed=True msg='pyrax required for this module'") + sys.exit(1) + + +def cloud_network(module, state, label, cidr): + for arg in (state, label, cidr): + if not arg: + module.fail_json(msg='%s is required for cloud_networks' % arg) + + instances = [] + changed = False + network = None + + if state == 'present': + try: + network = pyrax.cloud_networks.find_network_by_label(label) + except exc.NetworkNotFound: + try: + network = pyrax.cloud_networks.create(label, cidr=cidr) + changed = True + except Exception, e: + module.fail_json(msg='%s' % e.message) + except Exception: + module.fail_json(msg='%s' % e.message) + + elif state in ('absent', 'deleted'): + try: + network = pyrax.cloud_networks.find_network_by_label(label) + network.delete() + changed = True + except exc.NetworkNotFound: + pass + except Exception, e: + module.fail_json(msg='%s' % e.message) + + if network: + instance = {'id': network.id, + 'label': network.label, + 'cidr': network.cidr} + instances.append(instance) + + module.exit_json(changed=changed, instances=instances) + + +def main(): + module = AnsibleModule( + argument_spec=dict( + state=dict(default='present', + choices=['present', 'deleted', 'absent']), + credentials=dict(aliases=['creds_file']), + api_key=dict(), + username=dict(), + region=dict(), + label=dict(), + cidr=dict() + ) + ) + + credentials = module.params.get('credentials') + api_key = module.params.get('api_key') + username = module.params.get('username') + region = module.params.get('region') + state = module.params.get('state') + label = module.params.get('label') + cidr = module.params.get('cidr') + + try: + username = username or os.environ.get('RAX_USERNAME') + api_key = api_key or os.environ.get('RAX_API_KEY') + credentials = credentials or \ + os.environ.get('RAX_CREDENTIALS') or \ + os.environ.get('RAX_CREDS_FILE') + region = region or os.environ.get('RAX_REGION') + + except KeyError, e: + module.fail_json(msg='Unable to load %s' % e.message) + + try: + pyrax.set_setting("identity_type", "rackspace") + if api_key and username: + pyrax.set_credentials(username, api_key=api_key, region=region) + elif credentials: + credentials = os.path.expanduser(credentials) + pyrax.set_credential_file(credentials, region=region) + else: + raise Exception('No credentials supplied!') + except Exception, e: + module.fail_json(msg='%s' % e.message) + + cloud_network(module, state, label, cidr) + +# this is magic, see lib/ansible/module_common.py +#<> + +main() From b414a3af6f8b74dcb8a3f805adfd5416b070bba9 Mon Sep 17 00:00:00 2001 From: "Christopher H. Laco" Date: Sun, 20 Oct 2013 15:30:46 -0400 Subject: [PATCH 2/2] Update module based on upstream feedback - Remove deleted state - Use dict() instead of raw hash - Wrap or statements in parens instead of backslash line continuations - Change instances to networks in module return result --- cloud/rax_network | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cloud/rax_network b/cloud/rax_network index c7b6bb56a82..6c6fc5de6d0 100644 --- a/cloud/rax_network +++ b/cloud/rax_network @@ -25,7 +25,7 @@ options: state: description: - Indicate desired state of the resource - choices: ['present', 'absent', 'deleted'] + choices: ['present', 'absent'] default: present credentials: description: @@ -93,9 +93,9 @@ def cloud_network(module, state, label, cidr): if not arg: module.fail_json(msg='%s is required for cloud_networks' % arg) - instances = [] changed = False network = None + networks = [] if state == 'present': try: @@ -109,7 +109,7 @@ def cloud_network(module, state, label, cidr): except Exception: module.fail_json(msg='%s' % e.message) - elif state in ('absent', 'deleted'): + elif state == 'absent': try: network = pyrax.cloud_networks.find_network_by_label(label) network.delete() @@ -120,19 +120,19 @@ def cloud_network(module, state, label, cidr): module.fail_json(msg='%s' % e.message) if network: - instance = {'id': network.id, - 'label': network.label, - 'cidr': network.cidr} - instances.append(instance) + instance = dict(id=network.id, + label=network.label, + cidr=network.cidr) + networks.append(instance) - module.exit_json(changed=changed, instances=instances) + module.exit_json(changed=changed, networks=networks) def main(): module = AnsibleModule( argument_spec=dict( state=dict(default='present', - choices=['present', 'deleted', 'absent']), + choices=['present', 'absent']), credentials=dict(aliases=['creds_file']), api_key=dict(), username=dict(), @@ -153,9 +153,9 @@ def main(): try: username = username or os.environ.get('RAX_USERNAME') api_key = api_key or os.environ.get('RAX_API_KEY') - credentials = credentials or \ - os.environ.get('RAX_CREDENTIALS') or \ - os.environ.get('RAX_CREDS_FILE') + credentials = (credentials or + os.environ.get('RAX_CREDENTIALS') or + os.environ.get('RAX_CREDS_FILE')) region = region or os.environ.get('RAX_REGION') except KeyError, e: