Separate Monitor management to its own file
Allows better separation of file local data. Also allows moving monitor- related code from config_runtime.cc.
This commit is contained in:
		@ -79,6 +79,8 @@ extern const char CN_MONITOR_INTERVAL[];
 | 
			
		||||
extern const char CN_SCRIPT[];
 | 
			
		||||
extern const char CN_SCRIPT_TIMEOUT[];
 | 
			
		||||
 | 
			
		||||
json_t* monitor_json_data(const mxs::Monitor* monitor, const char* host);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The monitor API version number. Any change to the monitor module API
 | 
			
		||||
 * must change these versions using the rules defined in modinfo.h
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,7 @@ add_library(maxscale-common SHARED
 | 
			
		||||
  modulecmd.cc
 | 
			
		||||
  modutil.cc
 | 
			
		||||
  monitor.cc
 | 
			
		||||
  monitormanager.cc
 | 
			
		||||
  mysql_binlog.cc
 | 
			
		||||
  mysql_utils.cc
 | 
			
		||||
  paths.cc
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@
 | 
			
		||||
#include <maxscale/monitor.hh>
 | 
			
		||||
#include <maxscale/resultset.hh>
 | 
			
		||||
#include "externcmd.hh"
 | 
			
		||||
#include "monitormanager.hh"
 | 
			
		||||
 | 
			
		||||
#define MON_ARG_MAX 8192
 | 
			
		||||
 | 
			
		||||
@ -49,132 +50,6 @@ static const MXS_ENUM_VALUE mxs_monitor_event_enum_values[] =
 | 
			
		||||
    {NULL}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class contains internal monitor management functions that should not be exposed in the public
 | 
			
		||||
 * monitor class. It's a friend of MXS_MONITOR.
 | 
			
		||||
 */
 | 
			
		||||
class MonitorManager
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new monitor. Loads the module, calls constructor and configure, and adds monitor to the
 | 
			
		||||
     * global list.
 | 
			
		||||
     *
 | 
			
		||||
     * @param name          The configuration name of the monitor
 | 
			
		||||
     * @param module        The module name to load
 | 
			
		||||
     * @return              The newly created monitor, or NULL on error
 | 
			
		||||
     */
 | 
			
		||||
    static mxs::Monitor* create_monitor(const std::string& name, const std::string& module,
 | 
			
		||||
                                        MXS_CONFIG_PARAMETER* params);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Mark monitor as deactivated. A deactivated monitor appears not to exist, as if it had been
 | 
			
		||||
     * destroyed. Any servers the monitor had are removed. The monitor should not be serialized after
 | 
			
		||||
     * this function.
 | 
			
		||||
     *
 | 
			
		||||
     * @param monitor Monitor to deactivate
 | 
			
		||||
     */
 | 
			
		||||
    static void deactivate_monitor(mxs::Monitor* monitor);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Destroys all monitors. At this point all monitors should
 | 
			
		||||
     *        have been stopped.
 | 
			
		||||
     *
 | 
			
		||||
     * @attn Must only be called in single-thread context at system shutdown.
 | 
			
		||||
     */
 | 
			
		||||
    static void destroy_all_monitors();
 | 
			
		||||
 | 
			
		||||
    static void start_monitor(mxs::Monitor* monitor);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Stop a given monitor
 | 
			
		||||
     *
 | 
			
		||||
     * @param monitor The monitor to stop
 | 
			
		||||
     */
 | 
			
		||||
    static void stop_monitor(mxs::Monitor* monitor);
 | 
			
		||||
 | 
			
		||||
    static void stop_all_monitors();
 | 
			
		||||
    static void start_all_monitors();
 | 
			
		||||
 | 
			
		||||
    static mxs::Monitor* find_monitor(const char* name);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Populate services with the servers of the monitors.
 | 
			
		||||
     */
 | 
			
		||||
    static void populate_services();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get links to monitors that relate to a server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param server Server to inspect
 | 
			
		||||
     * @param host   Hostname of this server
 | 
			
		||||
     * @return Array of monitor links or NULL if no relations exist
 | 
			
		||||
     */
 | 
			
		||||
    static json_t* monitor_relations_to_server(const SERVER* server, const char* host);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert all monitors to JSON.
 | 
			
		||||
     *
 | 
			
		||||
     * @param host    Hostname of this server
 | 
			
		||||
     * @return JSON array containing all monitors
 | 
			
		||||
     */
 | 
			
		||||
    static json_t* monitor_list_to_json(const char* host);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a server is being monitored and return the monitor.
 | 
			
		||||
     * @param server Server that is queried
 | 
			
		||||
     * @return The monitor watching this server, or NULL if not monitored
 | 
			
		||||
     */
 | 
			
		||||
    static mxs::Monitor* server_is_monitored(const SERVER* server);
 | 
			
		||||
 | 
			
		||||
    static void show_all_monitors(DCB* dcb);
 | 
			
		||||
    static void monitor_show(DCB* dcb, mxs::Monitor* monitor);
 | 
			
		||||
 | 
			
		||||
    static void monitor_list(DCB*);
 | 
			
		||||
 | 
			
		||||
    static std::unique_ptr<ResultSet> monitor_get_list();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Serialize a monitor to a file
 | 
			
		||||
     *
 | 
			
		||||
     * This converts the static configuration of the monitor into an INI format file.
 | 
			
		||||
     *
 | 
			
		||||
     * @param monitor Monitor to serialize
 | 
			
		||||
     * @return True if serialization was successful
 | 
			
		||||
     */
 | 
			
		||||
    static bool monitor_serialize(const mxs::Monitor* monitor);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Attempt to reconfigure a monitor
 | 
			
		||||
     *
 | 
			
		||||
     * If the configuration fails, the old parameters are restored.
 | 
			
		||||
     *
 | 
			
		||||
     * @param monitor    Monitor to reconfigure
 | 
			
		||||
     * @param parameters New parameters to apply
 | 
			
		||||
     *
 | 
			
		||||
     * @return True if reconfiguration was successful
 | 
			
		||||
     */
 | 
			
		||||
    static bool reconfigure_monitor(mxs::Monitor* monitor, const MXS_CONFIG_PARAMETER& parameters);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Convert monitor to JSON
 | 
			
		||||
     *
 | 
			
		||||
     * @param monitor Monitor to convert
 | 
			
		||||
     * @param host    Hostname of this server
 | 
			
		||||
     *
 | 
			
		||||
     * @return JSON representation of the monitor
 | 
			
		||||
     */
 | 
			
		||||
    static json_t* monitor_to_json(const mxs::Monitor* monitor, const char* host);
 | 
			
		||||
 | 
			
		||||
    static bool create_monitor_config(const mxs::Monitor* monitor, const char* filename);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Waits until all running monitors have advanced one tick.
 | 
			
		||||
     */
 | 
			
		||||
    static void debug_wait_one_tick();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// RAII helper class for temprarily stopping monitors
 | 
			
		||||
class MonitorStop
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										141
									
								
								server/core/internal/monitormanager.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								server/core/internal/monitormanager.hh
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,141 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2019 MariaDB Corporation Ab
 | 
			
		||||
 *
 | 
			
		||||
 * Use of this software is governed by the Business Source License included
 | 
			
		||||
 * in the LICENSE.TXT file and at www.mariadb.com/bsl11.
 | 
			
		||||
 *
 | 
			
		||||
 * Change Date: 2023-01-01
 | 
			
		||||
 *
 | 
			
		||||
 * On the date above, in accordance with the Business Source License, use
 | 
			
		||||
 * of this software will be governed by version 2 or later of the General
 | 
			
		||||
 * Public License.
 | 
			
		||||
 */
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <maxscale/monitor.hh>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class contains internal monitor management functions that should not be exposed in the public
 | 
			
		||||
 * monitor class. It's a friend of MXS_MONITOR.
 | 
			
		||||
 */
 | 
			
		||||
class MonitorManager
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new monitor. Loads the module, calls constructor and configure, and adds monitor to the
 | 
			
		||||
     * global list.
 | 
			
		||||
     *
 | 
			
		||||
     * @param name          The configuration name of the monitor
 | 
			
		||||
     * @param module        The module name to load
 | 
			
		||||
     * @return              The newly created monitor, or NULL on error
 | 
			
		||||
     */
 | 
			
		||||
    static mxs::Monitor* create_monitor(const std::string& name, const std::string& module,
 | 
			
		||||
                                        MXS_CONFIG_PARAMETER* params);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Mark monitor as deactivated. A deactivated monitor appears not to exist, as if it had been
 | 
			
		||||
     * destroyed. Any servers the monitor had are removed. The monitor should not be serialized after
 | 
			
		||||
     * this function.
 | 
			
		||||
     *
 | 
			
		||||
     * @param monitor Monitor to deactivate
 | 
			
		||||
     */
 | 
			
		||||
    static void deactivate_monitor(mxs::Monitor* monitor);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Destroys all monitors. At this point all monitors should
 | 
			
		||||
     *        have been stopped.
 | 
			
		||||
     *
 | 
			
		||||
     * @attn Must only be called in single-thread context at system shutdown.
 | 
			
		||||
     */
 | 
			
		||||
    static void destroy_all_monitors();
 | 
			
		||||
 | 
			
		||||
    static void start_monitor(mxs::Monitor* monitor);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Stop a given monitor
 | 
			
		||||
     *
 | 
			
		||||
     * @param monitor The monitor to stop
 | 
			
		||||
     */
 | 
			
		||||
    static void stop_monitor(mxs::Monitor* monitor);
 | 
			
		||||
 | 
			
		||||
    static void stop_all_monitors();
 | 
			
		||||
    static void start_all_monitors();
 | 
			
		||||
 | 
			
		||||
    static mxs::Monitor* find_monitor(const char* name);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Populate services with the servers of the monitors.
 | 
			
		||||
     */
 | 
			
		||||
    static void populate_services();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get links to monitors that relate to a server.
 | 
			
		||||
     *
 | 
			
		||||
     * @param server Server to inspect
 | 
			
		||||
     * @param host   Hostname of this server
 | 
			
		||||
     * @return Array of monitor links or NULL if no relations exist
 | 
			
		||||
     */
 | 
			
		||||
    static json_t* monitor_relations_to_server(const SERVER* server, const char* host);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert all monitors to JSON.
 | 
			
		||||
     *
 | 
			
		||||
     * @param host    Hostname of this server
 | 
			
		||||
     * @return JSON array containing all monitors
 | 
			
		||||
     */
 | 
			
		||||
    static json_t* monitor_list_to_json(const char* host);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a server is being monitored and return the monitor.
 | 
			
		||||
     * @param server Server that is queried
 | 
			
		||||
     * @return The monitor watching this server, or NULL if not monitored
 | 
			
		||||
     */
 | 
			
		||||
    static mxs::Monitor* server_is_monitored(const SERVER* server);
 | 
			
		||||
 | 
			
		||||
    static void show_all_monitors(DCB* dcb);
 | 
			
		||||
    static void monitor_show(DCB* dcb, mxs::Monitor* monitor);
 | 
			
		||||
 | 
			
		||||
    static void monitor_list(DCB*);
 | 
			
		||||
 | 
			
		||||
    static std::unique_ptr<ResultSet> monitor_get_list();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Serialize a monitor to a file
 | 
			
		||||
     *
 | 
			
		||||
     * This converts the static configuration of the monitor into an INI format file.
 | 
			
		||||
     *
 | 
			
		||||
     * @param monitor Monitor to serialize
 | 
			
		||||
     * @return True if serialization was successful
 | 
			
		||||
     */
 | 
			
		||||
    static bool monitor_serialize(const mxs::Monitor* monitor);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Attempt to reconfigure a monitor
 | 
			
		||||
     *
 | 
			
		||||
     * If the configuration fails, the old parameters are restored.
 | 
			
		||||
     *
 | 
			
		||||
     * @param monitor    Monitor to reconfigure
 | 
			
		||||
     * @param parameters New parameters to apply
 | 
			
		||||
     *
 | 
			
		||||
     * @return True if reconfiguration was successful
 | 
			
		||||
     */
 | 
			
		||||
    static bool reconfigure_monitor(mxs::Monitor* monitor, const MXS_CONFIG_PARAMETER& parameters);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @brief Convert monitor to JSON
 | 
			
		||||
     *
 | 
			
		||||
     * @param monitor Monitor to convert
 | 
			
		||||
     * @param host    Hostname of this server
 | 
			
		||||
     *
 | 
			
		||||
     * @return JSON representation of the monitor
 | 
			
		||||
     */
 | 
			
		||||
    static json_t* monitor_to_json(const mxs::Monitor* monitor, const char* host);
 | 
			
		||||
 | 
			
		||||
    static bool create_monitor_config(const mxs::Monitor* monitor, const char* filename);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Waits until all running monitors have advanced one tick.
 | 
			
		||||
     */
 | 
			
		||||
    static void debug_wait_one_tick();
 | 
			
		||||
};
 | 
			
		||||
