Example #1
0
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')
Example #2
0
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')
Example #3
0
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
Example #4
0
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')
Example #5
0
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
Example #6
0
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