示例#1
0
def worker_vacuum(commands, command, config):
    start_time = time.time() * 1000
    set_logger_name("vacuum_worker")
    logger = get_logger(config)
    logger.info("Starting with pid=%s" % (os.getpid()))
    logger.debug("commandid=%s" % (command.commandid, ))

    try:
        command.state = COMMAND_START
        command.time = time.time()
        commands.update(command)
        parameters = pickle.loads(base64.b64decode(command.parameters))
        logger.debug("table=%s, mode=%s, database=%s" % (
            parameters['table'],
            parameters['mode'],
            parameters['database'],
        ))

        conn = connector(host=config.postgresql['host'],
                         port=config.postgresql['port'],
                         user=config.postgresql['user'],
                         password=config.postgresql['password'],
                         database=parameters['database'])
        conn.connect()
        if parameters['mode'] == 'standard':
            query = "VACUUM %s" % (parameters['table'], )
        else:
            query = "VACUUM %s %s" % (
                parameters['mode'],
                parameters['table'],
            )
        conn.execute(query)
        conn.close()
    except (error, SharedItem_not_found, Exception) as e:
        command.state = COMMAND_ERROR
        command.result = str(e)
        command.time = time.time()

        logger.traceback(get_tb())
        logger.error(str(e))

        try:
            commands.update(command)
            conn.close()
        except Exception as e:
            pass
        logger.info("Failed.")
        return

    try:
        command.state = COMMAND_DONE
        command.time = time.time()
        commands.update(command)
    except Exception as e:
        logger.traceback(get_tb())
        logger.error(str(e))

    logger.info("Done.")
    logger.debug(" in %s s." % (str(
        (time.time() * 1000 - start_time) / 1000), ))
示例#2
0
def api_vacuum(http_context, queue_in = None, config = None, sessions = None, commands = None):
    set_logger_name("administration")
    worker = b'vacuum'
    # Get a new logger.
    logger = get_logger(config)
    try:
        check_sessionid(http_context['headers'], sessions)
        post = http_context['post']
        # Check POST parameters.
        validate_parameters(post, [
            ('database', T_OBJECTNAME, False),
            ('table', T_OBJECTNAME, False),
            ('mode', T_VACUUMMODE, False)
        ])
        # Serialize parameters.
        parameters = base64.b64encode(
                        pickle.dumps({
                            'database': post['database'],
                            'table': post['table'],
                            'mode': post['mode']
        })).decode('utf-8')
    except (Exception, HTTPError) as e:
        logger.traceback(get_tb())
        logger.error(str(e))
        if isinstance(e, HTTPError):
            raise e
        else:
            raise HTTPError(500, "Internal error.")

    # Check command uniqueness.
    try:
        commands.check_uniqueness(worker, parameters)
    except SharedItem_exists as e:
        logger.traceback(get_tb())
        logger.error(str(e))
        raise HTTPError(402, "Vaccum '%s' already running on table '%s'." % (post['mode'], post['table']))
    cid =  hash_id(worker + b'-' + parameters.encode('utf-8'))
    command =  Command(
            cid.encode('utf-8'),
            time.time(),
            0,
            worker,
            parameters,
            0,
            u'')
    try:
        commands.add(command)
        # Put the Command in the command queue
        queue_in.put(command)
        return {"cid": cid}
    except SharedItem_no_free_slot_left as e:
        logger.traceback(get_tb())
        logger.error(str(e))
        raise HTTPError(500, "Internal error.")
示例#3
0
def supervision_sender_worker(commands, command, config):
    signal.signal(signal.SIGTERM, supervision_worker_sigterm_handler)
    start_time = time.time() * 1000
    set_logger_name("supervision_sender_worker")
    logger = get_logger(config)
    # TODO: logging methods in supervision plugin must be aligned.
    logging.root = logger
    logger.debug("Starting with pid=%s" % (os.getpid()))
    logger.debug("commandid=%s" % (command.commandid))
    command.state = COMMAND_START
    command.time = time.time()
    command.pid = os.getpid()
    commands.update(command)
    c = 0
    while True:
        # Let's do it smoothly..
        time.sleep(0.5)

        q = Queue('%s/metrics.q' % (config.temboard['home']),
                  max_size=1024 * 1024 * 10,
                  overflow_mode='slide')
        msg = q.shift(delete=False)
        if msg is None:
            break
        try:
            send_output(config.plugins['supervision']['ssl_ca_cert_file'],
                        config.plugins['supervision']['collector_url'],
                        config.temboard['key'], msg.content)
        except urllib2.HTTPError as e:
            logger.traceback(get_tb())
            logger.error(str(e))
            # On an error 409 (DB Integrity) we need to remove the message.
            if int(e.code) != 409:
                logger.debug("Duration: %s." %
                             (str(time.time() * 1000 - start_time)))
                logger.debug("Failed.")
                sys.exit(1)
        except Exception as e:
            logger.traceback(get_tb())
            logger.error(str(e))
            logger.debug("Duration: %s." %
                         (str(time.time() * 1000 - start_time)))
            logger.debug("Failed.")
            sys.exit(1)
        _ = q.shift(delete=True, check_msg=msg)
        if c > 60:
            break
        c += 1
    logger.debug("Duration: %s." % (str(time.time() * 1000 - start_time)))
    logger.debug("Done.")
