From 4600fef1018cfc969468c4020acba641fa175b6b Mon Sep 17 00:00:00 2001 From: Oleksandr Liemieshko Date: Thu, 15 Dec 2016 19:25:33 -0800 Subject: [PATCH] Add: scripts_all_pairs 'one way' mode Add config parameter scripts_all_pairs_one_way Add cli argument --one-way Change-Id: I27237f2b8534a284b05aad63d9b78ca9ff9b943a --- specs/python-timmy.spec | 5 ++++- timmy/cli.py | 7 +++++++ timmy/conf.py | 1 + timmy/env.py | 2 +- timmy/nodes.py | 8 +++++--- timmy/tools.py | 24 +++++++++++++----------- 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/specs/python-timmy.spec b/specs/python-timmy.spec index c295d17..0595566 100644 --- a/specs/python-timmy.spec +++ b/specs/python-timmy.spec @@ -4,7 +4,7 @@ %global pypi_name timmy Name: python-%{pypi_name} -Version: 1.25.5 +Version: 1.26.0 Release: 1%{?dist}~mos0 Summary: Log collector tool for OpenStack Fuel @@ -107,6 +107,9 @@ popd %changelog +* Thu Dec 15 2016 Alexander Lemeshko - 1.26.0 +- Add: scripts_all_pairs 'one way' mode + * Wed Dec 14 2016 Dmitry Sutyagin - 1.25.5 - Fix: RuntimeWarning when using analyze diff --git a/timmy/cli.py b/timmy/cli.py index d1537b7..f1e500e 100755 --- a/timmy/cli.py +++ b/timmy/cli.py @@ -86,6 +86,11 @@ def parser_init(add_help=False): ' a path specified by "rqdir" configuration' ' parameter. For help on shell mode, read' ' timmy/conf.py.') % Node.skey) + parser.add_argument('--one-way', action='store_true', + help=('When executing scripts_all_pairs (if defined),' + ' for each pair of nodes [A, B] run client' + ' script only on A (A->B connection).' + ' Default is to run both A->B and B->A.')) parser.add_argument('-P', '--put', nargs=2, action='append', metavar=('SOURCE', 'DESTINATION'), help=('Enables shell mode. Can be specified multiple' @@ -300,6 +305,8 @@ def main(argv=None): conf['analyze'] = True if args.offline: conf['offline'] = True + if args.one_way: + conf['scripts_all_pairs_one_way'] = True logger.info('Using rqdir: %s, rqfile: %s' % (conf['rqdir'], conf['rqfile'])) nm = pretty_run(args.quiet, 'Initializing node data', diff --git a/timmy/conf.py b/timmy/conf.py index efbc7fa..d68517e 100644 --- a/timmy/conf.py +++ b/timmy/conf.py @@ -74,6 +74,7 @@ def init_default_conf(): conf['clean'] = True conf['analyze'] = False conf['offline'] = False # mark all nodes as offline + conf['scripts_all_pairs_one_way'] = False return conf diff --git a/timmy/env.py b/timmy/env.py index 865ef22..911f1c7 100644 --- a/timmy/env.py +++ b/timmy/env.py @@ -16,7 +16,7 @@ # under the License. project_name = 'timmy' -version = '1.25.5' +version = '1.26.0' if __name__ == '__main__': import sys diff --git a/timmy/nodes.py b/timmy/nodes.py index 363524e..edd3388 100644 --- a/timmy/nodes.py +++ b/timmy/nodes.py @@ -902,13 +902,14 @@ class NodeManager(object): @run_with_lock def run_scripts_all_pairs(self, maxthreads, fake=False): - if len(self.selected_nodes) < 2: + nodes = self.selected_nodes.values() + if len(nodes) < 2: self.logger.warning('less than 2 nodes are available, ' 'skipping paired scripts') return run_server_start_items = [] run_server_stop_items = [] - for n in self.selected_nodes.values(): + for n in nodes: start_args = {'phase': 'server_start', 'fake': fake} run_server_start_items.append(tools.RunItem(target=n.exec_pair, args=start_args, @@ -920,7 +921,8 @@ class NodeManager(object): dict_result=True) for key in result: self.nodes[key].scripts_all_pairs = result[key] - for pairset in tools.all_pairs(self.selected_nodes.values()): + one_way = self.conf['scripts_all_pairs_one_way'] + for pairset in tools.all_pairs(nodes, one_way=one_way): run_client_items = [] self.logger.info(['%s->%s' % (p[0].ip, p[1].ip) for p in pairset]) for pair in pairset: diff --git a/timmy/tools.py b/timmy/tools.py index ff2647d..5498288 100644 --- a/timmy/tools.py +++ b/timmy/tools.py @@ -408,29 +408,31 @@ def w_list(value): return value if type(value) == list else [value] -def all_pairs(items): - def incomplete(i_set, p_dict): - for i, p_set in p_dict.items(): - not_paired = i_set.difference(p_set).difference([i]) - if not_paired: - return not_paired +def all_pairs(items, one_way=False): + def incomplete(items_set, paired_dict): + for paired_set in paired_dict.values(): + if items_set.difference(paired_set): + return True items_set = set(items) pairs = [] paired = {} for i in items_set: - paired[i] = set() + paired[i] = set([i]) while incomplete(items_set, paired): busy = set() current_pairs = [] - for i in [i for i in items if items_set.difference(paired[i])]: - can_pair = incomplete(items_set.difference(busy), {i: paired[i]}) - if i not in busy and can_pair: - pair_i = next(iter(can_pair)) + for i in items_set: + if items_set.difference(paired[i]) and i not in busy: + can_pair = items_set.difference(busy).difference(paired[i]) + if can_pair: + pair_i = can_pair.pop() current_pairs.append([i, pair_i]) busy.add(i) busy.add(pair_i) paired[i].add(pair_i) + if one_way: + paired[pair_i].add(i) pairs.append(current_pairs) return pairs