Kevin Carter c7b7169c79
Update dist-sort module for better effectiveness
The dist-sort module has been updated to ensure its execution
is effective, fast, and nonintrusive. There are cases where
the rounds made by the module take an excessive amount of time
to complete. This change ensures that the module is limiting its
rounds to a known index and the iterable is processed using a
generator.

Change-Id: I03d1f70cb6cd17f38ef37b4d8371a8982beca29e
Signed-off-by: Kevin Carter <kevin.carter@rackspace.com>
2016-07-20 08:43:01 -05:00

174 lines
5.1 KiB
Python

#!/usr/bin/env python
# (c) 2014, Kevin Carter <kevin.carter@rackspace.com>
#
# Copyright 2014, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# import module snippets
from ansible.module_utils.basic import *
DOCUMENTATION = """
---
module: dist_sort
version_added: "1.6.6"
short_description:
- Deterministically sort a list to distribute the elements in the list
evenly. Based on external values such as host or static modifier. Returns
a string as named key ``sorted_list``.
description:
- This module returns a list of servers uniquely sorted based on a index
from a look up value location within a group. The group should be an
existing ansible inventory group. This will module returns the sorted
list as a delimited string.
options:
src_list:
description:
- list in the form of a string separated by a delimiter.
required: True
ref_list:
description:
- list to lookup value_to_lookup against to return index number
This should be a pre-determined ansible group containing the
``value_to_lookup``.
required: False
value_to_lookup:
description:
- value is looked up against ref_list to get index number.
required: False
sort_modifier:
description:
- add a static int into the sort equation to weight the output.
type: int
default: 0
delimiter:
description:
- delimiter used to parse ``src_list`` with.
default: ','
author:
- Kevin Carter
- Sam Yaple
"""
EXAMPLES = """
- dist_sort:
value_to_lookup: "Hostname-in-ansible-group_name"
ref_list: "{{ groups['group_name'] }}"
src_list: "Server1,Server2,Server3"
register: test_var
# With a pre-set delimiter
- dist_sort:
value_to_lookup: "Hostname-in-ansible-group_name"
ref_list: "{{ groups['group_name'] }}"
src_list: "Server1|Server2|Server3"
delimiter: '|'
register: test_var
# With a set modifier
- dist_sort:
value_to_lookup: "Hostname-in-ansible-group_name"
ref_list: "{{ groups['group_name'] }}"
src_list: "Server1#Server2#Server3"
delimiter: '#'
sort_modifier: 5
register: test_var
"""
class DistSort(object):
def __init__(self, module):
"""Deterministically sort a list of servers.
:param module: The active ansible module.
:type module: ``class``
"""
self.module = module
self.params = self.module.params
self.return_data = self._runner()
def _runner(self):
"""Return the sorted list of servers.
Based on the modulo of index of a *value_to_lookup* from an ansible
group this function will return a comma "delimiter" separated list of
items.
:returns: ``str``
"""
try:
index = self.params['ref_list'].index(
self.params['value_to_lookup']
)
except ValueError:
index = 0
src_list = self.params['src_list'].split(self.params['delimiter'])
index += self.params['sort_modifier']
for _ in xrange(index % len(src_list)):
src_list.append(src_list.pop(0))
return self.params['delimiter'].join(src_list)
def main():
"""Run the main app."""
module = AnsibleModule(
argument_spec=dict(
value_to_lookup=dict(
required=True,
type='str'
),
ref_list=dict(
required=True,
type='list'
),
src_list=dict(
required=True,
type='str'
),
delimiter=dict(
required=False,
type='str',
default=','
),
sort_modifier=dict(
required=False,
type='str',
default='0'
)
),
supports_check_mode=False
)
try:
# This is done so that the failure can be parsed and does not cause
# ansible to fail if a non-int is passed.
module.params['sort_modifier'] = int(module.params['sort_modifier'])
_ds = DistSort(module=module)
if _ds.return_data == module.params['src_list']:
_changed = False
else:
_changed = True
except Exception as exp:
resp = {'stderr': str(exp)}
resp.update(module.params)
module.fail_json(msg='Failed Process', **resp)
else:
module.exit_json(changed=_changed, **{'sorted_list': _ds.return_data})
if __name__ == '__main__':
main()