示例#4
0
def exec_scheduler(queue_in, config, commands, logger):
    """
    In charge of running the scheduling function of each plugin.
    """
    global PLUGINS_LAST_SCHEDULE
    for plugin_name in config.plugins:
        first_run = False
        if not (plugin_name in sys.modules):
            # The plugin seems not to be loaded.
            continue
        if not ('scheduler_interval' in config.plugins[plugin_name]):
            # If scheduler_interval is not set, we don't want to run it.
            continue
        if not (plugin_name in PLUGINS_LAST_SCHEDULE):
            # Check if this is the first shoot.
            PLUGINS_LAST_SCHEDULE[plugin_name] = time.time()
            first_run = True
        if not first_run  and (time.time() - PLUGINS_LAST_SCHEDULE[plugin_name]) < \
             config.plugins[plugin_name]['scheduler_interval']:
            continue
        try:
            logger.debug("Running %s.scheduler()" % (plugin_name))
            # Call plugin's scheduler() function.
            getattr(sys.modules[plugin_name], 'scheduler')(queue_in, config, commands)
            PLUGINS_LAST_SCHEDULE[plugin_name] = time.time()
            logger.debug("Done.")
        except AttributeError as e:
            # scheduler() function does not exist.
            logger.debug("Function does not exist.")
            pass
        except Exception as e:
            logger.traceback(get_tb())
            logger.error(str(e))
            logger.debug("Failed.")
示例#5
0
def api_function_wrapper(config, http_context, sessions, module, function_name):
    """
    API function wrapper in charge of:
        - instanciate a new logger;
        - check the user session id;
        - call a function named 'function_name' from 'module_name' module and return its result;
    """
    logger = get_logger(config)
    logger.debug("Calling %s.%s()." % (module.__name__, function_name,))
    logger.debug(http_context)

    try:
        username = check_sessionid(http_context['headers'], sessions)
        http_context['username'] = username
        dm = getattr(module, function_name)(config, http_context)
        logger.debug("Done.")
        return dm

    except (Exception, HTTPError) as e:
        logger.traceback(get_tb())
        logger.error(str(e))
        logger.debug("Failed.")
        if isinstance(e, HTTPError):
            raise e
        else:
            raise HTTPError(500, "Internal error.")
示例#6
0
def get_command(http_context,
                queue_in=None,
                config=None,
                sessions=None,
                commands=None):
    headers = http_context['headers']
    set_logger_name("api")
    logger = get_logger(config)
    logger.info("Get command status.")
    try:
        check_sessionid(headers, sessions)
    except HTTPError as e:
        logger.traceback(get_tb())
        logger.error(e.message)
        logger.info("Invalid session.")
        raise e
    cid = http_context['urlvars'][0]
    try:
        command = commands.get_by_commandid(cid.encode('utf-8'))
        c_time = command.time
        c_state = command.state
        c_result = command.result
        if c_state == COMMAND_DONE or c_state == COMMAND_ERROR:
            commands.delete(cid.encode('utf-8'))
        logger.info("Done.")
        return {
            'cid': cid,
            'time': c_time,
            'state': c_state,
            'result': c_result
        }
    except SharedItem_not_found as e:
        logger.traceback(get_tb())
        logger.error(e.message)
        logger.info("Failed.")
        raise HTTPError(401, "Invalid command.")
示例#7
0
def httpd_run(commands, queue_in, config, sessions):
    """
    Serve HTTP for ever and reload configuration from the conf file on SIGHUP
    signal catch.
    """
    server_address = (config.temboard['address'], config.temboard['port'])
    handler_class = handleRequestsUsing(commands, queue_in, config, sessions)
    httpd = ThreadedHTTPServer(server_address, handler_class)
    httpd.socket = ssl.wrap_socket(httpd.socket,
                                   keyfile=config.temboard['ssl_key_file'],
                                   certfile=config.temboard['ssl_cert_file'],
                                   server_side=True)
    # We need a timeout here because the code after httpd.handle_request() call
    # is written to handle configuration re-loading and needs to be ran periodicaly.
    httpd.timeout = 1
    set_logger_name("httpd")
    logger = get_logger(config)
    while True:
        httpd.handle_request()
        if reload_true():
            # SIGHUP caught
            # Try to load configuration from the configuration file.
            try:
                logger.info("SIGHUP signal caught, trying to reload "
                            "configuration.")
                new_config = Configuration(config.configfile)
                # Prevent any change on plugins list..
                new_config.temboard['plugins'] = config.temboard['plugins']
                new_config.plugins = load_plugins_configurations(new_config)
                # New RequestHandler using the new configuration.
                httpd.RequestHandlerClass = handleRequestsUsing(
                    commands, queue_in, new_config, sessions)
                del logger
                # ... and re-create a new one with the new
                # configuration.
                set_logger_name("httpd")
                logger = get_logger(new_config)
                logger.info("Done.")
            except (ConfigurationError, ImportError) as e:
                logger.traceback(get_tb())
                logger.error(str(e))
                logger.info("Keeping previous configuration.")
            # Reset the global var indicating a SIGHUP signal.
            set_global_reload(False)
