def list_reports(config):
    """
    TODO
    """
    result = {}

    if not 'reports_directory' in config:
        msg = "Internal Error."
        raise UserError(msg)

    target = config['reports_directory'] or PGBADGER_REPORTS_DIRECTORY

    try:
        all_files_in_reports_dir = os.listdir(target)
    except:
        msg = "Error while reading the reports directory."
        raise UserError(msg)

    for f in all_files_in_reports_dir:
        if f.endswith(".json"):
            # filename format is supposed to be like that:
            # 1525794324_pgbadger_report_05may2018.json
            timestamp = int(f.split('_')[0])
            metadata = {}
            metadata['timestamp'] = timestamp
            metadata['created_at'] = datetime.fromtimestamp(timestamp)
            metadata['url_json'] = '/pgbadger/v0/reports/%d/json' % timestamp
            metadata['url_html'] = '/pgbadger/v0/reports/%d/html' % timestamp
            result[timestamp] = metadata

    return result
def fetch_report_html(config, timestamp):
    """
    TODO
    """
    html_file = html_report_filepath(config, timestamp)

    # if the report does not exist let's build it from the JSON data
    if not os.path.isfile(html_file):
        # Generate the HTML report from the JSON version
        output_args = ['-f', 'json', json_report_filepath(config, timestamp)]
        input_args = ['-o', html_file]
        command = ['perl', pgbadger_bin(config)] + output_args + input_args
        # This operation should be very quick
        (return_code, stdout, stderr) = exec_command(command)
        if return_code != 0:
            msg = "pgBadger failed."
            logger.error("%s during command %s with error %s" %
                         (msg, command, stderr))
            raise UserError(msg)
    try:
        f = open(html_file, 'r')
        html_content = f.read()
    except:
        msg = "Internal Error."
        logger.error("Can't open file : %s" % html_file)
        raise UserError(msg)

    return html_content
def create_report(config):
    """
    TODO
    """
    now = datetime.now()
    metadata = {}
    metadata['created_at'] = now
    metadata['timestamp'] = int(time.mktime(now.timetuple()))

    # output file
    output_args = [
        '--outfile',
        json_report_filepath(config, metadata['timestamp'])
    ]

    # input file
    try:
        input_dir = config['log_directory'] or POSTGRESQL_LOG_DIRECTORY
    except:
        msg = 'Internal Error.'
        raise UserError(msg)
    input_filename = 'postgresql.log'
    input_args = [os.path.join(input_dir, input_filename)]

    # Launch
    command = ['perl', pgbadger_bin(config)] + output_args + input_args
    (return_code, stdout, stderr) = exec_command(command)

    if return_code != 0:
        msg = "pgBadger failed"
        logger.error("%s during command %s with error %s" %
                     (msg, command, stderr))
        raise UserError(msg)

    return metadata
Example #4
0
def check_table_exists(conn, schema, table):
    # Check that the specified table exists in schema
    rows = conn.query(
        "SELECT 1 FROM pg_tables WHERE tablename = '{table}' AND "
        "schemaname = '{schema}'".format(table=table, schema=schema))
    if not list(rows):
        raise UserError("Table %s.%s not found" % (schema, table))
Example #5
0
def check_index_exists(conn, schema, index):
    # Check that the specified table exists in schema
    rows = conn.query(
        "SELECT 1 FROM pg_indexes WHERE indexname = '{index}' AND "
        "schemaname = '{schema}'".format(index=index, schema=schema))
    if not list(rows):
        raise UserError("Index %s.%s not found" % (schema, index))
Example #6
0
def vacuum(conn, dbname, mode, schema=None, table=None):
    # Run vacuum statement

    if table:
        check_table_exists(conn, schema, table)

    # Build the SQL query
    q = "VACUUM"
    q += " (%s) " % mode.upper() if mode else ""

    if schema and table:
        q += " {schema}.{table}".format(schema=schema, table=table)

    try:
        # Try to execute the statement
        logger.info("Running SQL on DB %s: %s" % (dbname, q))
        conn.execute(q)
        logger.info("VACCUM done.")
    except error as e:
        logger.exception(str(e))
        logger.error("Unable to execute SQL: %s" % q)
        message = "Unable to run vacuum %s" % mode
        if schema and table:
            message += " on %s.%s" % (
                schema,
                table,
            )

        raise UserError(message)
Example #7
0
def analyze(conn, dbname, schema=None, table=None):
    # Run analyze statement
    if table:
        check_table_exists(conn, schema, table)

    # Build the SQL query
    q = "ANALYZE"
    if schema and table:
        q += " {schema}.{table}".format(schema=schema, table=table)

    try:
        # Try to execute the statement
        logger.info("Running SQL on DB %s: %s" % (dbname, q))
        conn.execute(q)
        logger.info("ANALYZE done.")
    except error as e:
        logger.exception(str(e))
        logger.error("Unable to execute SQL: %s" % q)
        message = "Unable to run analyze"
        if schema and table:
            message += " on %s.%s" % (
                schema,
                table,
            )

        raise UserError(message)
Example #8
0
def reindex(conn, dbname, schema, table, index):
    if index:
        check_index_exists(conn, schema, index)
    if table:
        check_table_exists(conn, schema, table)

    # Build the SQL query
    q = "REINDEX"
    if table:
        element = '{schema}.{table}'.format(schema=schema, table=table)
        q += " TABLE {element}".format(element=element)
    elif index:
        element = '{schema}.{index}'.format(schema=schema, index=index)
        q += " INDEX {element}".format(element=element)
    else:
        element = '{dbname}'.format(dbname=dbname)
        q += " DATABASE {element}".format(element=element)

    try:
        # Try to execute the statement
        logger.info("Running SQL on DB %s: %s" % (dbname, q))
        conn.execute(q)
        logger.info("reindex done.")
    except error as e:
        logger.exception(str(e))
        logger.error("Unable to execute SQL: %s" % q)
        raise UserError("Unable to run reindex on %s" % (element))
