Merge pull request #5404 from sivel/rax-improvements

rax module: improvements
This commit is contained in:
jctanner 2014-01-07 07:10:31 -08:00 committed by James Tanner
parent 0fdcb8ea69
commit 4cd821e9d9

161
cloud/rax
View file

@ -26,6 +26,13 @@ options:
api_key: api_key:
description: description:
- Rackspace API key (overrides I(credentials)) - Rackspace API key (overrides I(credentials))
auto_increment:
description:
- Whether or not to increment a single number with the name of the
created servers. Only applicable when used with the I(group) attribute
or meta key.
default: yes
version_added: 1.5
count: count:
description: description:
- number of instances to launch - number of instances to launch
@ -147,6 +154,26 @@ EXAMPLES = '''
networks: networks:
- private - private
- public - public
register: rax
- name: Build an exact count of cloud servers with incremented names
hosts: local
gather_facts: False
tasks:
- name: Server build requests
local_action:
module: rax
credentials: ~/.raxpub
name: test%03d.example.org
flavor: performance1-1
image: ubuntu-1204-lts-precise-pangolin
state: present
count: 10
count_offset: 10
exact_count: yes
group: test
wait: yes
register: rax
''' '''
import sys import sys
@ -199,7 +226,7 @@ def create(module, names, flavor, image, meta, key_name, files,
lpath = os.path.expanduser(files[rpath]) lpath = os.path.expanduser(files[rpath])
try: try:
fileobj = open(lpath, 'r') fileobj = open(lpath, 'r')
files[rpath] = fileobj files[rpath] = fileobj.read()
except Exception, e: except Exception, e:
module.fail_json(msg='Failed to load %s' % lpath) module.fail_json(msg='Failed to load %s' % lpath)
try: try:
@ -347,7 +374,8 @@ def delete(module, instance_ids, wait, wait_timeout):
def cloudservers(module, state, name, flavor, image, meta, key_name, files, def cloudservers(module, state, name, flavor, image, meta, key_name, files,
wait, wait_timeout, disk_config, count, group, wait, wait_timeout, disk_config, count, group,
instance_ids, exact_count, networks, count_offset): instance_ids, exact_count, networks, count_offset,
auto_increment):
cs = pyrax.cloudservers cs = pyrax.cloudservers
cnw = pyrax.cloud_networks cnw = pyrax.cloud_networks
servers = [] servers = []
@ -358,6 +386,15 @@ def cloudservers(module, state, name, flavor, image, meta, key_name, files,
elif 'group' in meta and group is None: elif 'group' in meta and group is None:
group = meta['group'] group = meta['group']
# When using state=absent with group, the absent block won't match the
# names properly. Use the exact_count functionality to decrease the count
# to the desired level
was_absent = False
if group is not None and state == 'absent':
exact_count = True
state = 'present'
was_absent = True
# Check if the provided image is a UUID and if not, search for an # Check if the provided image is a UUID and if not, search for an
# appropriate image using human_id and name # appropriate image using human_id and name
if image: if image:
@ -416,27 +453,43 @@ def cloudservers(module, state, name, flavor, image, meta, key_name, files,
module.fail_json(msg='"group" must be provided when using ' module.fail_json(msg='"group" must be provided when using '
'"exact_count"') '"exact_count"')
else: else:
numbers = set() if auto_increment:
numbers = set()
try: try:
name % 0 name % 0
except TypeError, e: except TypeError, e:
if e.message.startswith('not all'): if e.message.startswith('not all'):
name = '%s%%d' % name name = '%s%%d' % name
else:
module.fail_json(msg=e.message)
pattern = re.sub(r'%\d+[sd]', r'(\d+)', name)
for server in cs.servers.list():
if server.metadata.get('group') == group:
servers.append(server)
match = re.search(pattern, server.name)
if match:
number = int(match.group(1))
numbers.add(number)
number_range = xrange(count_offset, count_offset + count)
available_numbers = list(set(number_range)
.difference(numbers))
else:
for server in cs.servers.list():
if server.metadata.get('group') == group:
servers.append(server)
# If state was absent but the count was changed,
# assume we only wanted to remove that number of instances
if was_absent:
diff = len(servers) - count
if diff < 0:
count = 0
else: else:
module.fail_json(msg=e.message) count = diff
pattern = re.sub(r'%\d+[sd]', r'(\d+)', name)
for server in cs.servers.list():
if server.metadata.get('group') == group:
servers.append(server)
match = re.search(pattern, server.name)
if match:
number = int(match.group(1))
numbers.add(number)
number_range = xrange(count_offset, count_offset + count)
available_numbers = list(set(number_range).difference(numbers))
if len(servers) > count: if len(servers) > count:
state = 'absent' state = 'absent'
del servers[:count] del servers[:count]
@ -445,45 +498,52 @@ def cloudservers(module, state, name, flavor, image, meta, key_name, files,
instance_ids.append(server.id) instance_ids.append(server.id)
delete(module, instance_ids, wait, wait_timeout) delete(module, instance_ids, wait, wait_timeout)
elif len(servers) < count: elif len(servers) < count:
names = [] if auto_increment:
numbers_to_use = available_numbers[:count - len(servers)] names = []
for number in numbers_to_use: name_slice = count - len(servers)
names.append(name % number) numbers_to_use = available_numbers[:name_slice]
for number in numbers_to_use:
names.append(name % number)
else:
names = [name] * (count - len(servers))
else: else:
module.exit_json(changed=False, action=None, instances=[], module.exit_json(changed=False, action=None, instances=[],
success=[], error=[], timeout=[], success=[], error=[], timeout=[],
instance_ids={'instances': [], instance_ids={'instances': [],
'success': [], 'error': [], 'success': [], 'error': [],
'timeout': []}) 'timeout': []})
else: else:
if group is not None: if group is not None:
numbers = set() if auto_increment:
numbers = set()
try: try:
name % 0 name % 0
except TypeError, e: except TypeError, e:
if e.message.startswith('not all'): if e.message.startswith('not all'):
name = '%s%%d' % name name = '%s%%d' % name
else: else:
module.fail_json(msg=e.message) module.fail_json(msg=e.message)
pattern = re.sub(r'%\d+[sd]', r'(\d+)', name) pattern = re.sub(r'%\d+[sd]', r'(\d+)', name)
for server in cs.servers.list(): for server in cs.servers.list():
if server.metadata.get('group') == group: if server.metadata.get('group') == group:
servers.append(server) servers.append(server)
match = re.search(pattern, server.name) match = re.search(pattern, server.name)
if match: if match:
number = int(match.group(1)) number = int(match.group(1))
numbers.add(number) numbers.add(number)
number_range = xrange(count_offset, number_range = xrange(count_offset,
count_offset + count + len(numbers)) count_offset + count + len(numbers))
available_numbers = list(set(number_range).difference(numbers)) available_numbers = list(set(number_range)
names = [] .difference(numbers))
numbers_to_use = available_numbers[:count] names = []
for number in numbers_to_use: numbers_to_use = available_numbers[:count]
names.append(name % number) for number in numbers_to_use:
names.append(name % number)
else:
names = [name] * count
else: else:
search_opts = { search_opts = {
'name': name, 'name': name,
@ -552,6 +612,7 @@ def main():
argument_spec = rax_argument_spec() argument_spec = rax_argument_spec()
argument_spec.update( argument_spec.update(
dict( dict(
auto_increment=dict(choices=BOOLEANS, default=True, type='bool'),
count=dict(default=1, type='int'), count=dict(default=1, type='int'),
count_offset=dict(default=1, type='int'), count_offset=dict(default=1, type='int'),
disk_config=dict(default='auto', choices=['auto', 'manual']), disk_config=dict(default='auto', choices=['auto', 'manual']),
@ -584,6 +645,7 @@ def main():
'please remove "service: cloudservers" from your ' 'please remove "service: cloudservers" from your '
'playbook pertaining to the "rax" module') 'playbook pertaining to the "rax" module')
auto_increment = module.params.get('auto_increment')
count = module.params.get('count') count = module.params.get('count')
count_offset = module.params.get('count_offset') count_offset = module.params.get('count_offset')
disk_config = module.params.get('disk_config').upper() disk_config = module.params.get('disk_config').upper()
@ -605,7 +667,8 @@ def main():
cloudservers(module, state, name, flavor, image, meta, key_name, files, cloudservers(module, state, name, flavor, image, meta, key_name, files,
wait, wait_timeout, disk_config, count, group, wait, wait_timeout, disk_config, count, group,
instance_ids, exact_count, networks, count_offset) instance_ids, exact_count, networks, count_offset,
auto_increment)
# import module snippets # import module snippets