示例#8
0
def api_function_wrapper_pg(config, http_context, sessions, module, function_name):
    """
    API function wrapper in charge of:
        - instanciate a new logger;
        - check the user session id;
        - start a new PostgreSQL connexion;
        - call a function named 'function_name' from 'module_name' module and return its result;
        - close the PG connexion.
    """
    logger = get_logger(config)
    logger.debug("Calling %s.%s()." % (module.__name__, function_name,))
    logger.debug(http_context)

    try:
        username = check_sessionid(http_context['headers'], sessions)
        http_context['username'] = username
        conn = connector(
            host = config.postgresql['host'],
            port = config.postgresql['port'],
            user = config.postgresql['user'],
            password = config.postgresql['password'],
            database = config.postgresql['dbname']
        )
        conn.connect()
        dm = getattr(module, function_name)(conn, config, http_context)
        conn.close()
        logger.debug("Done.")
        return dm

    except (error, Exception, HTTPError) as e:
        logger.traceback(get_tb())
        logger.error(str(e))
        logger.debug("Failed.")
        try:
            conn.close()
        except Exception:
            pass
        if isinstance(e, HTTPError):
            raise e
        else:
            raise HTTPError(500, "Internal error.")
示例#9
0
def dashboard_collector_worker(commands, command, config):
    try:
        signal.signal(signal.SIGTERM, dashboard_worker_sigterm_handler)
        start_time = time.time() * 1000
        set_logger_name("dashboard_collector")
        logger = get_logger(config)
        logger.debug("Starting with pid=%s" % (getpid()))
        logger.debug("commandid=%s" % (command.commandid))
        command.state = COMMAND_START
        command.time = time.time()
        command.pid = getpid()
        commands.update(command)

        conn = connector(host=config.postgresql['host'],
                         port=config.postgresql['port'],
                         user=config.postgresql['user'],
                         password=config.postgresql['password'],
                         database=config.postgresql['dbname'])
        conn.connect()
        db_metrics = metrics.get_metrics(conn, config)
        # We don't want to store notifications in the history.
        db_metrics.pop('notifications', None)

        conn.close()
        q = Queue('%s/dashboard.q' % (config.temboard['home']),
                  max_length=(config.plugins['dashboard']['history_length'] +
                              1),
                  overflow_mode='slide')
        q.push(Message(content=json.dumps(db_metrics)))
        logger.debug("Duration: %s." % (str(time.time() * 1000 - start_time)))
        logger.debug("Done.")
    except (error, Exception) as e:
        logger.traceback(get_tb())
        logger.error(str(e))
        logger.debug("Failed.")
        try:
            conn.close()
        except Exception:
            pass
        sys.exit(1)
