Add: function analyze
Add argument -a --analyze Add conf parameter 'analyze' Add analizys for scripts: 'df-m', 'df-i' Change-Id: I0697777da6be773103b337c001df8aaeb4290db1 (cherry picked from commit abdb347e6b9c5a23a43421228aeb77edc997f0b9)
This commit is contained in:
parent
41d9d89207
commit
78a462dacd
@ -4,7 +4,7 @@
|
||||
%global pypi_name timmy
|
||||
|
||||
Name: python-%{pypi_name}
|
||||
Version: 1.23.7
|
||||
Version: 1.24.0
|
||||
Release: 1%{?dist}~mos0
|
||||
Summary: Log collector tool for OpenStack Fuel
|
||||
|
||||
|
123
timmy/analyze.py
Normal file
123
timmy/analyze.py
Normal file
@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2016 Mirantis, 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.
|
||||
|
||||
from timmy.env import project_name
|
||||
import logging
|
||||
import sys
|
||||
|
||||
|
||||
logger = logging.getLogger(project_name)
|
||||
|
||||
|
||||
def analyze(node_manager):
|
||||
col_msg = 'Column "%s" not found in output of "%s" from node "%s"'
|
||||
green = 0
|
||||
unknown = 1
|
||||
yellow = 2
|
||||
red = 3
|
||||
|
||||
def parse_df_m(data, script, node):
|
||||
column_use = "Use%"
|
||||
full = 100
|
||||
near_full = 80
|
||||
health = green
|
||||
details = []
|
||||
if column_use not in data[0]:
|
||||
logger.warning(col_msg % (column_use, script, node.repr))
|
||||
health = unknown
|
||||
index = data[0].split().index(column_use)
|
||||
for line in data[2:]:
|
||||
value = int(line.split()[index][:-1])
|
||||
if value >= full:
|
||||
health = red
|
||||
details.append(line)
|
||||
elif value >= near_full:
|
||||
health = yellow if health < yellow else health
|
||||
details.append(line)
|
||||
return health, details
|
||||
|
||||
def parse_df_i(data, script, node):
|
||||
column_use = "IUse%"
|
||||
full = 100
|
||||
near_full = 80
|
||||
health = green
|
||||
details = []
|
||||
if column_use not in data[0]:
|
||||
logger.warning(col_msg % (column_use, script, node.repr))
|
||||
health = unknown
|
||||
index = data[0].split().index(column_use)
|
||||
for line in data[2:]:
|
||||
if "%" in line.split()[index]:
|
||||
value = int(line.split()[index][:-1])
|
||||
if value >= full:
|
||||
health = red
|
||||
details.append(line)
|
||||
elif value >= near_full:
|
||||
health = yellow if health < yellow else health
|
||||
details.append(line)
|
||||
return health, details
|
||||
|
||||
fn_mapping = {"df-m": parse_df_m,
|
||||
"df-i": parse_df_i}
|
||||
results = {}
|
||||
for node in node_manager.nodes.values():
|
||||
for script, output_file in node.mapscr.items():
|
||||
if script in fn_mapping:
|
||||
with open(output_file, "r") as f:
|
||||
data = [l.rstrip() for l in f.readlines()]
|
||||
health, details = fn_mapping[script](data, script, node)
|
||||
if node.repr not in results:
|
||||
results[node.repr] = []
|
||||
results[node.repr].append({"script": script,
|
||||
"output_file": output_file,
|
||||
"health": health,
|
||||
"details": details})
|
||||
node_manager.analyze_results = results
|
||||
|
||||
|
||||
def analyze_print_results(node_manager):
|
||||
code_colors = {3: ["RED", "\033[91m"],
|
||||
2: ["YELLOW", "\033[93m"],
|
||||
0: ["GREEN", "\033[92m"],
|
||||
1: ["BLUE", "\033[94m"]}
|
||||
color_end = "\033[0m"
|
||||
print("Nodes health analysis:")
|
||||
for node, result in node_manager.analyze_results.items():
|
||||
node_health = max([x["health"] for x in result])
|
||||
node_color = code_colors[node_health][1]
|
||||
health_repr = code_colors[node_health][0]
|
||||
print(" %s%s: %s%s" % (node_color, node, health_repr, color_end))
|
||||
if node_health == 0:
|
||||
continue
|
||||
for r in result:
|
||||
if r['health'] == 0:
|
||||
continue
|
||||
color = code_colors[r["health"]][1]
|
||||
sys.stdout.write(color)
|
||||
for key, value in r.items():
|
||||
if key == "health":
|
||||
value = code_colors[value][0]
|
||||
if key == "details" and len(value) > 0:
|
||||
if len(value) > 1:
|
||||
print(" details:")
|
||||
for d in value:
|
||||
print(" - %s" % d)
|
||||
else:
|
||||
print(" details: %s" % value[0])
|
||||
elif key != "details":
|
||||
print(" %s: %s" % (key, value))
|
||||
sys.stdout.write(color_end)
|
11
timmy/cli.py
11
timmy/cli.py
@ -15,6 +15,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from timmy.analyze import analyze, analyze_print_results
|
||||
from timmy.env import project_name, version
|
||||
from timmy.nodes import Node
|
||||
from timmy.tools import signal_wrapper
|
||||
@ -171,6 +172,9 @@ def parser_init(add_help=False):
|
||||
parser.add_argument('-m', '--module', metavar='INVENTORY MODULE',
|
||||
default='fuel',
|
||||
help='Use module to get node data')
|
||||
parser.add_argument('-a', '--analyze', action='store_true',
|
||||
help=('Analyze collected outputs to determine node or'
|
||||
'service health and print results'))
|
||||
parser.add_argument('-v', '--verbose', action='count', default=0,
|
||||
help=('This works for -vvvv, -vvv, -vv, -v, -v -v,'
|
||||
'etc, If no -v then logging.WARNING is '
|
||||
@ -286,6 +290,8 @@ def main(argv=None):
|
||||
# this is mainly to see the path in logs instad of ""
|
||||
conf['archive_dir'] = os.getcwd()
|
||||
conf['archive_name'] = os.path.split(args.dest_file)[1]
|
||||
if args.analyze:
|
||||
conf['analyze'] = True
|
||||
logger.info('Using rqdir: %s, rqfile: %s' %
|
||||
(conf['rqdir'], conf['rqfile']))
|
||||
nm = pretty_run(args.quiet, 'Initializing node data',
|
||||
@ -315,6 +321,9 @@ def main(argv=None):
|
||||
if nm.has(Node.ckey, Node.skey):
|
||||
pretty_run(args.quiet, 'Executing commands and scripts',
|
||||
nm.run_commands, args=(args.maxthreads,))
|
||||
if conf['analyze']:
|
||||
pretty_run(args.quiet, 'Analyzing outputs', analyze,
|
||||
args=[nm])
|
||||
if nm.has('scripts_all_pairs'):
|
||||
pretty_run(args.quiet, 'Executing paired scripts',
|
||||
nm.run_scripts_all_pairs, args=(args.maxthreads,))
|
||||
@ -350,6 +359,8 @@ def main(argv=None):
|
||||
for line in output_dict[node.ip]['output']:
|
||||
name = output_dict[node.ip]['name'].rjust(maxlength)
|
||||
print("%s: %s" % (name, line))
|
||||
if conf['analyze']:
|
||||
analyze_print_results(nm)
|
||||
if nm.has(Node.ckey, Node.skey, Node.fkey, Node.flkey) and not args.quiet:
|
||||
print('Outputs and/or files available in "%s".' % nm.conf['outdir'])
|
||||
if all([not args.no_archive, nm.has(*Node.conf_archive_general),
|
||||
|
@ -72,6 +72,7 @@ def init_default_conf():
|
||||
conf['do_print_results'] = False
|
||||
'''Clean - erase previous results in outdir and archive_dir dir, if any.'''
|
||||
conf['clean'] = True
|
||||
conf['analyze'] = False
|
||||
return conf
|
||||
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
# under the License.
|
||||
|
||||
project_name = 'timmy'
|
||||
version = '1.23.7'
|
||||
version = '1.24.0'
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
Loading…
x
Reference in New Issue
Block a user