@ -87,61 +87,6 @@ const char CN_SCRIPT_TIMEOUT[] = "script_timeout";
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class ThisUnit
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Call a function on every monitor in the global monitor list.
 | 
			
		||||
     *
 | 
			
		||||
     * @param apply The function to apply. If the function returns false, iteration is discontinued.
 | 
			
		||||
     */
 | 
			
		||||
    void foreach_monitor(std::function<bool(Monitor*)> apply)
 | 
			
		||||
    {
 | 
			
		||||
        Guard guard(m_all_monitors_lock);
 | 
			
		||||
        for (Monitor* monitor : m_all_monitors)
 | 
			
		||||
        {
 | 
			
		||||
            if (!apply(monitor))
 | 
			
		||||
            {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clear the internal list and return previous contents.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Contents before clearing
 | 
			
		||||
     */
 | 
			
		||||
    std::vector<Monitor*> clear()
 | 
			
		||||
    {
 | 
			
		||||
        Guard guard(m_all_monitors_lock);
 | 
			
		||||
        return std::move(m_all_monitors);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void insert_front(Monitor* monitor)
 | 
			
		||||
    {
 | 
			
		||||
        Guard guard(m_all_monitors_lock);
 | 
			
		||||
        m_all_monitors.insert(m_all_monitors.begin(), monitor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void move_to_deactivated_list(Monitor *monitor)
 | 
			
		||||
    {
 | 
			
		||||
        Guard guard(m_all_monitors_lock);
 | 
			
		||||
        auto iter = std::find(m_all_monitors.begin(), m_all_monitors.end(), monitor);
 | 
			
		||||
        mxb_assert(iter != m_all_monitors.end());
 | 
			
		||||
        m_all_monitors.erase(iter);
 | 
			
		||||
        m_deact_monitors.push_back(monitor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::mutex m_all_monitors_lock;          /**< Protects access to arrays */
 | 
			
		||||
    std::vector<Monitor*> m_all_monitors;    /**< Global list of monitors, in configuration file order */
 | 
			
		||||
    std::vector<Monitor*> m_deact_monitors;  /**< Deactivated monitors. TODO: delete monitors */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ThisUnit this_unit;
 | 
			
		||||
 | 
			
		||||
const char* monitor_state_to_string(monitor_state_t state)
 | 
			
		||||
{
 | 
			
		||||
    switch (state)
 | 
			
		||||
@ -415,6 +360,8 @@ json_t* monitor_parameters_to_json(const Monitor* monitor)
 | 
			
		||||
    return rval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
json_t* monitor_json_data(const Monitor* monitor, const char* host)
 | 
			
		||||
{
 | 
			
		||||
    json_t* rval = json_object();
 | 
			
		||||
@ -459,394 +406,6 @@ json_t* monitor_json_data(const Monitor* monitor, const char* host)
 | 
			
		||||
    return rval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Monitor* MonitorManager::create_monitor(const string& name, const string& module,
 | 
			
		||||
                                        MXS_CONFIG_PARAMETER* params)
 | 
			
		||||
{
 | 
			
		||||
    MXS_MONITOR_API* api = (MXS_MONITOR_API*)load_module(module.c_str(), MODULE_MONITOR);
 | 
			
		||||
    if (!api)
 | 
			
		||||
    {
 | 
			
		||||
        MXS_ERROR("Unable to load library file for monitor '%s'.", name.c_str());
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Monitor* mon = api->createInstance(name, module);
 | 
			
		||||
    if (!mon)
 | 
			
		||||
    {
 | 
			
		||||
        MXS_ERROR("Unable to create monitor instance for '%s', using module '%s'.",
 | 
			
		||||
                  name.c_str(), module.c_str());
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (mon->configure(params))
 | 
			
		||||
    {
 | 
			
		||||
        this_unit.insert_front(mon);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        delete mon;
 | 
			
		||||
        mon = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    return mon;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MonitorManager::debug_wait_one_tick()
 | 
			
		||||
{
 | 
			
		||||
    using namespace std::chrono;
 | 
			
		||||
    std::map<Monitor*, uint64_t> ticks;
 | 
			
		||||
 | 
			
		||||
    // Get tick values for all monitors
 | 
			
		||||
    this_unit.foreach_monitor([&ticks](Monitor* mon) {
 | 
			
		||||
        ticks[mon] = mxb::atomic::load(&mon->m_ticks);
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Wait for all running monitors to advance at least one tick.
 | 
			
		||||
    this_unit.foreach_monitor([&ticks](Monitor* mon) {
 | 
			
		||||
        if (mon->state() == MONITOR_STATE_RUNNING)
 | 
			
		||||
        {
 | 
			
		||||
            auto start = steady_clock::now();
 | 
			
		||||
            // A monitor may have been added in between the two foreach-calls (not if config changes are
 | 
			
		||||
            // serialized). Check if entry exists.
 | 
			
		||||
            if (ticks.count(mon) > 0)
 | 
			
		||||
            {
 | 
			
		||||
                auto tick = ticks[mon];
 | 
			
		||||
                while (mxb::atomic::load(&mon->m_ticks) == tick && (steady_clock::now() - start < seconds(60)))
 | 
			
		||||
                {
 | 
			
		||||
                    std::this_thread::sleep_for(milliseconds(100));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MonitorManager::destroy_all_monitors()
 | 
			
		||||
{
 | 
			
		||||
    auto monitors = this_unit.clear();
 | 
			
		||||
    for (auto monitor : monitors)
 | 
			
		||||
    {
 | 
			
		||||
        mxb_assert(monitor->state() == MONITOR_STATE_STOPPED);
 | 
			
		||||
        delete monitor;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MonitorManager::start_monitor(Monitor* monitor)
 | 
			
		||||
{
 | 
			
		||||
    mxb_assert(monitor);
 | 
			
		||||
 | 
			
		||||
    Guard guard(monitor->m_lock);
 | 
			
		||||
 | 
			
		||||
    // Only start the monitor if it's stopped.
 | 
			
		||||
    if (monitor->state() == MONITOR_STATE_STOPPED)
 | 
			
		||||
    {
 | 
			
		||||
        if (!monitor->start())
 | 
			
		||||
        {
 | 
			
		||||
                    MXS_ERROR("Failed to start monitor '%s'.", monitor->name());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MonitorManager::populate_services()
 | 
			
		||||
{
 | 
			
		||||
    this_unit.foreach_monitor([](Monitor* pMonitor) -> bool {
 | 
			
		||||
        pMonitor->populate_services();
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Start all monitors
 | 
			
		||||
 */
 | 
			
		||||
void MonitorManager::start_all_monitors()
 | 
			
		||||
{
 | 
			
		||||
    this_unit.foreach_monitor([](Monitor* monitor) {
 | 
			
		||||
        MonitorManager::start_monitor(monitor);
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MonitorManager::stop_monitor(Monitor* monitor)
 | 
			
		||||
{
 | 
			
		||||
    mxb_assert(monitor);
 | 
			
		||||
 | 
			
		||||
    Guard guard(monitor->m_lock);
 | 
			
		||||
 | 
			
		||||
    /** Only stop the monitor if it is running */
 | 
			
		||||
    if (monitor->state() == MONITOR_STATE_RUNNING)
 | 
			
		||||
    {
 | 
			
		||||
        monitor->stop();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MonitorManager::deactivate_monitor(Monitor* monitor)
 | 
			
		||||
{
 | 
			
		||||
    // This cannot be done with configure(), since other, module-specific config settings may depend on the
 | 
			
		||||
    // "servers"-setting of the base monitor. Directly manipulate monitor field for now, later use a dtor
 | 
			
		||||
    // to cleanly "deactivate" inherited objects.
 | 
			
		||||
    stop_monitor(monitor);
 | 
			
		||||
    while (!monitor->m_servers.empty())
 | 
			
		||||
    {
 | 
			
		||||
        monitor->remove_server(monitor->m_servers.front()->server);
 | 
			
		||||
    }
 | 
			
		||||
    this_unit.move_to_deactivated_list(monitor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Shutdown all running monitors
 | 
			
		||||
 */
 | 
			
		||||
void MonitorManager::stop_all_monitors()
 | 
			
		||||
{
 | 
			
		||||
    this_unit.foreach_monitor([](Monitor* monitor) {
 | 
			
		||||
        MonitorManager::stop_monitor(monitor);
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Show all monitors
 | 
			
		||||
 *
 | 
			
		||||
 * @param dcb   DCB for printing output
 | 
			
		||||
 */
 | 
			
		||||
void MonitorManager::show_all_monitors(DCB* dcb)
 | 
			
		||||
{
 | 
			
		||||
    this_unit.foreach_monitor([dcb](Monitor* monitor) {
 | 
			
		||||
        monitor_show(dcb, monitor);
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Show a single monitor
 | 
			
		||||
 *
 | 
			
		||||
 * @param dcb   DCB for printing output
 | 
			
		||||
 */
 | 
			
		||||
void MonitorManager::monitor_show(DCB* dcb, Monitor* monitor)
 | 
			
		||||
{
 | 
			
		||||
    monitor->show(dcb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * List all the monitors
 | 
			
		||||
 *
 | 
			
		||||
 * @param dcb   DCB for printing output
 | 
			
		||||
 */
 | 
			
		||||
void MonitorManager::monitor_list(DCB* dcb)
 | 
			
		||||
{
 | 
			
		||||
    dcb_printf(dcb, "---------------------+---------------------\n");
 | 
			
		||||
    dcb_printf(dcb, "%-20s | Status\n", "Monitor");
 | 
			
		||||
    dcb_printf(dcb, "---------------------+---------------------\n");
 | 
			
		||||
 | 
			
		||||
    this_unit.foreach_monitor([dcb](Monitor* ptr) {
 | 
			
		||||
        dcb_printf(dcb, "%-20s | %s\n",
 | 
			
		||||
                   ptr->name(), ptr->state() == MONITOR_STATE_RUNNING ? "Running" : "Stopped");
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    dcb_printf(dcb, "---------------------+---------------------\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find a monitor by name
 | 
			
		||||
 *
 | 
			
		||||
 * @param       name    The name of the monitor
 | 
			
		||||
 * @return      Pointer to the monitor or NULL
 | 
			
		||||
 */
 | 
			
		||||
Monitor* MonitorManager::find_monitor(const char* name)
 | 
			
		||||
{
 | 
			
		||||
    Monitor* rval = nullptr;
 | 
			
		||||
    this_unit.foreach_monitor([&rval, name](Monitor* ptr) {
 | 
			
		||||
        if (ptr->m_name == name)
 | 
			
		||||
        {
 | 
			
		||||
            rval = ptr;
 | 
			
		||||
        }
 | 
			
		||||
        return (rval == nullptr);
 | 
			
		||||
    });
 | 
			
		||||
    return rval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return a resultset that has the current set of monitors in it
 | 
			
		||||
 *
 | 
			
		||||
 * @return A Result set
 | 
			
		||||
 */
 | 
			
		||||
std::unique_ptr<ResultSet> MonitorManager::monitor_get_list()
 | 
			
		||||
{
 | 
			
		||||
    std::unique_ptr<ResultSet> set = ResultSet::create({"Monitor", "Status"});
 | 
			
		||||
    this_unit.foreach_monitor([&set](Monitor* ptr) {
 | 
			
		||||
        const char* state = ptr->state() == MONITOR_STATE_RUNNING ? "Running" : "Stopped";
 | 
			
		||||
        set->add_row({ptr->m_name, state});
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
    return set;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Monitor* MonitorManager::server_is_monitored(const SERVER* server)
 | 
			
		||||
{
 | 
			
		||||
    Monitor* rval = nullptr;
 | 
			
		||||
    this_unit.foreach_monitor([&rval, server](Monitor* monitor) {
 | 
			
		||||
        Guard guard(monitor->m_lock);
 | 
			
		||||
        for (MonitorServer* db : monitor->m_servers)
 | 
			
		||||
        {
 | 
			
		||||
            if (db->server == server)
 | 
			
		||||
            {
 | 
			
		||||
                rval = monitor;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return (rval == nullptr);
 | 
			
		||||
    });
 | 
			
		||||
    return rval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MonitorManager::create_monitor_config(const Monitor* monitor, const char* filename)
 | 
			
		||||
{
 | 
			
		||||
    int file = open(filename, O_EXCL | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 | 
			
		||||
    if (file == -1)
 | 
			
		||||
    {
 | 
			
		||||
                MXS_ERROR("Failed to open file '%s' when serializing monitor '%s': %d, %s",
 | 
			
		||||
                          filename,
 | 
			
		||||
                          monitor->name(),
 | 
			
		||||
                          errno,
 | 
			
		||||
                          mxs_strerror(errno));
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        Guard guard(monitor->m_lock);
 | 
			
		||||
 | 
			
		||||
        const MXS_MODULE* mod = get_module(monitor->m_module.c_str(), NULL);
 | 
			
		||||
        mxb_assert(mod);
 | 
			
		||||
 | 
			
		||||
        string config = generate_config_string(monitor->m_name, monitor->parameters,
 | 
			
		||||
                                               config_monitor_params, mod->parameters);
 | 
			
		||||
 | 
			
		||||
        if (dprintf(file, "%s", config.c_str()) == -1)
 | 
			
		||||
        {
 | 
			
		||||
                    MXS_ERROR("Could not write serialized configuration to file '%s': %d, %s",
 | 
			
		||||
                              filename, errno, mxs_strerror(errno));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    close(file);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MonitorManager::monitor_serialize(const Monitor* monitor)
 | 
			
		||||
{
 | 
			
		||||
    bool rval = false;
 | 
			
		||||
    char filename[PATH_MAX];
 | 
			
		||||
    snprintf(filename,
 | 
			
		||||
             sizeof(filename),
 | 
			
		||||
             "%s/%s.cnf.tmp",
 | 
			
		||||
             get_config_persistdir(),
 | 
			
		||||
             monitor->name());
 | 
			
		||||
 | 
			
		||||
    if (unlink(filename) == -1 && errno != ENOENT)
 | 
			
		||||
    {
 | 
			
		||||
                MXS_ERROR("Failed to remove temporary monitor configuration at '%s': %d, %s",
 | 
			
		||||
                          filename,
 | 
			
		||||
                          errno,
 | 
			
		||||
                          mxs_strerror(errno));
 | 
			
		||||
    }
 | 
			
		||||
    else if (create_monitor_config(monitor, filename))
 | 
			
		||||
    {
 | 
			
		||||
        char final_filename[PATH_MAX];
 | 
			
		||||
        strcpy(final_filename, filename);
 | 
			
		||||
 | 
			
		||||
        char* dot = strrchr(final_filename, '.');
 | 
			
		||||
        mxb_assert(dot);
 | 
			
		||||
        *dot = '\0';
 | 
			
		||||
 | 
			
		||||
        if (rename(filename, final_filename) == 0)
 | 
			
		||||
        {
 | 
			
		||||
            rval = true;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
                    MXS_ERROR("Failed to rename temporary monitor configuration at '%s': %d, %s",
 | 
			
		||||
                              filename,
 | 
			
		||||
                              errno,
 | 
			
		||||
                              mxs_strerror(errno));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return rval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// static
 | 
			
		||||
bool MonitorManager::reconfigure_monitor(mxs::Monitor* monitor, const MXS_CONFIG_PARAMETER& parameters)
 | 
			
		||||
{
 | 
			
		||||
    // Backup monitor parameters in case configure fails.
 | 
			
		||||
    auto orig = monitor->parameters;
 | 
			
		||||
    monitor->parameters.clear();
 | 
			
		||||
 | 
			
		||||
    bool success = monitor->configure(¶meters);
 | 
			
		||||
 | 
			
		||||
    if (!success)
 | 
			
		||||
    {
 | 
			
		||||
        MXB_AT_DEBUG(bool check = ) monitor->configure(&orig);
 | 
			
		||||
        mxb_assert(check);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
json_t* MonitorManager::monitor_to_json(const Monitor* monitor, const char* host)
 | 
			
		||||
{
 | 
			
		||||
    string self = MXS_JSON_API_MONITORS;
 | 
			
		||||
    self += monitor->m_name;
 | 
			
		||||
    return mxs_json_resource(host, self.c_str(), monitor_json_data(monitor, host));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
json_t* MonitorManager::monitor_list_to_json(const char* host)
 | 
			
		||||
{
 | 
			
		||||
    json_t* rval = json_array();
 | 
			
		||||
    this_unit.foreach_monitor([rval, host](Monitor* mon) {
 | 
			
		||||
        json_t* json = monitor_json_data(mon, host);
 | 
			
		||||
        if (json)
 | 
			
		||||
        {
 | 
			
		||||
            json_array_append_new(rval, json);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return mxs_json_resource(host, MXS_JSON_API_MONITORS, rval);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
json_t* MonitorManager::monitor_relations_to_server(const SERVER* server, const char* host)
 | 
			
		||||
{
 | 
			
		||||
    std::vector<std::string> names;
 | 
			
		||||
    this_unit.foreach_monitor([&names, server](Monitor* mon) {
 | 
			
		||||
        Guard guard(mon->m_lock);
 | 
			
		||||
        for (MonitorServer* db : mon->m_servers)
 | 
			
		||||
        {
 | 
			
		||||
            if (db->server == server)
 | 
			
		||||
            {
 | 
			
		||||
                names.push_back(mon->m_name);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    json_t* rel = NULL;
 | 
			
		||||
    if (!names.empty())
 | 
			
		||||
    {
 | 
			
		||||
        rel = mxs_json_relationship(host, MXS_JSON_API_MONITORS);
 | 
			
		||||
 | 
			
		||||
        for (std::vector<std::string>::iterator it = names.begin();
 | 
			
		||||
             it != names.end(); it++)
 | 
			
		||||
        {
 | 
			
		||||
            mxs_json_add_relation(rel, it->c_str(), CN_MONITORS);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return rel;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace maxscale
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										471
									
								
								server/core/monitormanager.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										471
									
								
								server/core/monitormanager.cc
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,471 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2019 MariaDB Corporation Ab
 | 
			
		||||
 *
 | 
			
		||||
 * Use of this software is governed by the Business Source License included
 | 
			
		||||
 * in the LICENSE.TXT file and at www.mariadb.com/bsl11.
 | 
			
		||||
 *
 | 
			
		||||
 * Change Date: 2025-01-01
 | 
			
		||||
 *
 | 
			
		||||
 * On the date above, in accordance with the Business Source License, use
 | 
			
		||||
 * of this software will be governed by version 2 or later of the General
 | 
			
		||||
 * Public License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <maxscale/ccdefs.hh>
 | 
			
		||||
 | 
			
		||||
#include <maxscale/json_api.hh>
 | 
			
		||||
#include <maxscale/paths.h>
 | 
			
		||||
 | 
			
		||||
#include "internal/config.hh"
 | 
			
		||||
#include "internal/monitor.hh"
 | 
			
		||||
#include "internal/modules.hh"
 | 
			
		||||
 | 
			
		||||
using maxscale::Monitor;
 | 
			
		||||
using maxscale::MonitorServer;
 | 
			
		||||
using Guard = std::lock_guard<std::mutex>;
 | 
			
		||||
using std::string;
 | 
			
		||||
 | 
			
		||||
namespace
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class ThisUnit
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Call a function on every monitor in the global monitor list.
 | 
			
		||||
     *
 | 
			
		||||
     * @param apply The function to apply. If the function returns false, iteration is discontinued.
 | 
			
		||||
     */
 | 
			
		||||
    void foreach_monitor(std::function<bool(Monitor*)> apply)
 | 
			
		||||
    {
 | 
			
		||||
        Guard guard(m_all_monitors_lock);
 | 
			
		||||
        for (Monitor* monitor : m_all_monitors)
 | 
			
		||||
        {
 | 
			
		||||
            if (!apply(monitor))
 | 
			
		||||
            {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clear the internal list and return previous contents.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Contents before clearing
 | 
			
		||||
     */
 | 
			
		||||
    std::vector<Monitor*> clear()
 | 
			
		||||
    {
 | 
			
		||||
        Guard guard(m_all_monitors_lock);
 | 
			
		||||
        return std::move(m_all_monitors);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void insert_front(Monitor* monitor)
 | 
			
		||||
    {
 | 
			
		||||
        Guard guard(m_all_monitors_lock);
 | 
			
		||||
        m_all_monitors.insert(m_all_monitors.begin(), monitor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void move_to_deactivated_list(Monitor* monitor)
 | 
			
		||||
    {
 | 
			
		||||
        Guard guard(m_all_monitors_lock);
 | 
			
		||||
        auto iter = std::find(m_all_monitors.begin(), m_all_monitors.end(), monitor);
 | 
			
		||||
        mxb_assert(iter != m_all_monitors.end());
 | 
			
		||||
        m_all_monitors.erase(iter);
 | 
			
		||||
        m_deact_monitors.push_back(monitor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::mutex m_all_monitors_lock;          /**< Protects access to arrays */
 | 
			
		||||
    std::vector<Monitor*> m_all_monitors;    /**< Global list of monitors, in configuration file order */
 | 
			
		||||
    std::vector<Monitor*> m_deact_monitors;  /**< Deactivated monitors. TODO: delete monitors */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ThisUnit this_unit;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Monitor* MonitorManager::create_monitor(const string& name, const string& module,
 | 
			
		||||
                                        MXS_CONFIG_PARAMETER* params)
 | 
			
		||||
{
 | 
			
		||||
    MXS_MONITOR_API* api = (MXS_MONITOR_API*)load_module(module.c_str(), MODULE_MONITOR);
 | 
			
		||||
    if (!api)
 | 
			
		||||
    {
 | 
			
		||||
        MXS_ERROR("Unable to load library file for monitor '%s'.", name.c_str());
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Monitor* mon = api->createInstance(name, module);
 | 
			
		||||
    if (!mon)
 | 
			
		||||
    {
 | 
			
		||||
        MXS_ERROR("Unable to create monitor instance for '%s', using module '%s'.",
 | 
			
		||||
                  name.c_str(), module.c_str());
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (mon->configure(params))
 | 
			
		||||
    {
 | 
			
		||||
        this_unit.insert_front(mon);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        delete mon;
 | 
			
		||||
        mon = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    return mon;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MonitorManager::debug_wait_one_tick()
 | 
			
		||||
{
 | 
			
		||||
    using namespace std::chrono;
 | 
			
		||||
    std::map<Monitor*, uint64_t> ticks;
 | 
			
		||||
 | 
			
		||||
    // Get tick values for all monitors
 | 
			
		||||
    this_unit.foreach_monitor([&ticks](Monitor* mon) {
 | 
			
		||||
        ticks[mon] = mxb::atomic::load(&mon->m_ticks);
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Wait for all running monitors to advance at least one tick.
 | 
			
		||||
    this_unit.foreach_monitor([&ticks](Monitor* mon) {
 | 
			
		||||
        if (mon->state() == MONITOR_STATE_RUNNING)
 | 
			
		||||
        {
 | 
			
		||||
            auto start = steady_clock::now();
 | 
			
		||||
            // A monitor may have been added in between the two foreach-calls (not if config changes are
 | 
			
		||||
            // serialized). Check if entry exists.
 | 
			
		||||
            if (ticks.count(mon) > 0)
 | 
			
		||||
            {
 | 
			
		||||
                auto tick = ticks[mon];
 | 
			
		||||
                while (mxb::atomic::load(&mon->m_ticks) == tick && (steady_clock::now() - start < seconds(60)))
 | 
			
		||||
                {
 | 
			
		||||
                    std::this_thread::sleep_for(milliseconds(100));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MonitorManager::destroy_all_monitors()
 | 
			
		||||
{
 | 
			
		||||
    auto monitors = this_unit.clear();
 | 
			
		||||
    for (auto monitor : monitors)
 | 
			
		||||
    {
 | 
			
		||||
        mxb_assert(monitor->state() == MONITOR_STATE_STOPPED);
 | 
			
		||||
        delete monitor;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MonitorManager::start_monitor(Monitor* monitor)
 | 
			
		||||
{
 | 
			
		||||
    mxb_assert(monitor);
 | 
			
		||||
 | 
			
		||||
    Guard guard(monitor->m_lock);
 | 
			
		||||
 | 
			
		||||
    // Only start the monitor if it's stopped.
 | 
			
		||||
    if (monitor->state() == MONITOR_STATE_STOPPED)
 | 
			
		||||
    {
 | 
			
		||||
        if (!monitor->start())
 | 
			
		||||
        {
 | 
			
		||||
            MXS_ERROR("Failed to start monitor '%s'.", monitor->name());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MonitorManager::populate_services()
 | 
			
		||||
{
 | 
			
		||||
    this_unit.foreach_monitor([](Monitor* pMonitor) -> bool {
 | 
			
		||||
        pMonitor->populate_services();
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Start all monitors
 | 
			
		||||
 */
 | 
			
		||||
void MonitorManager::start_all_monitors()
 | 
			
		||||
{
 | 
			
		||||
    this_unit.foreach_monitor([](Monitor* monitor) {
 | 
			
		||||
        MonitorManager::start_monitor(monitor);
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MonitorManager::stop_monitor(Monitor* monitor)
 | 
			
		||||
{
 | 
			
		||||
    mxb_assert(monitor);
 | 
			
		||||
 | 
			
		||||
    Guard guard(monitor->m_lock);
 | 
			
		||||
 | 
			
		||||
    /** Only stop the monitor if it is running */
 | 
			
		||||
    if (monitor->state() == MONITOR_STATE_RUNNING)
 | 
			
		||||
    {
 | 
			
		||||
        monitor->stop();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MonitorManager::deactivate_monitor(Monitor* monitor)
 | 
			
		||||
{
 | 
			
		||||
    // This cannot be done with configure(), since other, module-specific config settings may depend on the
 | 
			
		||||
    // "servers"-setting of the base monitor. Directly manipulate monitor field for now, later use a dtor
 | 
			
		||||
    // to cleanly "deactivate" inherited objects.
 | 
			
		||||
    stop_monitor(monitor);
 | 
			
		||||
    while (!monitor->m_servers.empty())
 | 
			
		||||
    {
 | 
			
		||||
        monitor->remove_server(monitor->m_servers.front()->server);
 | 
			
		||||
    }
 | 
			
		||||
    this_unit.move_to_deactivated_list(monitor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Shutdown all running monitors
 | 
			
		||||
 */
 | 
			
		||||
void MonitorManager::stop_all_monitors()
 | 
			
		||||
{
 | 
			
		||||
    this_unit.foreach_monitor([](Monitor* monitor) {
 | 
			
		||||
        MonitorManager::stop_monitor(monitor);
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Show all monitors
 | 
			
		||||
 *
 | 
			
		||||
 * @param dcb   DCB for printing output
 | 
			
		||||
 */
 | 
			
		||||
void MonitorManager::show_all_monitors(DCB* dcb)
 | 
			
		||||
{
 | 
			
		||||
    this_unit.foreach_monitor([dcb](Monitor* monitor) {
 | 
			
		||||
        monitor_show(dcb, monitor);
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Show a single monitor
 | 
			
		||||
 *
 | 
			
		||||
 * @param dcb   DCB for printing output
 | 
			
		||||
 */
 | 
			
		||||
void MonitorManager::monitor_show(DCB* dcb, Monitor* monitor)
 | 
			
		||||
{
 | 
			
		||||
    monitor->show(dcb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * List all the monitors
 | 
			
		||||
 *
 | 
			
		||||
 * @param dcb   DCB for printing output
 | 
			
		||||
 */
 | 
			
		||||
void MonitorManager::monitor_list(DCB* dcb)
 | 
			
		||||
{
 | 
			
		||||
    dcb_printf(dcb, "---------------------+---------------------\n");
 | 
			
		||||
    dcb_printf(dcb, "%-20s | Status\n", "Monitor");
 | 
			
		||||
    dcb_printf(dcb, "---------------------+---------------------\n");
 | 
			
		||||
 | 
			
		||||
    this_unit.foreach_monitor([dcb](Monitor* ptr) {
 | 
			
		||||
        dcb_printf(dcb, "%-20s | %s\n",
 | 
			
		||||
                   ptr->name(), ptr->state() == MONITOR_STATE_RUNNING ? "Running" : "Stopped");
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    dcb_printf(dcb, "---------------------+---------------------\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find a monitor by name
 | 
			
		||||
 *
 | 
			
		||||
 * @param       name    The name of the monitor
 | 
			
		||||
 * @return      Pointer to the monitor or NULL
 | 
			
		||||
 */
 | 
			
		||||
Monitor* MonitorManager::find_monitor(const char* name)
 | 
			
		||||
{
 | 
			
		||||
    Monitor* rval = nullptr;
 | 
			
		||||
    this_unit.foreach_monitor([&rval, name](Monitor* ptr) {
 | 
			
		||||
        if (ptr->m_name == name)
 | 
			
		||||
        {
 | 
			
		||||
            rval = ptr;
 | 
			
		||||
        }
 | 
			
		||||
        return (rval == nullptr);
 | 
			
		||||
    });
 | 
			
		||||
    return rval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return a resultset that has the current set of monitors in it
 | 
			
		||||
 *
 | 
			
		||||
 * @return A Result set
 | 
			
		||||
 */
 | 
			
		||||
std::unique_ptr<ResultSet> MonitorManager::monitor_get_list()
 | 
			
		||||
{
 | 
			
		||||
    std::unique_ptr<ResultSet> set = ResultSet::create({"Monitor", "Status"});
 | 
			
		||||
    this_unit.foreach_monitor([&set](Monitor* ptr) {
 | 
			
		||||
        const char* state = ptr->state() == MONITOR_STATE_RUNNING ? "Running" : "Stopped";
 | 
			
		||||
        set->add_row({ptr->m_name, state});
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
    return set;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Monitor* MonitorManager::server_is_monitored(const SERVER* server)
 | 
			
		||||
{
 | 
			
		||||
    Monitor* rval = nullptr;
 | 
			
		||||
    this_unit.foreach_monitor([&rval, server](Monitor* monitor) {
 | 
			
		||||
        Guard guard(monitor->m_lock);
 | 
			
		||||
        for (MonitorServer* db : monitor->m_servers)
 | 
			
		||||
        {
 | 
			
		||||
            if (db->server == server)
 | 
			
		||||
            {
 | 
			
		||||
                rval = monitor;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return (rval == nullptr);
 | 
			
		||||
    });
 | 
			
		||||
    return rval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MonitorManager::create_monitor_config(const Monitor* monitor, const char* filename)
 | 
			
		||||
{
 | 
			
		||||
    int file = open(filename, O_EXCL | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 | 
			
		||||
    if (file == -1)
 | 
			
		||||
    {
 | 
			
		||||
        MXS_ERROR("Failed to open file '%s' when serializing monitor '%s': %d, %s",
 | 
			
		||||
                  filename,
 | 
			
		||||
                  monitor->name(),
 | 
			
		||||
                  errno,
 | 
			
		||||
                  mxs_strerror(errno));
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        Guard guard(monitor->m_lock);
 | 
			
		||||
 | 
			
		||||
        const MXS_MODULE* mod = get_module(monitor->m_module.c_str(), NULL);
 | 
			
		||||
        mxb_assert(mod);
 | 
			
		||||
 | 
			
		||||
        string config = generate_config_string(monitor->m_name, monitor->parameters,
 | 
			
		||||
                                               config_monitor_params, mod->parameters);
 | 
			
		||||
 | 
			
		||||
        if (dprintf(file, "%s", config.c_str()) == -1)
 | 
			
		||||
        {
 | 
			
		||||
                    MXS_ERROR("Could not write serialized configuration to file '%s': %d, %s",
 | 
			
		||||
                              filename, errno, mxs_strerror(errno));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    close(file);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MonitorManager::monitor_serialize(const Monitor* monitor)
 | 
			
		||||
{
 | 
			
		||||
    bool rval = false;
 | 
			
		||||
    char filename[PATH_MAX];
 | 
			
		||||
    snprintf(filename,
 | 
			
		||||
             sizeof(filename),
 | 
			
		||||
             "%s/%s.cnf.tmp",
 | 
			
		||||
             get_config_persistdir(),
 | 
			
		||||
             monitor->name());
 | 
			
		||||
 | 
			
		||||
    if (unlink(filename) == -1 && errno != ENOENT)
 | 
			
		||||
    {
 | 
			
		||||
                MXS_ERROR("Failed to remove temporary monitor configuration at '%s': %d, %s",
 | 
			
		||||
                          filename,
 | 
			
		||||
                          errno,
 | 
			
		||||
                          mxs_strerror(errno));
 | 
			
		||||
    }
 | 
			
		||||
    else if (create_monitor_config(monitor, filename))
 | 
			
		||||
    {
 | 
			
		||||
        char final_filename[PATH_MAX];
 | 
			
		||||
        strcpy(final_filename, filename);
 | 
			
		||||
 | 
			
		||||
        char* dot = strrchr(final_filename, '.');
 | 
			
		||||
        mxb_assert(dot);
 | 
			
		||||
        *dot = '\0';
 | 
			
		||||
 | 
			
		||||
        if (rename(filename, final_filename) == 0)
 | 
			
		||||
        {
 | 
			
		||||
            rval = true;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            MXS_ERROR("Failed to rename temporary monitor configuration at '%s': %d, %s",
 | 
			
		||||
                      filename,
 | 
			
		||||
                      errno,
 | 
			
		||||
                      mxs_strerror(errno));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return rval;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// static
 | 
			
		||||
bool MonitorManager::reconfigure_monitor(mxs::Monitor* monitor, const MXS_CONFIG_PARAMETER& parameters)
 | 
			
		||||
{
 | 
			
		||||
    // Backup monitor parameters in case configure fails.
 | 
			
		||||
    auto orig = monitor->parameters;
 | 
			
		||||
    monitor->parameters.clear();
 | 
			
		||||
 | 
			
		||||
    bool success = monitor->configure(¶meters);
 | 
			
		||||
 | 
			
		||||
    if (!success)
 | 
			
		||||
    {
 | 
			
		||||
        MXB_AT_DEBUG(bool check = ) monitor->configure(&orig);
 | 
			
		||||
        mxb_assert(check);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
json_t* MonitorManager::monitor_to_json(const Monitor* monitor, const char* host)
 | 
			
		||||
{
 | 
			
		||||
    string self = MXS_JSON_API_MONITORS;
 | 
			
		||||
    self += monitor->m_name;
 | 
			
		||||
    return mxs_json_resource(host, self.c_str(), monitor_json_data(monitor, host));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
json_t* MonitorManager::monitor_list_to_json(const char* host)
 | 
			
		||||
{
 | 
			
		||||
    json_t* rval = json_array();
 | 
			
		||||
    this_unit.foreach_monitor([rval, host](Monitor* mon) {
 | 
			
		||||
        json_t* json = monitor_json_data(mon, host);
 | 
			
		||||
        if (json)
 | 
			
		||||
        {
 | 
			
		||||
            json_array_append_new(rval, json);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return mxs_json_resource(host, MXS_JSON_API_MONITORS, rval);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
json_t* MonitorManager::monitor_relations_to_server(const SERVER* server, const char* host)
 | 
			
		||||
{
 | 
			
		||||
    std::vector<std::string> names;
 | 
			
		||||
    this_unit.foreach_monitor([&names, server](Monitor* mon) {
 | 
			
		||||
        Guard guard(mon->m_lock);
 | 
			
		||||
        for (MonitorServer* db : mon->m_servers)
 | 
			
		||||
        {
 | 
			
		||||
            if (db->server == server)
 | 
			
		||||
            {
 | 
			
		||||
                names.push_back(mon->m_name);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    json_t* rel = NULL;
 | 
			
		||||
    if (!names.empty())
 | 
			
		||||
    {
 | 
			
		||||
        rel = mxs_json_relationship(host, MXS_JSON_API_MONITORS);
 | 
			
		||||
 | 
			
		||||
        for (std::vector<std::string>::iterator it = names.begin();
 | 
			
		||||
             it != names.end(); it++)
 | 
			
		||||
        {
 | 
			
		||||
            mxs_json_add_relation(rel, it->c_str(), CN_MONITORS);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return rel;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user