示例#10
0
def load_plugins_configurations(config):
    """
    Intend to load plugins and run their configuration() function.
    Plugins are defined as a module located in plugins/ directory. The list
    of plugins to load is set into temboard section of the configuration file:
        [temboard]
        plugins = [ "plugin1", "plugin2" ]
    """

    # Get this module's path.
    path = os.path.dirname(__file__)
    ret = dict()
    # Get the logger.
    logger = get_logger(config)
    # PostgreSQL version
    pg_version = 0

    while pg_version == 0:
        try:
            conn = connector(
                host = config.postgresql['host'],
                port = config.postgresql['port'],
                user = config.postgresql['user'],
                password = config.postgresql['password'],
                database = config.postgresql['dbname']
            )
            """ Trying to get PostgreSQL version number. """
            conn.connect()
            pg_version = conn.get_pg_version()
            conn.close()
        except Exception as e:
            logger.traceback(get_tb())
            logger.error(str(e))
            logger.error("Not able to get PostgreSQL version number.")
            try:
                conn.close()
            except Exception:
                pass

        # If we reach this point, PostgreSQL is not available, so we
        # wait 5 seconds and try again
        if pg_version == 0:
            time.sleep(5)

    # Loop through each plugin listed in the configuration file.
    for plugin_name in config.temboard['plugins']:
        logger.info("Loading plugin '%s'." % (plugin_name,))
        try:
            # Loading compat.py file
            fp_s, pathname_s, description_s = imp.find_module('compat', [path + '/plugins/'+plugin_name])
            module_compat = imp.load_module('compat', fp_s, pathname_s, description_s)
            # Check modules's PG_MIN_VERSION
            try:
                if (module_compat.PG_MIN_VERSION > pg_version):
                    # Version not supported
                    logger.error("PostgreSQL version (%s) is not supported (min:%s)."
                                    % (pg_version, module_compat.PG_MIN_VERSION))
                    logger.info("Failed.")
                    continue
            except ValueError as e:
                # PG_MIN_VERSION not set
                pass
        except Exception as e:
            if fp_s:
                fp_s.close()
            logger.info("Not able to load the compatibility file: compat.py.")
        logger.info("Done.")
        try:
            # Locate and load the module with imp.
            fp, pathname, description = imp.find_module(plugin_name, [path + '/plugins'])
            module = imp.load_module(plugin_name, fp, pathname, description)
            # Try to run module's configuration() function.
            logger.info("Loading plugin '%s' configuration." % (plugin_name))
            plugin_configuration = getattr(module, 'configuration')(config)
            ret.update({module.__name__: plugin_configuration})
            logger.info("Done.")
        except AttributeError as e:
            logger.info("No configuration.")
        except Exception as e:
            if fp:
                fp.close()
            logger.traceback(get_tb())
            logger.error(str(e))
            logger.info("Failed.")

    return ret
示例#11
0
def post_pg_control(http_context, queue_in = None, config = None, sessions = None, commands = None):
    # NOTE: in this case we don't want to use api functions wrapper, it leads
    # to "Broken pipe" error with debian init.d on start/restart. This is
    # probably due to getattr() call.
    set_logger_name("administration")
    # Get a new logger.
    logger = get_logger(config)
    post = http_context['post']

    try:
        check_sessionid(http_context['headers'], sessions)
        # Check POST parameters.
        validate_parameters(post, [
            ('action', T_CONTROL, False)
        ])
        session = sessions.get_by_sessionid(http_context['headers']['X-Session'].encode('utf-8'))
    except (Exception, HTTPError) as e:
        logger.traceback(get_bt())
        logger.error(str(e))
        logger.debug(http_context)
        if isinstance(e, HTTPError):
            raise e
        else:
            raise HTTPError(500, "Internal error.")

    try:
        NotificationMgmt.push(config, Notification(
                                        username = session.username,
                                        message = "PostgreSQL %s" % (post['action'])))
    except (NotificationError, Exception) as e:
        logger.traceback(get_tb())
        logger.error(str(e))

    try:
        logger.info("PostgreSQL '%s' requested." % (post['action']))
        cmd_args = oneline_cmd_to_array(config.plugins['administration']['pg_ctl'] % (post['action']))
        (rcode, stdout, stderr) = exec_script(cmd_args)
        if rcode != 0:
            raise Exception(str(stderr))
        # Let's check if postgresql is up & running on 'start' or 'restart' action.
        if post['action'] in ['start', 'restart']:
            conn = connector(
                host = config.postgresql['host'],
                port = config.postgresql['port'],
                user = config.postgresql['user'],
                password = config.postgresql['password'],
                database = config.postgresql['dbname']
            )
            # When a start/restart operation is requested, after the startup/pg_ctl
            # script is executed we check that postgres is up & running: while the
            # PG connection is not working, during 10 seconds (max) we'll check
            # (connect/SELECT 1/disconnect) the connection, every 0.5 second.
            retry = True
            t_start = time.time()
            while retry:
                try:
                    conn.connect()
                    conn.execute('SELECT 1')
                    conn.close()
                    logger.info("Done.")
                    return {'action': post['action'], 'state': 'ok'}
                except error as e:
                    if (time.time() - t_start) > 10:
                        try:
                            conn.close()
                        except error as e:
                            pass
                        except Exception:
                            pass
                        logger.info("Failed.")
                        return {'action': post['action'], 'state': 'ko'}
                time.sleep(0.5)

        elif post['action'] == 'stop':
            conn = connector(
                host = config.postgresql['host'],
                port = config.postgresql['port'],
                user = config.postgresql['user'],
                password = config.postgresql['password'],
                database = config.postgresql['dbname']
            )
            # Check the PG conn is not working anymore.
            try:
                retry = True
                t_start = time.time()
                while retry:
                    conn.connect()
                    conn.execute('SELECT 1')
                    conn.close()
                    time.sleep(0.5)
                    if (time.time() - t_start) > 10:
                        retry = False
                logger.info("Failed.")
                return {'action': post['action'], 'state': 'ko'}
            except error as e:
                logger.info("Done.")
                return {'action': post['action'], 'state': 'ok'}
        logger.info("Done.")
        return {'action': post['action'], 'state': 'ok'}
    except (Exception, error, HTTPError) as e:
        logger.traceback(get_tb())
        logger.error(str(e))
        logger.info("Failed")
        if isinstance(e, HTTPError):
            raise e
        else:
            raise HTTPError(500, "Internal error.") 
