def __init__(self, dir, host, rrd, period="day"): api = twirrdy.RRDBasicAPI() self.rrd = rrd self.host = host path = "%s/%s/%s" % (dir, host, rrd) self.rrd_path = "%s.rrd" % path self.info = api.info(self.rrd_path) self.color = Colorator() self.period = period try: coil_fd = open("%s.coil" % path) try: coil_stat = os.fstat(coil_fd.fileno()) self.private = not (coil_stat.st_mode & stat.S_IROTH) self.conf = coil.parse(coil_fd.read()) finally: coil_fd.close() except (IOError, OSError), ex: raise errors.InitError("Unable to read coil file: %s" % ex)
def are_graphable(host, service_list): """Flags services of host that are graphable (has state or trend)""" rra_path = settings.RRA_PATH for service in service_list: coilfile = '%s%s/%s.coil' % \ (rra_path, host, service['service_description']) rrd = '%s%s/%s.rrd' % (rra_path, host, service['service_description']) if os.path.exists(coilfile) and os.path.exists(rrd): coilstring = open(coilfile).read() coilstruct = coil.parse(coilstring) query = coilstruct.get('query') # rrdtool hates unicode strings, and Django gives us one, # so convert to ascii rrdslice = rrdtool.fetch(str(rrd), '--start', '0', '--end', '10', '--resolution', '1', 'AVERAGE') try: rrdslice[1].index('_state') service['is_graphable'] = True except ValueError: for key in query.keys(): val = query.get(key) if type() == type(query) and 'trend' in val: service['is_graphable'] = True break service['is_graphable'] = False else: service['is_graphable'] = False
def is_graphable(host, service): """Checks if service of host is graphable (has state or trend)""" rra_path = settings.RRA_PATH coilfile = '%s%s/%s.coil' % (rra_path, host, service) rrd = '%s%s/%s.rrd' % (rra_path, host, service) if os.path.exists(coilfile) and os.path.exists(rrd): coilstring = open(coilfile).read() coilstruct = coil.parse(coilstring) query = coilstruct.get('query') # rrdtool hates unicode strings, and Django gives us one, # so convert to ascii rrdslice = rrdtool.fetch(str(rrd), '--start', '0', '--end', '10', '--resolution', '1', 'AVERAGE') try: rrdslice[1].index('_state') return True except ValueError: for key in query.keys(): val = query.get(key) if type() == type(query) and 'trend' in val: return True return False return False
def setUp(self): self.notification = plugin.search(notify.INotification, self.name) self.macros = { 'host': notify.Macros(test_notify.ENVIRONMENT_HOST), 'service': notify.Macros(test_notify.ENVIRONMENT_SERVICE)} self.factory = dummy_server.SMTP() self.server = reactor.listenTCP(0, self.factory) self.config = coil.parse(notify.DEFAULT_CONFIG) self.config.merge(coil.struct.Struct(self.notification.defaults)) self.config['smtp.port'] = self.server.getHost().port
def setUp(self): self.macros = { 'host': notify.Macros(ENVIRONMENT_HOST), 'service': notify.Macros(ENVIRONMENT_SERVICE)} self.config = coil.parse(notify.DEFAULT_CONFIG)
def get_data(host, service, start=None, end=None, resolution='150'): if not end: end = int(time.time()) if not start: start = end - DAY rra_path = settings.RRA_PATH rrd = '%s%s/%s.rrd' % (rra_path, host, service) coilfile = '%s%s/%s.coil' % (rra_path, host, service) railroad_conf = 'railroad_conf' statistics = 'statistics' trend_attributes = ['color', 'stack', 'scale', 'display'] # calculate custom resolution resolution = (int(end) - int(start)) / int(resolution) # rrdtool hates unicode strings, and Django gives us one, # so convert to ascii rrdslice = rrdtool.fetch(str(rrd), '--start', str(start), '--end', str(end), '--resolution', str(resolution), 'AVERAGE') time_struct = time.gmtime() time_dict = {'h': time_struct.tm_hour, 'm': time_struct.tm_min, \ 's': time_struct.tm_sec} current_time = '%(h)02d:%(m)02d:%(s)02d UTC' % time_dict # Parse the data actual_start, actual_end, res = rrdslice[0] # Multiply by 1000 to convert to JS timestamp (millisecond resolution) res *= 1000 coilstring = open(coilfile).read() coilstruct = coil.parse(coilstring) query = coilstruct.get('query', {}) if not(query): raise RailroadError("OMG PONIES! query doesn't exist in coil file") # Graph options for FLOT graph_options = { 'xaxis': { 'mode': 'time', }, 'yaxis': {}, 'legend': {'position': 'nw'}, 'selection': {'mode': 'x'}, 'pan': {'interactive': True}, 'grid': { 'hoverable': True, } } # Handle unconventional trend definitions root_trend = coilstruct.get('trend', {}) all_labels = rrdslice[1] labels = [] root_label = None if root_trend: root_label = root_trend.get('label', None) if not(root_label): root_label = coilstruct.get('label', None) compound = query.get('type') == 'compound' if compound: for key in query.keys(): val = query.get(key) if isinstance(val, coil.struct.Struct): trend = val.get('trend', None) if trend and trend.get('type', None): label = trend.get('label', None) if not(label): label = key labels.append((key, label)) if 'query' in all_labels: trend = query.get('trend', None) if trend: query_label = trend.get('label', None) if not(query_label): query_label = root_label labels.append(('query', query_label if query_label else 'Result')) if '_result' in all_labels: labels.append(('_result', root_label if root_label else 'Result')) length = len(labels) indices = range(length) dataset = {} # flot_data and flot_data are of the format # [ { label: "Foo", data: [ [10, 1], [17, -14], [30, 5] ] }, # { label: "Bar", data: [ [11, 13], [19, 11], [30, -7] ] } ] # See Flot Reference (http://flot.googlecode.com/svn/trunk/API.txt) flot_data = [{'label': label[1], railroad_conf: {}, 'data': []} for label in labels] labels = map(lambda x: x[0], labels) state_data = [] graph_options['colors'] = getColors(labels) # Reading graph options for index in indices: key = labels[index] trend = query.get(key, {}).get('trend', {}) if not(trend): continue trend_settings = {} for var in trend_attributes: trend_settings[var] = trend.get(var, '') flot_data[index]['lines'] = {'show': True} if trend_settings['display']: flot_data[index]['lines']['fill'] = ( 0.5 if trend_settings['display'] == 'area' else 0) if trend_settings['scale']: flot_data[index][railroad_conf]['scale'] = trend_settings['scale'] else: flot_data[index][railroad_conf]['scale'] = 1 if trend_settings['color']: flot_data[index]['color'] = trend_settings['color'] if trend_settings['stack']: flot_data[index]['stack'] = True if index > 0: flot_data[index-1]['stack'] = True # See above x = actual_start * 1000 transform = [all_labels.index(z) for z in labels] state_index = all_labels.index('_state') # Set defaults datapoint = rrdslice[2][0] for index in indices: flot_data[index][statistics] = {} flot_data[index][statistics]['cur'] = None flot_data[index][statistics]['num'] = 0 flot_data[index][statistics]['sum'] = 0 flot_data[index][statistics]['max'] = None flot_data[index][statistics]['min'] = None if not 'scale' in flot_data[index][railroad_conf]: flot_data[index][railroad_conf]['scale'] = 1 data = datapoint[transform[index]] if data: data *= flot_data[index][railroad_conf]['scale'] flot_data[index][statistics]['max'] = data flot_data[index][statistics]['min'] = data # Loop over all data and aggregate it in flot's desired format for datapoints in rrdslice[2]: data = datapoints[state_index] state_data.append([x, data]) for index in indices: data = datapoints[transform[index]] if datapoints[state_index] != None: flot_data[index][statistics]['cur'] = data if data != None: flot_data[index][statistics]['num'] += 1 data *= flot_data[index][railroad_conf]['scale'] flot_data[index][statistics]['sum'] += data if (flot_data[index][statistics]['max'] == None or data > flot_data[index][statistics]['max']): flot_data[index][statistics]['max'] = data if (flot_data[index][statistics]['min'] == None or data < flot_data[index][statistics]['min']): flot_data[index][statistics]['min'] = data flot_data[index]['data'].append([x, data]) if 'lines' not in flot_data[index]: flot_data[index]['lines'] = {} flot_data[index]['lines']['show'] = True x += res empty_graph = True for index in indices: if flot_data[index][statistics]['num']: empty_graph = False base = 1000 max = 100 if length > 0: value = query.get(labels[0], {}).get('trend', {}).get('base', '') if value: base = int(value) max = flot_data[0][statistics]['max'] for index in indices: if flot_data[index][statistics]['num'] > 0: flot_data[index][statistics]['avg'] = ( flot_data[index][statistics]['sum'] / flot_data[index][statistics]['num']) if flot_data[index][statistics]['max'] > max: max = flot_data[index][statistics]['max'] # Compute appropriate unit from base bases = ['', 'K', 'M', 'G', 'T'] for interval in range(len(bases)): if max != None and (max / pow(base, interval)) <= base: break final_base = pow(base, interval) unit = bases[interval] if max != None: graph_options['yaxis']['max'] = max * 1.1 + 1 if root_trend and max != None: axis_max = root_trend.get('axis_max', '') if axis_max and graph_options['yaxis']['max'] < axis_max: graph_options['yaxis']['max'] = axis_max * 1.1 + 1 if root_trend: axis_label = root_trend.get('axis_label', '') if axis_label: graph_options['yaxis']['label'] = axis_label for index in indices: del(flot_data[index][railroad_conf]) # Set background of graph based on state colors = ['#BBFFBB', '#FFFFBB', '#FFBBBB', '#C0C0C0'] markings = [] state = state_data[0][1] if type(state) == types.FloatType: state = int(state) if float.is_integer(state) else 3 markings.append({'xaxis': {'from': state_data[0][0]}, \ 'color': colors[state]}) for x, y in state_data: if type(y) == types.FloatType: y = int(y) if float.is_integer(y) else 3 if y != state: if type(state) == types.IntType: markings[-1]['xaxis']['to'] = x state = y if type(state) == types.IntType: markings.append({'xaxis': {'from': x}, 'color': colors[state]}) if type(state) == types.FloatType: markings[-1]['xaxis']['to'] = state_data[-1][0] empty_graph = empty_graph and (not(len(markings))) graph_options['grid']['markings'] = markings # Pass state, BUT DONT DRAW!! this is so that graphs with ONLY state # still draw (otherwise they don't get axes, ticks, etc) flot_data.append({'data': state_data, 'lines': {'show': False}}) result = {'options': graph_options, 'data': flot_data, 'base': base, 'empty': empty_graph, 'current_time': current_time, 'start': start, 'end': end, } return result
'--resolution', str(resolution), 'AVERAGE') time_struct = time.gmtime() time_dict = {'h': time_struct.tm_hour, 'm': time_struct.tm_min, \ 's': time_struct.tm_sec} current_time = '%(h)02d:%(m)02d:%(s)02d UTC' % time_dict # Parse the data actual_start, actual_end, res = rrdslice[0] # Multiply by 1000 to convert to JS timestamp (millisecond resolution) res *= 1000 coilstring = open(coilfile).read() coilstruct = coil.parse(coilstring) query = coilstruct.get('query', {}) if not(query): raise RailroadError("OMG PONIES! query doesn't exist in coil file") # Graph options for FLOT graph_options = { 'xaxis': { 'mode': 'time', }, 'yaxis': {}, 'legend': {'position': 'nw'}, 'selection': {'mode': 'x'}, 'pan': {'interactive': True},
def main(): options, method = parse_options() log.init(options.logfile, options.loglevel) if not options.dump and options.daemonize: if os.fork() > 0: os._exit(0) os.chdir("/") os.setsid() if os.fork() > 0: os._exit(0) log.init_stdio() try: config = coil.parse(DEFAULT_CONFIG) if method.defaults: if isinstance(method.defaults, str): config.merge(coil.parse(method.defaults)) else: config.merge(coil.struct.Struct(method.defaults)) if options.config: config.merge(coil.parse_file(options.config)) except coil.errors.CoilError, ex: log.error("Error parsing config: %s" % ex) sys.exit(1)