def graph(request, name): """Handle the graph request. :param request: The original resmon GRAPH request. :type request: HttpRequest :param name: The name of the resmon RRD whose graph is desired. :type name: str :return: The response to the graph request. :rtype: HttpResponse """ try: period = request.GET.get('period') width = request.GET.get('width') height = request.GET.get('height') dataset = request.GET.get('dataset') # Space delimited data set end_ts = int(time.time()) start_ts = end_ts - parse_timespec(period) if not dataset: raise HttpResponseBadRequest('No dataset given') resp = RestCmd('resmon/graph', '') img = tempfile.mkstemp(suffix=".png", prefix="resmongraph") try: close(img[0]) execute_graph_request(name, dataset.split(), img[1], start_ts, end_ts, 'AVERAGE', width, height) # Now read in the image file and prepare for the response. with open(img[1], 'r') as f: img_size = os.path.getsize(img[1]) if img_size <= 2095104: # Read maximum 2Mb resp.data = f.read() if 'xml' in request.META.get('HTTP_ACCEPT'): return HttpResponse(ElementTree.tostring(resp.export_xml()), content_type='application/xml') return HttpResponse(resp.export_json(), content_type='application/json') else: logger.warning('Image file size {0} exceeded the maximum limit of 2Mb, please retry with smaller dimensions.' .format(img_size)) return HttpResponseServerError('Image file too large') finally: os.remove(img[1]) # Clean up the temp file. except Exception as e: tb = sys.exc_info()[2] logger.error('Encountered unexpected {0} at {1}'.format(e, traceback.format_tb(tb))) return HttpResponseServerError('Unexpected internal server error')
def resmon_on_off(request, action, name): """Activate/deactivate a specific resmon, create a new resmon DB if necessary. :param request: The original HTTP request. :type request: HttpRequest :param action: The action to take, must be one of: 'on' or 'off'. :type action: str :param name: The name of the monitor against which to apply the action. :type name: str :return: The response to this request. :rtype: HttpResponse """ global _task_repository global _lock try: resp = RestCmd('resmon', '') if action == 'on': period = request.GET.get('period') with _lock: if name in _task_repository: logger.warning('Monitor {0} already running, restarting.'.format(name)) _task_repository.pop(name).stop() logger.info('Staring monitor {0} at intervals {1}.'.format(name, period)) _task_repository[name] = start_monitor(name, parse_timespec(period), ResmonListener()) if 'xml' in request.META.get('HTTP_ACCEPT'): return HttpResponse(ElementTree.tostring(resp.export_xml()), content_type='application/xml') return HttpResponse(resp.export_json(), content_type='application/json') with _lock: if name in _task_repository: task = _task_repository.pop(name) logger.info('Stopping {0}'.format(name)) task.stop() else: logger.warning('{0} not in resmon repository. Attempt to stop is ignored.'.format(name)) if 'xml' in request.META.get('HTTP_ACCEPT'): return HttpResponse(ElementTree.tostring(resp.export_xml()), content_type='application/xml') return HttpResponse(resp.export_json(), content_type='application/json') except Exception as e: tb = sys.exc_info()[2] logger.warning('Encountered unexpected {0} at {1}'.format(e, traceback.format_tb(tb))) return HttpResponseServerError('Encountered unexpected internal server error')
def main(args): """Main entry point of this program. :param args: The command-line argument list :return: Exit code :rtype: int """ parser = argparse.ArgumentParser(prog='resmon.py', description='Monitor the system resource utilisation, periodically') top = parser group1 = top.add_argument_group() group1.add_argument('-n', metavar='name', help='Name of the resource monitoring session, artifacts will follow this' ' name', type=str) group1.add_argument('-p', metavar='period', help='The sampling period of the monitoring process. E.g. 10s, 1m, 2h.' ' Default is 1m', default='1m', type=str) group2 = top.add_argument_group() group2.add_argument('-l', help='List all the resmon databases found in the working directory and return.', action='count') arg = parser.parse_args(args) if arg.l: print(execute_list_dbs()) return 0 if not arg.n: logger.error('No name specified') return errno.EINVAL if arg.p: period = parse_timespec(arg.p) else: period = 60 # Default period is 1m monitor = start_monitor(arg.n, period) try: while 1: # Run until stopped # Wake up periodically and do something, like kicking a watchdog or something like that, not sure what yet. sleep(600) except KeyboardInterrupt: logger.info('User interrupted') return errno.EINTR finally: monitor.stop() logger.info('resmon terminated') return errno.EINVAL # If we are here we were interrupted by something other than KeyboardInterrupt
def fetch(request, name, res_type, consolidation): """Fetch the data from a specific RRD, in some time frame, with a particular resolution. :param request: The original request. :type request: HttpRequest :param name: The name of the target resmon database. :type name: str :param res_type: The type of data: cpu | memory :type res_type: str :param consolidation: The optional consolidation function used. If specified must be one of: average | last. The default is last. :type consolidation; str :return: The requested data set. """ try: resolution = request.GET.get('resolution') start = request.GET.get('start') end = request.GET.get('end') if not resolution: resolution = '1s' # Default to the fastest resolution if not end: end = time.time() # Default to now if not start: start = end - (24 * 3600) # Default to one day worth of data ts = time.time() data = None if consolidation == 'average': data = rrdutil.fetch_avg_data(name + res_type + '.rrd', start_ts=int(start), end_ts=int(end), resolution=parse_timespec(resolution)) else: data = rrdutil.fetch_last_data(name + res_type + '.rrd', start_ts=int(start), end_ts=int(end), resolution=parse_timespec(resolution)) resp = RestCmd('/resmon/fetch', _process_fetch_data(data)) if 'xml' in request.META.get('HTTP_ACCEPT'): return HttpResponse(ElementTree.tostring(resp.export_xml()), content_type='application/xml') return HttpResponse(resp.export_json(), content_type='application/json') except Exception as e: tb = sys.exc_info()[2] logger.error('Encountered unexpected {0} at {1}'.format(e, traceback.format_tb(tb))) return HttpResponseServerError('Encountered unexpected error, please check service log for more details')
def main(args): """Main entry to the gen_graph command. :param args: Command line argument list. A list of strings. :type args: list :return: The return code for the command, 0 is success, anything else for failure :rtype: int """ exit_code = 0 # Default to success parser = None try: # Parse the given argument list parser = argparse.ArgumentParser(prog='fetch', description='Fetch some resource utilisation data from a resmon DB') parser.add_argument('-s', metavar='start_time', help='The start time, default to 24h before the end time', type=int) parser.add_argument('-e', metavar='end_time', help='The end time, default to now', type=int) parser.add_argument('-c', help='Consolidation function: ave | last. Default to ave', type=str, choices=['ave', 'last'], default='ave') parser.add_argument('-r', help='Resolution of the requested data, e.g. 1s, 30s, 1m, ...', type=str, required=True) parser.add_argument('-p', metavar='period/timeframe', help='If a start time is not specified then this will ' 'specify the period of time against which the graph will cover. E.g. 23s, 5m, 6h, 1d, 2w', type=str, default='1d') parser.add_argument('-f', metavar='RRD_file', help='Name of the RRD file', type=str, required=True) arg = parser.parse_args(args=args) # Calculating the end timestamp end_ts = int(time.time()) if arg.e: # End time end_ts = int(arg.e) # Calculating the start timestamp start_ts = end_ts - (24 * 3600) # Default start time is one day old data if arg.s: # Start time start_ts = int(arg.s) elif arg.p: # Period is meaningful only when start time is not specified start_ts = end_ts - parse_timespec(arg.p) ret = [] # Calculating the consolidation function if arg.c == 'last': ret += fetch_last_data(arg.f, start_ts=start_ts, end_ts=end_ts, resolution=parse_timespec(arg.r)) else: ret += fetch_avg_data(arg.f, start_ts=start_ts, end_ts=end_ts, resolution=parse_timespec(arg.r)) if len(ret) > 2: curr_ts = ret[0][0] inc = int(ret[0][2]) print(rrd_fields_to_csv('ts', ret[1])) for line in ret[2]: print(rrd_fields_to_csv(curr_ts, line)) curr_ts += inc except KeyboardInterrupt: tb = sys.exc_info()[2] logger.warning('User interruption at {0}'.format(format_tb(tb))) exit_code = errno.EINTR except ValueError as e: tb = sys.exc_info()[2] logger.warning('Encountered {0} at {1}'.format(e, format_tb(tb))) exit_code = errno.EINVAL except Exception as e: tb = sys.exc_info()[2] logger.warning('Encountered unexpected {0} at {1}'.format(e, format_tb(tb))) exit_code = errno.EINVAL return exit_code
def main(args): """Main entry to the gen_graph command. :param args: Command line argument list. A list of strings. :type args: list :return: The return code for the command, 0 is success, anything else for failure :rtype: int """ exit_code = 0 # Default to success parser = None try: # Parse the given argument list parser = argparse.ArgumentParser(prog="gengraph.py", description="Generate resource utilisation graphs") parser.add_argument("image", metavar="img_file", help="Name of the image file", type=str) parser.add_argument( "-d", metavar="data_set", help="Space delimited dataset to be included in the graph", type=str, required=True, ) parser.add_argument( "-s", metavar="start_time", help="The start time, default to 24h before the end time", type=int ) parser.add_argument("-e", metavar="end_time", help="The end time, default to now", type=int) parser.add_argument( "-c", help="Consolidation function: ave | last. Default to ave", type=str, choices=["ave", "last"], default="ave", ) parser.add_argument( "-p", metavar="period/timeframe", help="If a start time is not specified then this will " "specify the period of time against which the graph will cover. E.g. 23s, 5m, 6h, 1d, 2w", type=str, default="1d", ) parser.add_argument("-f", metavar="RRD_file", help="Name of the RRD file", type=str, required=True) parser.add_argument( "-x", metavar="width", help="The width of the graph, in number of pixels (default=640)", type=int, default=640, ) parser.add_argument( "-y", metavar="height", help="The height of the graph, in number of pixels (default=480)", type=int, default=480, ) arg = parser.parse_args(args=args) # Calculating the end timestamp end_graf = int(time.time()) if arg.e: # End time end_graf = arg.e # Calculating the start timestamp start_graf = end_graf - (24 * 3600) # Default start time is one day old data if arg.s: # Start time start_graf = arg.s elif arg.p: # Period is meaningful only when start time is not specified start_graf = end_graf - parse_timespec(arg.p) # Calculating the consolidation function cf = "AVERAGE" if arg.c == "last": cf = "LAST" execute_graph_request( rrd_name=arg.f, data_set=arg.d.split(), image_file=arg.image, start_ts=start_graf, end_ts=end_graf, consolidation_func=cf, width=arg.x, height=arg.y, ) except KeyboardInterrupt: tb = sys.exc_info()[2] logger.warning("User interruption at {0}".format(format_tb(tb))) exit_code = errno.EINTR except ValueError as e: tb = sys.exc_info()[2] logger.warning("Encountered {0} at {1}".format(e, format_tb(tb))) exit_code = errno.EINVAL except Exception as e: tb = sys.exc_info()[2] logger.warning("Encountered unexpected {0} at {1}".format(e, format_tb(tb))) exit_code = errno.EINVAL return exit_code