示例#12
0
文件: async.py 项目: segmond/temboard
def Scheduler(commands, queue_in, config, sessions):
    """
    Asynchronous command scheduler in charge of:
        - fetching new async command from the command queue.
        - if any new command, starting a new worker process.
        - doing maintenance tasks like sessions and commands clean-up.
        - executing function named scheduler() from each loaded plugins. 
    """
    set_logger_name("scheduler")
    logger = get_logger(config)

    # Add a signal handler on SIGTERM and SIGHUP signals.
    signal.signal(signal.SIGTERM, scheduler_sigterm_handler)
    signal.signal(signal.SIGHUP, scheduler_sighup_handler)

    logger.debug("Starting with pid=%s", (getpid()))
    workers = []
    while True:
        if reload_true():
            # SIGHUP signal caught.
            try:
                logger.info("SIGHUP signal caught, trying to reload"
                            " configuration.")
                new_config =  Configuration(config.configfile)
                # Prevent any change on plugins list..
                new_config.temboard['plugins'] = config.temboard['plugins']
                new_config.plugins = load_plugins_configurations(new_config)
                # Logger re-creation.
                del logger
                set_logger_name("scheduler")
                logger = get_logger(new_config)
                config = new_config
                logger.info("New configuration loaded.")
            except (ConfigurationError, ImportError) as e:
                logger.traceback(get_tb())
                logger.error(str(e))
                logger.info("Some error occured, keeping old configuration.")

            set_global_reload(False)

        try:
            # Fetch one new input from the command queue.
            # There is a 0.5s second timeout and the call isn't blocking.
            command = queue_in.get(True, 0.5)
        except Exception:
            # No new command.
            pass
        else:
            # Start the worker process.
            newworker = Process(target=Worker, args=(commands, command, config))
            workers.append(newworker)
            newworker.start()

        # Check that worker processes are still alive.
        for worker in workers:
            if not worker.is_alive():
                worker.join()
                workers.remove(worker)

        # Let store workers in a global var.
        set_global_workers(workers) 
        # Execute plugins scheduler() function.
        exec_scheduler(queue_in, config, commands, logger)
        # Purge expired sessions if any.
        sessions.purge_expired(3600, logger, config)
        # Remove old unchecked commands. 
        commands.purge_expired(60, logger)
示例#13
0
def login(http_context,
          queue_in=None,
          config=None,
          sessions=None,
          commands=None):
    """
    @api {get} /login User login
    @apiVersion 0.0.1
    @apiName UserLogin
    @apiGroup User

    @apiParam {String} username Username.
    @apiParam {String} password Password.

    @apiSuccess {String} sessions Session ID.

    @apiExample {curl} Example usage:
        curl -k -X POST -H "Content-Type: application/json" -d '{"username": "******", "password": "******"}' \
            https://localhost:2345/login

    @apiSuccessExample Success-Reponse:
        HTTP/1.0 200 OK
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:19:48 GMT
        Content-type: application/json

        {"session": "fa452548403ac53f2158a65f5eb6db9723d2b07238dd83f5b6d9ca52ce817b63"}

    @apiError (500 error) error Internal error.
    @apiError (404 error) error Invalid username or password.
    @apiError (406 error) error Username or password malformed or missing.

    @apiErrorExample 404 error example
        HTTP/1.0 404 Not Found
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:20:33 GMT
        Content-type: application/json

        {"error": "Invalid username/password."}

    @apiErrorExample 406 error example
        HTTP/1.0 406 Not Acceptable
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:21:01 GMT
        Content-type: application/json

        {"error": "Parameter 'password' is malformed."}
    """
    post = http_context['post']
    set_logger_name("api")
    logger = get_logger(config)
    # Add an unconditional sleeping time to reduce brute-force risks
    time.sleep(1)

    logger.info("Authenticating user: %s" % (post['username']))
    try:
        validate_parameters(post, [('username', T_USERNAME, False),
                                   ('password', T_PASSWORD, False)])
        auth_user(config.temboard['users'], post['username'], post['password'])
    except HTTPError as e:
        logger.traceback(get_tb())
        logger.error(e.message)
        logger.info("Authentication failed.")
        raise e
    try:
        session = sessions.get_by_username(post['username'])
        if not session:
            sessionid = gen_sessionid(post['username'])
            session = Session(sessionid.encode('utf-8'), time.time(),
                              post['username'].encode('utf-8'))
            sessions.add(session)
        else:
            sessionid = session.sessionid
            session.time = time.time()
            sessions.update(session)
        try:
            NotificationMgmt.push(
                config, Notification(username=post['username'],
                                     message="Login"))
        except NotificationError as e:
            logger.traceback(get_tb())
            logger.error(e.message)

    except (SharedItem_exists, SharedItem_no_free_slot_left) as e:
        logger.traceback(get_tb())
        logger.error(e.message)
        raise HTTPError(500, "Internal error.")
    return {'session': sessionid}
