Add: rabbitmq analysis module
rabbitmqctl list_queues: - non-empty queues (100 - yellow, 1000 - red) rabbitmqctl status: - disk_free vs disk_free_limit - file_descriptors (sockets & total) Change-Id: I0697683f31fb8b235aadf845d531053875f2ff48
This commit is contained in:
parent
dd688c9d96
commit
3d535488ba
@ -4,7 +4,7 @@
|
|||||||
%global pypi_name timmy
|
%global pypi_name timmy
|
||||||
|
|
||||||
Name: python-%{pypi_name}
|
Name: python-%{pypi_name}
|
||||||
Version: 1.26.0
|
Version: 1.26.2
|
||||||
Release: 1%{?dist}~mos0
|
Release: 1%{?dist}~mos0
|
||||||
Summary: Log collector tool for OpenStack Fuel
|
Summary: Log collector tool for OpenStack Fuel
|
||||||
|
|
||||||
@ -107,6 +107,9 @@ popd
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Dec 20 2016 Dmitry Sutyagin <dsutyagin@mirantis.com> - 1.26.2
|
||||||
|
- Add: rabbitmq analysis module
|
||||||
|
|
||||||
* Tue Dec 20 2016 Aleksandr Dobdin <adobdin@mirantis.com> - 1.26.1
|
* Tue Dec 20 2016 Aleksandr Dobdin <adobdin@mirantis.com> - 1.26.1
|
||||||
- Fix: download network templates for 9.1
|
- Fix: download network templates for 9.1
|
||||||
|
|
||||||
|
195
timmy/analyze_modules/rabbitmq.py
Normal file
195
timmy/analyze_modules/rabbitmq.py
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
#!/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.analyze_health import GREEN, UNKNOWN, YELLOW, RED
|
||||||
|
from timmy.env import project_name
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(project_name)
|
||||||
|
|
||||||
|
|
||||||
|
def register(function_mapping):
|
||||||
|
function_mapping['rabbitmqctl-list-queues'] = parse_list_queues
|
||||||
|
function_mapping['rabbitmqctl-status'] = parse_status
|
||||||
|
|
||||||
|
|
||||||
|
def parse_list_queues(data, script, node):
|
||||||
|
warning = 100
|
||||||
|
error = 1000
|
||||||
|
health = GREEN
|
||||||
|
details = []
|
||||||
|
for line in data[1:]:
|
||||||
|
elements = line.rstrip().split()
|
||||||
|
if len(elements) < 2:
|
||||||
|
logger.warning('no value in list_queues: "%s"' % line.rstrip())
|
||||||
|
else:
|
||||||
|
count = int(elements[1])
|
||||||
|
if count < error and count >= warning:
|
||||||
|
health = max(health, YELLOW)
|
||||||
|
details.append(line)
|
||||||
|
return health, details
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_status(data):
|
||||||
|
bad_yaml = ''.join(data[1:])
|
||||||
|
# quoting string elements
|
||||||
|
bad_yaml = re.sub(r'([,{])([a-z_A-Z]+)([,}])', r'\1"\2"\3', bad_yaml)
|
||||||
|
# changing first element int a key - replacing , with :
|
||||||
|
bad_yaml = re.sub(r'({[^,]+),', r'\1:', bad_yaml)
|
||||||
|
bad_yaml_list = list(bad_yaml)
|
||||||
|
good_yaml, _ = fix_dicts(bad_yaml_list, 0)
|
||||||
|
status_list = yaml.load(''.join(good_yaml))
|
||||||
|
status_dict = squash_dicts(status_list)
|
||||||
|
return status_dict
|
||||||
|
|
||||||
|
|
||||||
|
def fix_dicts(json_str_list, pos):
|
||||||
|
'''recursively puts all comma-separted values into square
|
||||||
|
brackets to make data look like normal 'key: value' dicts
|
||||||
|
'''
|
||||||
|
quoted_string = False
|
||||||
|
value = True
|
||||||
|
value_pos = 0
|
||||||
|
commas = False
|
||||||
|
is_list = False
|
||||||
|
in_list = 0
|
||||||
|
while pos < len(json_str_list):
|
||||||
|
if not quoted_string:
|
||||||
|
if json_str_list[pos] == '{':
|
||||||
|
json_str_list, pos = fix_dicts(json_str_list, pos+1)
|
||||||
|
elif json_str_list[pos] == '"':
|
||||||
|
quoted_string = True
|
||||||
|
elif json_str_list[pos] == ':':
|
||||||
|
value = True
|
||||||
|
value_pos = pos + 1
|
||||||
|
elif json_str_list[pos] == '[':
|
||||||
|
if value and not commas:
|
||||||
|
is_list = True
|
||||||
|
in_list += 1
|
||||||
|
elif json_str_list[pos] == ']':
|
||||||
|
in_list -= 1
|
||||||
|
elif json_str_list[pos] == ',':
|
||||||
|
commas = True
|
||||||
|
if not in_list:
|
||||||
|
is_list = False
|
||||||
|
elif json_str_list[pos] == '}':
|
||||||
|
if not is_list and commas:
|
||||||
|
json_str_list = (json_str_list[:value_pos] + ['['] +
|
||||||
|
json_str_list[value_pos:pos] + [']'] +
|
||||||
|
json_str_list[pos:])
|
||||||
|
pos += 2
|
||||||
|
return json_str_list, pos
|
||||||
|
elif json_str_list[pos] == '"':
|
||||||
|
quoted_string = False
|
||||||
|
pos += 1
|
||||||
|
return json_str_list, pos
|
||||||
|
|
||||||
|
|
||||||
|
def squash_dicts(input_data):
|
||||||
|
# recursively converts [{a:1},{b:2},{c:3}...] into {a:1, b:2, c:3}'''
|
||||||
|
if type(input_data) is list:
|
||||||
|
for i in range(len(input_data)):
|
||||||
|
input_data[i] = squash_dicts(input_data[i])
|
||||||
|
if all([type(i) is dict for i in input_data]):
|
||||||
|
kv_list = [(k, v) for i in input_data for k, v in i.items()]
|
||||||
|
input_data = dict(kv_list)
|
||||||
|
elif type(input_data) is dict:
|
||||||
|
for k, v in input_data.items():
|
||||||
|
input_data[k] = squash_dicts(v)
|
||||||
|
return input_data
|
||||||
|
|
||||||
|
|
||||||
|
def parse_status(data, script, node):
|
||||||
|
status = prepare_status(data)
|
||||||
|
health = GREEN
|
||||||
|
details = []
|
||||||
|
|
||||||
|
# disk free check
|
||||||
|
try:
|
||||||
|
dfree = int(status['disk_free'])
|
||||||
|
dlimit = int(status['disk_free_limit'])
|
||||||
|
dfree_ok = 10**9 # 1GB
|
||||||
|
if dfree > dlimit and dfree < dfree_ok:
|
||||||
|
health = max(health, YELLOW)
|
||||||
|
details.append('disk_free: %s, disk_free_limit: %s'
|
||||||
|
% (dfree, dlimit))
|
||||||
|
elif dfree <= dlimit:
|
||||||
|
health = max(health, RED)
|
||||||
|
details.append('disk_free: %s, disk_free_limit: %s'
|
||||||
|
% (dfree, dlimit))
|
||||||
|
except ValueError:
|
||||||
|
details.append('cannot convert disk_free* to int')
|
||||||
|
health = max(health, UNKNOWN)
|
||||||
|
except KeyError:
|
||||||
|
details.append('disk_free* not present')
|
||||||
|
health = max(health, UNKNOWN)
|
||||||
|
|
||||||
|
# process limit check
|
||||||
|
try:
|
||||||
|
pused = float(status['processes']['used'])
|
||||||
|
plimit = float(status['processes']['limit'])
|
||||||
|
ok_ratio = 0.9
|
||||||
|
if pused < plimit and pused/plimit > ok_ratio:
|
||||||
|
health = max(health, YELLOW)
|
||||||
|
details.append('processes used: %s, processes limit: %s'
|
||||||
|
% (pused, plimit))
|
||||||
|
elif pused >= plimit:
|
||||||
|
health = max(health, RED)
|
||||||
|
details.append('processes used: %s, processes limit: %s'
|
||||||
|
% (pused, plimit))
|
||||||
|
except ValueError:
|
||||||
|
details.append('cannot convert processes* to numbers')
|
||||||
|
health = max(health, UNKNOWN)
|
||||||
|
except KeyError:
|
||||||
|
details.append('processes* not present')
|
||||||
|
health = max(health, UNKNOWN)
|
||||||
|
|
||||||
|
# fd check
|
||||||
|
try:
|
||||||
|
sused = float(status['file_descriptors']['sockets_used'])
|
||||||
|
slimit = float(status['file_descriptors']['sockets_limit'])
|
||||||
|
ok_ratio = 0.9
|
||||||
|
if sused < slimit and sused/slimit > ok_ratio:
|
||||||
|
health = max(health, YELLOW)
|
||||||
|
details.append('sockets used: %s, sockets limit: %s'
|
||||||
|
% (sused, slimit))
|
||||||
|
elif sused >= slimit:
|
||||||
|
health = max(health, RED)
|
||||||
|
details.append('sockets used: %s, sockets limit: %s'
|
||||||
|
% (sused, slimit))
|
||||||
|
fdused = float(status['file_descriptors']['total_used'])
|
||||||
|
fdlimit = float(status['file_descriptors']['total_limit'])
|
||||||
|
ok_ratio = 0.9
|
||||||
|
if fdused < fdlimit and fdused/fdlimit > ok_ratio:
|
||||||
|
health = max(health, YELLOW)
|
||||||
|
details.append('fd total used: %s, fd total limit: %s'
|
||||||
|
% (fdused, fdlimit))
|
||||||
|
elif fdused >= fdlimit:
|
||||||
|
health = max(health, RED)
|
||||||
|
details.append('fd total used: %s, fd total limit: %s'
|
||||||
|
% (fdused, fdlimit))
|
||||||
|
except ValueError:
|
||||||
|
details.append('cannot convert file_descriptors* to numbers')
|
||||||
|
health = max(health, UNKNOWN)
|
||||||
|
except KeyError:
|
||||||
|
details.append('file_descriptors* not present')
|
||||||
|
health = max(health, UNKNOWN)
|
||||||
|
|
||||||
|
return health, details
|
@ -16,7 +16,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
project_name = 'timmy'
|
project_name = 'timmy'
|
||||||
version = '1.26.1'
|
version = '1.26.2'
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
|
Loading…
x
Reference in New Issue
Block a user