#!/usr/bin/env python # (c) 2014, Kevin Carter # # 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 range(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()