From d0b9fe2bbfc8fb8b03a5608758623f9c9e376916 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Tue, 17 Jul 2018 17:38:39 +0200 Subject: [PATCH] Remove cluster-monitor, it's in odltools now https://git.opendaylight.org/gerrit/odltools Change-Id: I0dbacea08c0685fcdb5f44f210753bc4b59f60b5 Signed-off-by: Stephen Kitt --- .../cluster-monitor/README.markdown | 71 ------ tools/clustering/cluster-monitor/cluster.json | 12 - tools/clustering/cluster-monitor/isolate.py | 72 ------ tools/clustering/cluster-monitor/monitor.py | 220 ------------------ tools/clustering/cluster-monitor/rejoin.py | 62 ----- .../cluster-monitor/requirements.txt | 2 - .../cluster-monitor/timed_isolation.py | 80 ------- 7 files changed, 519 deletions(-) delete mode 100644 tools/clustering/cluster-monitor/README.markdown delete mode 100644 tools/clustering/cluster-monitor/cluster.json delete mode 100755 tools/clustering/cluster-monitor/isolate.py delete mode 100755 tools/clustering/cluster-monitor/monitor.py delete mode 100755 tools/clustering/cluster-monitor/rejoin.py delete mode 100644 tools/clustering/cluster-monitor/requirements.txt delete mode 100755 tools/clustering/cluster-monitor/timed_isolation.py diff --git a/tools/clustering/cluster-monitor/README.markdown b/tools/clustering/cluster-monitor/README.markdown deleted file mode 100644 index 113db9382e..0000000000 --- a/tools/clustering/cluster-monitor/README.markdown +++ /dev/null @@ -1,71 +0,0 @@ -# Cluster Monitor Tool - -This tool provides real-time visualization of the cluster member roles for all -shards in the config datastore. It is useful for understanding cluster behavior -in when controllers are isolated, downed, or rebooted. - -A file named `cluster.json` containing a list of the IP addresses of the -controllers is required. This resides in the same directory as `monitor.py`. -"user" and "pass" are not required for `monitor.py`, but they may be -needed for other apps in this folder. Because this configuration -information unique to your environment, it may be more convenient to -copy the contents of this folder out of git to prevent these settings -from being overwritten by updates. - - -The file should look like this: - -``` - { - "cluster": { - "controllers": [ - "172.17.10.93", - "172.17.10.94", - "172.17.10.95" - ], - "user": "username", - "pass": "password" - } - } -``` - -## Usage: `monitor.py` - -### Starting `monitor.py` - -Before using, start and configure all controllers in the cluster. Use of the -cluster deployment script is recommended. All controllers must initially be -running so the tool can retrieve the controller and shard names. Once -the tool is started and the controller and cluster shard names are retrieved, -controllers can be isolated, downed, rebooted, etc. - -### The `monitor.py` UI - -Controller member names (not host names) are displayed across the top. Shard -names are displayed to the left. - -In the upper left is a heart emoticon "<3" which toggles between yellow and -black backgrounds with each update. If a controller is down, the HTTP timeout -comes in to play and updating becomes much slower. - -The central matrix displays controller roles. When REST queries fail, the -error type is displayed. Leader, Follower, and Candidate roles are color- -coded. - -## Other Scripts - -### `isolate.py` - -Isolates an indicated controller from the cluster. - -### `rejoin.py` - -Rejoins any isolated controllers to the cluster. - -### `timed_isolation.py` - -Isolates an indicated controller for a specified duration - -## Future Enhancements - -Add operational shards. diff --git a/tools/clustering/cluster-monitor/cluster.json b/tools/clustering/cluster-monitor/cluster.json deleted file mode 100644 index 138c9d21d8..0000000000 --- a/tools/clustering/cluster-monitor/cluster.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "cluster": { - "controllers": [ - {"ip": "172.17.10.93", "port": "8181"}, - {"ip": "172.17.10.93", "port": "8181"}, - {"ip": "172.17.10.93", "port": "8181"} - ], - "user": "username", - "pass": "password", - "shards_to_exclude": [] - } -} diff --git a/tools/clustering/cluster-monitor/isolate.py b/tools/clustering/cluster-monitor/isolate.py deleted file mode 100755 index 1dd80ef6b7..0000000000 --- a/tools/clustering/cluster-monitor/isolate.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/python -""" -Controller Isolation Tool -Author: Phillip Shea -Updated: 2015-May-07 - -This tool isolates an indicated controller from the cluster. The tool takes -a single integer argument corresponding to the number of a controller -in a json file's ordered list of controllers. This is the controller to -be isolated. - -A file named 'cluster.json' containing a list of the IP addresses, ports and -credentials of the controllers is required. It resides in the same -directory as monitor.py. - -The file should look like this: - - { - "cluster": { - "controllers": [ - {"ip": "172.17.10.93", "port": "8181"}, - {"ip": "172.17.10.93", "port": "8181"}, - {"ip": "172.17.10.93", "port": "8181"} - ], - "user": "username", - "pass": "password", - } - } - -Usage:python isolate.py [controller to be isolated] -""" - -import sys - - -def import_utility_modules(): - global UtilLibrary, json - import sys - sys.path.append('../../../csit/libraries') - import UtilLibrary - import json - - -import_utility_modules() - -try: - with open('cluster.json') as cluster_file: - data = json.load(cluster_file) -except: - print str(sys.exc_info()) - print "unable to open the file cluster.json" - exit(1) -try: - cluster_list = data["cluster"]["controllers"] - cluster_ips = [] - for controller in cluster_list: - cluster_ips.append(controller["ip"]) - user_name = data["cluster"]["user"] - user_pass = data["cluster"]["pass"] -except: - print str(sys.exc_info()) - print 'Error reading the file cluster.json' - exit(1) -try: - isolate = int(sys.argv[1]) -except: - print 'You must specify the number (e.g. 1, 2, 3) of the controller to isolate.' - exit(1) - -print "isolating controller " + str(isolate) - -print UtilLibrary.isolate_controller(cluster_ips, user_name, user_pass, isolate) diff --git a/tools/clustering/cluster-monitor/monitor.py b/tools/clustering/cluster-monitor/monitor.py deleted file mode 100755 index 0a40e8ee8f..0000000000 --- a/tools/clustering/cluster-monitor/monitor.py +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/python -""" -Cluster Monitor Tool -Author: Phillip Shea -Updated: 2016-Mar-07 - -This tool provides real-time visualization of the cluster member roles for all -shards in either the config or operational datastore. - -A file named 'cluster.json' contaning a list of the IP addresses and port numbers -of the controllers is required. This resides in the same directory as monitor.py. -"user" and "pass" are not required for monitor.py, but they may be -needed for other apps in this folder. The file should look like this: - - { - "cluster": { - "controllers": [ - {"ip": "172.17.10.93", "port": "8181"}, - {"ip": "172.17.10.93", "port": "8181"}, - {"ip": "172.17.10.93", "port": "8181"} - ], - "user": "username", - "pass": "password", - "shards_to_exclude": [] # list of shard names to omit from output - } - } - -Usage:python monitor.py [-d data_store_name] -""" -from io import BytesIO -import time -import pprint -import curses -import sys -import json -import pycurl -import string -import argparse -import math - - -def rest_get(restURL, username, password): - rest_buffer = BytesIO() - c = pycurl.Curl() - c.setopt(c.TIMEOUT, 2) - c.setopt(c.CONNECTTIMEOUT, 1) - c.setopt(c.FAILONERROR, False) - c.setopt(c.URL, str(restURL)) - c.setopt(c.HTTPGET, 0) - c.setopt(c.WRITEFUNCTION, rest_buffer.write) - c.setopt(pycurl.USERPWD, "%s:%s" % (str(username), str(password))) - c.perform() - c.close() - return json.loads(rest_buffer.getvalue()) - - -def getClusterRolesWithCurl(shardName, controllers): - controller_state = {} - for i, controller in enumerate(controllers): - controller_state[controller["ip"]] = None - url = "http://" + controller["ip"] + ":" + controller["port"]\ - + "/jolokia/read/org.opendaylight.controller:" - url += 'Category=Shards,name=' + controller['name'] - url += '-shard-' + shardName + '-' + data_store.lower() + ',type=Distributed' + data_store + 'Datastore' - try: - resp = rest_get(url, username, password) - if resp['status'] != 200: - controller_state[controller["ip"]] = 'HTTP ' + str(resp['status']) - if 'value' in resp: - data_value = resp['value'] - controller_state[controller["ip"]] = data_value['RaftState'] - except: - if 'timed out' in str(sys.exc_info()[1]): - controller_state[controller["ip"]] = 'timeout' - elif 'JSON' in str(sys.exc_info()): - controller_state[controller["ip"]] = 'JSON error' - elif 'connect to host' in str(sys.exc_info()): - controller_state[controller["ip"]] = 'no connection' - else: - controller_state[controller["ip"]] = 'down' - return controller_state - - -def size_and_color(cluster_roles, field_length, ip_addr): - status_dict = {} - status_dict['txt'] = string.center(str(cluster_roles[ip_addr]), field_length) - if cluster_roles[ip_addr] == "Leader": - status_dict['color'] = curses.color_pair(2) - elif cluster_roles[ip_addr] == "Follower": - status_dict['color'] = curses.color_pair(3) - elif cluster_roles[ip_addr] == "Candidate": - status_dict['color'] = curses.color_pair(5) - else: - status_dict['color'] = curses.color_pair(0) - return status_dict - - -parser = argparse.ArgumentParser() -parser.add_argument('-d', '--datastore', default='Config', type=str, - help='polling can be done on "Config" or "Operational" data stores') -args = parser.parse_args() -data_store = args.datastore -if data_store != 'Config' and data_store != 'Operational': - print 'Only "Config" or "Operational" data store is available for polling' - exit(1) - -try: - with open('cluster.json') as cluster_file: - data = json.load(cluster_file) -except: - print str(sys.exc_info()) - print 'Unable to open the file cluster.json' - exit(1) -try: - controllers = data["cluster"]["controllers"] - shards_to_exclude = data["cluster"]["shards_to_exclude"] - username = data["cluster"]["user"] - password = data["cluster"]["pass"] -except: - print str(sys.exc_info()) - print 'Error reading the file cluster.json' - exit(1) - -Shards = set() - -stdscr = curses.initscr() -curses.noecho() -curses.cbreak() -curses.curs_set(0) -stdscr.keypad(1) -stdscr.nodelay(1) - -curses.start_color() -curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK) -curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_GREEN) -curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_BLUE) -curses.init_pair(4, curses.COLOR_WHITE, curses.COLOR_YELLOW) -curses.init_pair(5, curses.COLOR_BLACK, curses.COLOR_YELLOW) - -(maxy, maxx) = stdscr.getmaxyx() - -key = -1 -controller_len = 0 -field_len = 0 -while key != ord('q') and key != ord('Q'): - key = max(key, stdscr.getch()) - - # Retrieve controller names and shard names. - for controller in controllers: - key = max(key, stdscr.getch()) - if key == ord('q') or key == ord('Q'): - break - - url = "http://" + controller["ip"] + ":" + controller["port"]\ - + "/jolokia/read/org.opendaylight.controller:" - url += "Category=ShardManager,name=shard-manager-" + data_store.lower()\ - + ",type=Distributed" + data_store + "Datastore" - try: - data = rest_get(url, username, password) - # grab the controller name from the first shard - name = data['value']['LocalShards'][0] - pos = name.find('-shard-') - controller['name'] = name[:name.find('-shard-')] - # collect shards found in any controller; does not require all controllers to have the same shards - for localShard in data['value']['LocalShards']: - shardName = localShard[(localShard.find("-shard-") + 7):localShard.rfind("-" + data_store.lower())] - if shardName not in shards_to_exclude: - Shards.add(shardName) - except: - if 'name' not in controller: - controller['name'] = controller['ip'] + ':' + controller['port'] - controller_len = max(controller_len, len(controller['name'])) - - if Shards: - field_len = max(map(len, Shards)) + 2 - else: - field_len = max(field_len, 0) - - # Ensure everything fits - if controller_len + 1 + (field_len + 1) * len(Shards) > maxx: - extra = controller_len + 1 + (field_len + 1) * len(Shards) - maxx - delta = int(math.ceil(float(extra) / (1 + len(Shards)))) - controller_len -= delta - field_len -= delta - - # display controller and shard headers - for row, controller in enumerate(controllers): - stdscr.addstr(row + 1, 0, string.center(controller['name'], controller_len), curses.color_pair(1)) - for data_column, shard in enumerate(Shards): - stdscr.addstr(0, controller_len + 1 + (field_len + 1) * data_column, string.center(shard, field_len), - curses.color_pair(1)) - stdscr.addstr(len(Shards) + 2, 0, 'Press q to quit.', curses.color_pair(1)) - stdscr.refresh() - - # display shard status - odd_or_even = 0 - for data_column, shard_name in enumerate(Shards): - key = max(key, stdscr.getch()) - if key == ord('q') or key == ord('Q'): - break - - odd_or_even += 1 - if shard_name not in shards_to_exclude: - cluster_stat = getClusterRolesWithCurl(shard_name, controllers) - for row, controller in enumerate(controllers): - status = size_and_color(cluster_stat, field_len, controller["ip"]) - stdscr.addstr(row + 1, controller_len + 1 + (field_len + 1) * data_column, status['txt'], - status['color']) - time.sleep(0.5) - if odd_or_even % 2 == 0: - stdscr.addstr(0, controller_len / 2 - 2, " <3 ", curses.color_pair(5)) - else: - stdscr.addstr(0, controller_len / 2 - 2, " <3 ", curses.color_pair(0)) - stdscr.refresh() - -# clean up -curses.nocbreak() -stdscr.keypad(0) -curses.echo() -curses.endwin() diff --git a/tools/clustering/cluster-monitor/rejoin.py b/tools/clustering/cluster-monitor/rejoin.py deleted file mode 100755 index c9735db4f2..0000000000 --- a/tools/clustering/cluster-monitor/rejoin.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/python -""" -Cluster Rejoin Tool -Author: Phillip Shea -Updated: 2015-May-07 - -This tool rejoins any isolated controllers to the cluster. - -A file named 'cluster.json' containing a list of the IP addresses and -credentials of the controllers is required. It resides in the same -directory as monitor.py. - -The file should look like this: - - { - "cluster": { - "controllers": [ - {"ip": "172.17.10.93", "port": "8181"}, - {"ip": "172.17.10.93", "port": "8181"}, - {"ip": "172.17.10.93", "port": "8181"} - ], - "user": "username", - "pass": "password", - } - } - -Usage:python rejoin.py - """ - -import sys - - -def import_utility_modules(): - global UtilLibrary, json - import sys - sys.path.append('../../../csit/libraries') - import UtilLibrary - import json - - -import_utility_modules() - -try: - with open('cluster.json') as cluster_file: - data = json.load(cluster_file) -except: - print str(sys.exc_info()) - print "unable to open the file cluster.json" - exit(1) -try: - cluster_list = data["cluster"]["controllers"] - cluster_ips = [] - for controller in cluster_list: - cluster_ips.append(controller["ip"]) - user_name = data["cluster"]["user"] - user_pass = data["cluster"]["pass"] -except: - print str(sys.exc_info()) - print 'Error reading the file cluster.json' - exit(1) - -print UtilLibrary.flush_iptables(cluster_ips, user_name, user_pass) diff --git a/tools/clustering/cluster-monitor/requirements.txt b/tools/clustering/cluster-monitor/requirements.txt deleted file mode 100644 index 98ba7e54d0..0000000000 --- a/tools/clustering/cluster-monitor/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -# Depends on system install of libcurl-devel and python-devel (or similar) -pycurl --global-option="--with-nss" diff --git a/tools/clustering/cluster-monitor/timed_isolation.py b/tools/clustering/cluster-monitor/timed_isolation.py deleted file mode 100755 index 06b5d12787..0000000000 --- a/tools/clustering/cluster-monitor/timed_isolation.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/python -""" -Controller Isolation Tool -Author: Phillip Shea -Updated: 2015-May-07 - -This tool isolates an indicated controller for a specified duration. -The tool's first integer argument corresponds to the number of a controller -in a json file's ordered list of controllers. This is the controller to -be isolated. The second argument is the duration of isolation in -seconds. - -A file named 'cluster.json' containing a list of the IP addresses and -credentials of the controllers is required. It resides in the same -directory as monitor.py. - -The file should look like this: - - { - "cluster": { - "controllers": [ - {"ip": "172.17.10.93", "port": "8181"}, - {"ip": "172.17.10.93", "port": "8181"}, - {"ip": "172.17.10.93", "port": "8181"} - ], - "user": "username", - "pass": "password", - } - } - -Usage:python timed_isolation.py [controller to be isolated] [duration of isolation in seconds] -""" - -import sys -import time - - -def import_utility_modules(): - global UtilLibrary, json - import sys - sys.path.append('../../../csit/libraries') - import UtilLibrary - import json - - -import_utility_modules() - -try: - with open('cluster.json') as cluster_file: - data = json.load(cluster_file) -except: - print str(sys.exc_info()) - print 'unable to open the file cluster.json' - exit(1) -try: - cluster_list = data["cluster"]["controllers"] - cluster_ips = [] - for controller in cluster_list: - cluster_ips.append(controller["ip"]) - user_name = data["cluster"]["user"] - user_pass = data["cluster"]["pass"] -except: - print str(sys.exc_info()) - print 'Error reading the file cluster.json' - exit(1) -try: - isolate = int(sys.argv[1]) - duration = int(sys.argv[2]) -except: - print 'You must specify the number (e.g. 1, 2, 3) of the controller to isolate.' - exit(1) - -print 'Isolating controller ' + str(isolate) - -print UtilLibrary.isolate_controller(cluster_ips, user_name, user_pass, isolate) - -print 'Pausing for ' + str(duration) + ' seconds...' -time.sleep(duration) - -print UtilLibrary.flush_iptables(cluster_ips, user_name, user_pass) -- 2.36.6