def info(app):
    cmd = base_cmd(app.config) + ['version']
    logger.debug(' '.join(cmd))
    (rc, out, err) = exec_command(cmd)
    if rc != 0:
        raise UserError("Could not get version of pgBackRest")
    v = out.strip().split()[1]
    return {"tool": "pgBackRest", "version": v, "supported": True}
Example #10
0
    def load(self):
        pg_version = self.app.postgres.fetch_version()
        if pg_version < self.PG_MIN_VERSION:
            msg = "%s is incompatible with Postgres below 9.4" % (
                self.__class__.__name__)
            raise UserError(msg)

        self.app.router.add(routes)
Example #11
0
    def load(self):
        pg_version = self.app.postgres.fetch_version()
        if pg_version < self.pg_min_version:
            raise UserError("hellong is incompatible with Postgres below 9.4")

        self.app.router.add(routes)
        self.app.worker_pool.add(workers)
        self.app.scheduler.add(workers)
Example #12
0
def purge(config):
    cmd = base_cmd(config) + ['purge']
    logger.debug(' '.join(cmd))
    (rc, out, err) = exec_command(cmd)
    result = {'rc': rc, 'stdout': out.split('\n'), 'stderr': err.split('\n')}
    logger.debug(out)
    logger.debug(err)
    if rc != 0:
        raise UserError(json.dumps(result))
    return json.dumps(result)
Example #13
0
    def load(self):
        pg_version = self.app.postgres.fetch_version()
        if pg_version < self.PG_MIN_VERSION:
            msg = "%s is incompatible with Postgres below 9.4" % (
                self.__class__.__name__)
            raise UserError(msg)

        add_route('GET', '/activity')(get_activity)
        add_route('GET', '/activity/waiting')(get_activity_waiting)
        add_route('GET', '/activity/blocking')(get_activity_blocking)
def fetch_report(config, timestamp):
    """
    TODO 
    """
    reports = list_reports(config)

    if not timestamp in reports.keys():
        msg = "Can't find report for timestamp %d" % timestamp
        logger.error(msg)
        raise UserError(msg)

    return append_json_report(config, reports[timestamp])
def delete_report(config, timestamp):
    """
    Remove a report, identified by its timestamp 
    """
    report_file = json_report_filepath(config, timestamp)
    try:
        os.remove(report_file)
    except:
        msg = "Internal Error."
        logger.error("Can't remove report %s" % report_file)
        raise UserError(msg)
    return {'result': 'Report Removed Succesfully'}
Example #16
0
    def load(self):
        pg_version = self.app.postgres.fetch_version()
        if pg_version < self.PG_MIN_VERSION:
            msg = "%s is incompatible with Postgres below 9.4" % (
                self.__class__.__name__)
            raise UserError(msg)

        self.app.router.add(routes)
        self.app.worker_pool.add(workers)
        workers.schedule(
            id='dashboard_collector',
            redo_interval=self.app.config.dashboard.scheduler_interval)(
                dashboard_collector_worker)
        self.app.scheduler.add(workers)
def append_json_report(config, report):
    """
    Add the JSON content of the report in the current report object
    """
    json_file = json_report_filepath(config, report['timestamp'])
    try:
        f = open(json_file, 'r')
        report['json'] = f.read()
    except:
        msg = "Internal Error."
        logger.error("Can't open file : %s" % json_file)
        raise UserError(msg)

    return report
def check_version(config):
    """
    check if the pgBadger version is correct, 
    throws an error is pgBadger is not present or too old
    
    :param path: directory containing the pgBadger binary (optional)
    :return: the version in different formats
    """

    command = ['perl', pgbadger_bin(config), '--version']
    (return_code, stdout, stderr) = exec_command(command)

    if return_code != 0:
        msg = "Seems like pgBadger is not installed : %s" % stderr
        raise UserError(msg)

    version = parse_version(stdout)

    if version['int_version'] < PGBADGER_MIN_VERSION:
        msg = "This version of pgBadger is too old : %s" % version[
            'full_version']
        raise UserError(msg)

    return version
    def load(self):
        global APP
        APP = self.app

        pg_version = self.app.postgres.fetch_version()
        if pg_version < self.pg_min_version:
            raise UserError("hellong is incompatible with Postgres below 9.4")

        # URI **MUST** be bytes.
        add_route('GET', b'/hello')(get_hello)
        add_route('GET', b'/hello/time')(get_hello_time)
        add_route('GET', b'/hello/' + T_SOMETHING)(get_hello_something)
        add_route('GET', b'/hello2/say')(get_hello_something2)
        add_route('POST', b'/hello3/say')(get_hello_something3)
        add_route('GET', b'/hello4/' + T_SOMETHING)(get_hello_something4)
        add_route('GET', b'/hello/from_config')(get_hello_from_config)
        add_route(
            'GET',
            b'/hello/from_background_worker')(get_hello_from_background_worker)

        taskmanager.worker(pool_size=1)(say_hello_worker)
        taskmanager.bootstrap()(hello_task_manager_bootstrap)
def pgbadger_bin(config):
    try:
        return os.path.join(config['pgbadger_path'] or '', 'pgbadger')
    except:
        msg = 'Internal Error.'
        raise UserError(msg)
def reports_directory(config):
    try:
        return config['reports_directory'] or PGBADGER_REPORTS_DIRECTORY
    except:
        msg = 'Internal Error.'
        raise UserError(msg)
Example #22
0
 def main(argv, environ):
     raise UserError('POUET', retcode=0xd0d0)