示例#14
0
def notifications(http_context,
                  queue_in=None,
                  config=None,
                  sessions=None,
                  commands=None):
    """
    @api {get} /notifications Get all notifications.
    @apiVersion 0.0.1
    @apiName Notifications
    @apiGroup User

    @apiHeader {String} X-Session Session ID.

    @apiSuccess {Object[]} notifications List of notifications.
    @apiSuccess {String}   notifications.date Notification datetime.
    @apiSuccess {String}   notifications.username Username.
    @apiSuccess {String}   notifications.message Message.

    @apiExample {curl} Example usage:
        curl -k -H "X-Session: fa452548403ac53f2158a65f5eb6db9723d2b07238dd83f5b6d9ca52ce817b63" https://localhost:2345/notifications

    @apiSuccessExample Success-Reponse:
        HTTP/1.0 200 OK
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:33:19 GMT
        Content-type: application/json

        [
            {"date": "2016-04-11T16:12:38", "username": "******", "message": "Login"},
            {"date": "2016-04-11T16:02:03", "username": "******", "message": "Login"},
            {"date": "2016-04-11T15:51:15", "username": "******", "message": "HBA file version '2016-04-11T15:32:53' removed."},
            {"date": "2016-04-11T15:51:10", "username": "******", "message": "HBA file version '2016-04-11T15:47:26' removed."},
            {"date": "2016-04-11T15:51:04", "username": "******", "message": "HBA file version '2016-04-11T15:48:50' removed."},
            {"date": "2016-04-11T15:50:57", "username": "******", "message": "PostgreSQL reload"},
            {"date": "2016-04-11T15:50:57", "username": "******", "message": "HBA file updated"},
            {"date": "2016-04-11T15:48:50", "username": "******", "message": "PostgreSQL reload"}
        ]

    @apiError (500 error) error Internal error.
    @apiError (401 error) error Invalid session ID.
    @apiError (406 error) error Session ID malformed.

    @apiErrorExample 401 error example
        HTTP/1.0 401 Unauthorized
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:36:33 GMT
        Content-type: application/json

        {"error": "Invalid session."}

    @apiErrorExample 406 error example
        HTTP/1.0 406 Not Acceptable
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:37:23 GMT
        Content-type: application/json

        {"error": "Parameter 'X-Session' is malformed."}
    """
    headers = http_context['headers']
    set_logger_name("api")
    logger = get_logger(config)
    logger.info("Get notifications.")
    try:
        username = check_sessionid(headers, sessions)
    except HTTPError as e:
        logger.traceback(get_tb())
        logger.error(e.message)
        logger.info("Invalid session.")
        raise e

    try:
        notifications = NotificationMgmt.get_last_n(config, -1)
        logger.info("Done.")
        return list(notifications)
    except (NotificationError, Exception) as e:
        logger.traceback(get_tb())
        logger.error(e.message)
        logger.info("Failed.")
        raise HTTPError(500, "Internal error.")
示例#15
0
def instance_info(conninfo, hostname):
    """Gather PostgreSQL instance information."""
    instance_info = {
        'hostname': hostname,
        'instance': conninfo['instance'],
        'local_name': conninfo.get('local_name', conninfo['instance']),
        'available': True,
        'host': conninfo['host'],
        'port': conninfo['port'],
        'user': conninfo['user'],
        'database': conninfo['database'],
        'password': conninfo['password']
    }

    # Try the connection
    conn = connector(conninfo['host'], conninfo['port'], conninfo['user'],
                     conninfo['password'], conninfo['database'])
    try:
        conn.connect()
        # Get PostgreSQL informations using PgInfo
        pginfo = PgInfo(conn)
        pgv = pginfo.version()
        # Gather the info while where are connected
        instance_info['version_num'] = pgv['num']
        instance_info['version'] = pgv['server']
        instance_info['data_directory'] = pginfo.setting('data_directory')

        # hot standby is available from 9.0
        instance_info['standby'] = pginfo.is_in_recovery()

        # Grab the list of tablespaces
        instance_info['tablespaces'] = pginfo.tablespaces(
            instance_info['data_directory'])

        # When the user has not given a dbnames list or '*' in the
        # configuration file, we must get the list of databases. Since
        # we have a working connection, let's do it now.
        dbs = pginfo.databases()
        instance_info['dbnames'] = []
        for db in conninfo['dbnames']:
            if db == '*':
                instance_info['dbnames'] = dbs.values()
                break
            if db in dbs.keys():
                instance_info['dbnames'].append(dbs[db])
        conn.close()

        # Now that we have the data_directory, find the owner
        try:
            statinfo = os.stat(instance_info['data_directory'])
            instance_info['sysuser'] = pwd.getpwuid(statinfo.st_uid).pw_name
        except OSError as e:
            logging.warning("Unable to get the owner of PGDATA: %s", str(e))
            instance_info['sysuser'] = None

    except error as e:
        logging.error(get_tb())
        logging.error(str(e))
        logging.warning("Unable to gather information for cluster \"%s\"",
                        conninfo['instance'])
        instance_info['available'] = False

    return instance_info
