2014-03-10 21:06:52 +00:00
|
|
|
# This code is part of Ansible, but is an independent component.
|
|
|
|
# This particular file snippet, and this file snippet only, is BSD licensed.
|
|
|
|
# Modules you write using this snippet, which is embedded dynamically by Ansible
|
|
|
|
# still belong to the author of the module, and may assign their own license
|
|
|
|
# to the complete work.
|
|
|
|
#
|
|
|
|
# Copyright (c), Michael DeHaan <michael.dehaan@gmail.com>, 2012-2013
|
|
|
|
# All rights reserved.
|
|
|
|
#
|
|
|
|
# Redistribution and use in source and binary forms, with or without modification,
|
|
|
|
# are permitted provided that the following conditions are met:
|
|
|
|
#
|
|
|
|
# * Redistributions of source code must retain the above copyright
|
|
|
|
# notice, this list of conditions and the following disclaimer.
|
|
|
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
# this list of conditions and the following disclaimer in the documentation
|
|
|
|
# and/or other materials provided with the distribution.
|
|
|
|
#
|
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
# 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.
|
2013-11-19 18:51:04 +00:00
|
|
|
|
2014-06-10 15:08:12 +00:00
|
|
|
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
|
|
|
|
|
2013-11-19 18:51:04 +00:00
|
|
|
|
|
|
|
def rax_argument_spec():
|
|
|
|
return dict(
|
2014-01-24 01:54:37 +00:00
|
|
|
api_key=dict(type='str', aliases=['password'], no_log=True),
|
2014-01-24 17:34:21 +00:00
|
|
|
auth_endpoint=dict(type='str'),
|
2013-11-19 18:51:04 +00:00
|
|
|
credentials=dict(type='str', aliases=['creds_file']),
|
2014-01-24 17:34:21 +00:00
|
|
|
env=dict(type='str'),
|
2014-01-24 01:54:37 +00:00
|
|
|
identity_type=dict(type='str', default='rackspace'),
|
2013-11-19 18:51:04 +00:00
|
|
|
region=dict(type='str'),
|
2014-01-24 01:54:37 +00:00
|
|
|
tenant_id=dict(type='str'),
|
2014-01-27 19:33:42 +00:00
|
|
|
tenant_name=dict(type='str'),
|
2013-11-19 18:51:04 +00:00
|
|
|
username=dict(type='str'),
|
2014-01-24 17:34:21 +00:00
|
|
|
verify_ssl=dict(choices=BOOLEANS, type='bool'),
|
2013-11-19 18:51:04 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def rax_required_together():
|
|
|
|
return [['api_key', 'username']]
|
|
|
|
|
|
|
|
|
|
|
|
def setup_rax_module(module, rax_module):
|
2014-06-10 15:08:12 +00:00
|
|
|
rax_module.USER_AGENT = 'ansible/%s %s' % (ANSIBLE_VERSION,
|
|
|
|
rax_module.USER_AGENT)
|
|
|
|
|
2013-11-19 18:51:04 +00:00
|
|
|
api_key = module.params.get('api_key')
|
2014-01-24 01:54:37 +00:00
|
|
|
auth_endpoint = module.params.get('auth_endpoint')
|
2013-11-19 18:51:04 +00:00
|
|
|
credentials = module.params.get('credentials')
|
2014-01-24 17:34:21 +00:00
|
|
|
env = module.params.get('env')
|
2014-01-24 01:54:37 +00:00
|
|
|
identity_type = module.params.get('identity_type')
|
2013-11-19 18:51:04 +00:00
|
|
|
region = module.params.get('region')
|
2014-01-24 01:54:37 +00:00
|
|
|
tenant_id = module.params.get('tenant_id')
|
2014-01-27 19:33:42 +00:00
|
|
|
tenant_name = module.params.get('tenant_name')
|
2013-11-19 18:51:04 +00:00
|
|
|
username = module.params.get('username')
|
2014-01-24 01:54:37 +00:00
|
|
|
verify_ssl = module.params.get('verify_ssl')
|
|
|
|
|
2014-01-24 17:34:21 +00:00
|
|
|
if env is not None:
|
|
|
|
rax_module.set_environment(env)
|
|
|
|
|
2014-01-24 01:54:37 +00:00
|
|
|
rax_module.set_setting('identity_type', identity_type)
|
2014-01-24 17:34:21 +00:00
|
|
|
if verify_ssl is not None:
|
|
|
|
rax_module.set_setting('verify_ssl', verify_ssl)
|
|
|
|
if auth_endpoint is not None:
|
|
|
|
rax_module.set_setting('auth_endpoint', auth_endpoint)
|
|
|
|
if tenant_id is not None:
|
2014-01-24 01:54:37 +00:00
|
|
|
rax_module.set_setting('tenant_id', tenant_id)
|
2014-01-27 19:33:42 +00:00
|
|
|
if tenant_name is not None:
|
|
|
|
rax_module.set_setting('tenant_name', tenant_name)
|
2013-11-19 18:51:04 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
username = username or os.environ.get('RAX_USERNAME')
|
2014-01-24 17:34:21 +00:00
|
|
|
if not username:
|
|
|
|
username = rax_module.get_setting('keyring_username')
|
2014-01-24 17:40:34 +00:00
|
|
|
if username:
|
|
|
|
api_key = 'USE_KEYRING'
|
2014-01-24 17:34:21 +00:00
|
|
|
if not api_key:
|
|
|
|
api_key = os.environ.get('RAX_API_KEY')
|
2013-11-19 18:51:04 +00:00
|
|
|
credentials = (credentials or os.environ.get('RAX_CREDENTIALS') or
|
|
|
|
os.environ.get('RAX_CREDS_FILE'))
|
2014-01-24 17:34:21 +00:00
|
|
|
region = (region or os.environ.get('RAX_REGION') or
|
|
|
|
rax_module.get_setting('region'))
|
2013-11-19 18:51:04 +00:00
|
|
|
except KeyError, e:
|
|
|
|
module.fail_json(msg='Unable to load %s' % e.message)
|
|
|
|
|
|
|
|
try:
|
|
|
|
if api_key and username:
|
2014-01-24 01:52:32 +00:00
|
|
|
if api_key == 'USE_KEYRING':
|
2014-01-24 17:41:45 +00:00
|
|
|
rax_module.keyring_auth(username, region=region)
|
2014-01-24 01:52:32 +00:00
|
|
|
else:
|
|
|
|
rax_module.set_credentials(username, api_key=api_key,
|
|
|
|
region=region)
|
2013-11-19 18:51:04 +00:00
|
|
|
elif credentials:
|
|
|
|
credentials = os.path.expanduser(credentials)
|
|
|
|
rax_module.set_credential_file(credentials, region=region)
|
|
|
|
else:
|
|
|
|
raise Exception('No credentials supplied!')
|
|
|
|
except Exception, e:
|
|
|
|
module.fail_json(msg='%s' % e.message)
|
|
|
|
|
|
|
|
return rax_module
|