示例#16
0
def profile(http_context,
            queue_in=None,
            config=None,
            sessions=None,
            commands=None):
    """
    @api {get} /profile Get current user name.
    @apiVersion 0.0.1
    @apiName Profile
    @apiGroup User

    @apiHeader {String} X-Session Session ID.

    @apiSuccess {String} username Username.

    @apiExample {curl} Example usage:
        curl -k -H "X-Session: fa452548403ac53f2158a65f5eb6db9723d2b07238dd83f5b6d9ca52ce817b63" https://localhost:2345/profile

    @apiSuccessExample Success-Reponse:
        HTTP/1.0 200 OK
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:33:19 GMT
        Content-type: application/json
        {
            "username": "******"
        }

    @apiError (500 error) error Internal error.
    @apiError (401 error) error Invalid session ID.
    @apiError (406 error) error Session ID malformed.

    @apiErrorExample 401 error example
        HTTP/1.0 401 Unauthorized
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:36:33 GMT
        Content-type: application/json

        {"error": "Invalid session."}

    @apiErrorExample 406 error example
        HTTP/1.0 406 Not Acceptable
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:37:23 GMT
        Content-type: application/json

        {"error": "Parameter 'X-Session' is malformed."}
    """
    headers = http_context['headers']
    set_logger_name("api")
    logger = get_logger(config)
    logger.info("Get user profile.")
    try:
        check_sessionid(headers, sessions)
    except HTTPError as e:
        logger.traceback(get_tb())
        logger.error(e.message)
        logger.info("Invalid session.")
        raise e
    try:
        session = sessions.get_by_sessionid(
            headers['X-Session'].encode('utf-8'))
        logger.info("Done.")
        return {'username': session.username}
    except SharedItem_not_found as e:
        logger.traceback(get_tb())
        logger.error(e.message)
        logger.info("Failed.")
        raise HTTPError(401, "Invalid session.")
示例#17
0
def get_discover(http_contexte,
                 queue_in=None,
                 config=None,
                 sessions=None,
                 commands=None):
    """
    @api {get} /discover Get global informations about the env.
    @apiVersion 0.0.1
    @apiName Discover
    @apiGroup User

    @apiSuccess {String}   hostname Hostname.
    @apiSuccess {String}   pg_data PostgreSQL data directory.
    @apiSuccess {Number}   pg_port PostgreSQL listen port.
    @apiSuccess {String}   pg_version PostgreSQL version.
    @apiSuccess {String[]} plugins List or available plugins.
    @apiSuccess {Number}   memory_size Memory size (bytes).
    @apiSuccess {Number}   cpu Number of CPU.

    @apiExample {curl} Example usage:
        curl -k https://localhost:2345/discover

    @apiSuccessExample Success-Reponse:
        HTTP/1.0 200 OK
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:33:19 GMT
        Content-type: application/json
        {
            "hostname": "neptune",
            "pg_data": "/var/lib/postgresql/9.4/main",
            "pg_port": 5432,
            "plugins": ["supervision", "dashboard", "settings", "administration", "activity"],
            "memory_size": 8241508352,
            "pg_version": "PostgreSQL 9.4.5 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu 4.9.2-10ubuntu13) 4.9.2, 64-bit",
            "cpu": 4
        }

    @apiError (500 error) error Internal error.
    """
    set_logger_name("api")
    logger = get_logger(config)
    conn = connector(host=config.postgresql['host'],
                     port=config.postgresql['port'],
                     user=config.postgresql['user'],
                     password=config.postgresql['password'],
                     database=config.postgresql['dbname'])
    logger.info('Starting discovery.')
    try:
        conn.connect()
        sysinfo = SysInfo()
        pginfo = PgInfo(conn)
        ret = {
            'hostname': sysinfo.hostname(config.temboard['hostname']),
            'cpu': sysinfo.n_cpu(),
            'memory_size': sysinfo.memory_size(),
            'pg_port': pginfo.setting('port'),
            'pg_version': pginfo.version()['full'],
            'pg_data': pginfo.setting('data_directory'),
            'plugins':
            [plugin_name for plugin_name in config.temboard['plugins']]
        }
        conn.close()
        logger.info('Discovery done.')
        return ret

    except (error, Exception, HTTPError) as e:
        logger.traceback(get_tb())
        logger.error(str(e))
        logger.info('Discovery failed.')
        try:
            conn.close()
        except Exception:
            pass
        if isinstance(e, HTTPError):
            raise e
        else:
            raise HTTPError(500, "Internal error.")
示例#18
0
def logout(http_context,
           queue_in=None,
           config=None,
           sessions=None,
           commands=None):
    """
    @api {get} /logout User logout
    @apiVersion 0.0.1
    @apiName UserLogout
    @apiGroup User

    @apiHeader {String} X-Session Session ID.

    @apiSuccess {Bool} logout True if logout succeeds.

    @apiExample {curl} Example usage:
        curl -k -H "X-Session: fa452548403ac53f2158a65f5eb6db9723d2b07238dd83f5b6d9ca52ce817b63" https://localhost:2345/logout

    @apiSuccessExample Success-Reponse:
        HTTP/1.0 200 OK
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:33:19 GMT
        Content-type: application/json

        {"logout": true}

    @apiError (500 error) error Internal error.
    @apiError (401 error) error Invalid session ID.
    @apiError (406 error) error Session ID malformed.

    @apiErrorExample 401 error example
        HTTP/1.0 401 Unauthorized
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:36:33 GMT
        Content-type: application/json

        {"error": "Invalid session."}

    @apiErrorExample 406 error example
        HTTP/1.0 406 Not Acceptable
        Server: temboard-agent/0.0.1 Python/2.7.8
        Date: Wed, 22 Apr 2015 12:37:23 GMT
        Content-type: application/json

        {"error": "Parameter 'X-Session' is malformed."}
    """
    headers = http_context['headers']
    set_logger_name("api")
    logger = get_logger(config)
    logger.info("Removing session: %s" % (headers['X-Session']))
    try:
        username = check_sessionid(headers, sessions)
    except HTTPError as e:
        logger.traceback(get_tb())
        logger.error(e.message)
        logger.info("Invalid session.")
        raise e

    try:
        NotificationMgmt.push(
            config, Notification(username=username, message="Logout"))
    except NotificationError as e:
        logger.traceback(get_tb())
        logger.error(e.message)

    try:
        sessions.delete(headers['X-Session'].encode('utf-8'))
    except (SharedItem_exists, SharedItem_no_free_slot_left) as e:
        logger.traceback(get_tb())
        logger.error(e.message)
        raise HTTPError(500, "Internal error.")
    return {'logout': True}
示例#19
0
def supervision_collector_worker(commands, command, config):
    """
    Run probes and push collected metrics in a queue.
    """
    signal.signal(signal.SIGTERM, supervision_worker_sigterm_handler)

    start_time = time.time() * 1000
    set_logger_name("supervision_collector_worker")
    logger = get_logger(config)
    # TODO: logging methods in supervision plugin must be aligned.
    logging.root = logger
    logger.debug("Starting with pid=%s" % (os.getpid()))
    logger.debug("commandid=%s" % (command.commandid))
    command.state = COMMAND_START
    command.time = time.time()

    try:
        command.pid = os.getpid()
        commands.update(command)
        system_info = host_info(config.temboard['hostname'])
    except (ValueError, Exception) as e:
        logger.traceback(get_tb())
        logger.error(str(e))
        logger.debug("Failed.")
        sys.exit(1)

# Load the probes to run
    try:
        probes = load_probes(config.plugins['supervision'],
                             config.temboard['home'])
        config.plugins['supervision']['conninfo'] = [{
            'host':
            config.postgresql['host'],
            'port':
            config.postgresql['port'],
            'user':
            config.postgresql['user'],
            'database':
            config.postgresql['dbname'],
            'password':
            config.postgresql['password'],
            'dbnames':
            config.plugins['supervision']['dbnames'],
            'instance':
            config.postgresql['instance']
        }]

        # Validate connection information from the config, and ensure
        # the instance is available
        instances = []
        for conninfo in config.plugins['supervision']['conninfo']:
            logging.debug("Validate connection information on instance \"%s\"",
                          conninfo['instance'])
            instances.append(instance_info(conninfo, system_info['hostname']))

        # Gather the data from probes
        data = run_probes(probes, instances)

        # Prepare and send output
        output = {
            'datetime': now(),
            'hostinfo': system_info,
            'instances': remove_passwords(instances),
            'data': data,
            'version': __VERSION__
        }
        logger.debug("Collected data: %s" % (output))
        q = Queue('%s/metrics.q' % (config.temboard['home']),
                  max_size=1024 * 1024 * 10,
                  overflow_mode='slide')
        q.push(Message(content=json.dumps(output)))
    except Exception as e:
        logger.traceback(get_tb())
        logger.error(str(e))
        logger.debug("Failed.")
        sys.exit(1)

    logger.debug("Duration: %s." % (str(time.time() * 1000 - start_time)))
    logger.debug("Done.")