617 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			617 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * 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.
 | 
						|
 */
 | 
						|
 | 
						|
#include <maxscale/ccdefs.hh>
 | 
						|
 | 
						|
#include <maxbase/format.hh>
 | 
						|
#include <maxscale/json_api.hh>
 | 
						|
#include <maxscale/paths.h>
 | 
						|
#include <maxscale/resultset.hh>
 | 
						|
 | 
						|
#include "internal/config.hh"
 | 
						|
#include "internal/monitor.hh"
 | 
						|
#include "internal/monitormanager.hh"
 | 
						|
#include "internal/modules.hh"
 | 
						|
#include "internal/externcmd.hh"
 | 
						|
 | 
						|
using maxscale::Monitor;
 | 
						|
using maxscale::MonitorServer;
 | 
						|
using Guard = std::lock_guard<std::mutex>;
 | 
						|
using std::string;
 | 
						|
using mxb::string_printf;
 | 
						|
 | 
						|
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 RECONFIG_FAILED[] = "Monitor reconfiguration failed when %s. Check log for more details.";
 | 
						|
}
 | 
						|
 | 
						|
Monitor* MonitorManager::create_monitor(const string& name, const string& module,
 | 
						|
                                        MXS_CONFIG_PARAMETER* params)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    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()
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    using namespace std::chrono;
 | 
						|
    std::map<Monitor*, long> ticks;
 | 
						|
 | 
						|
    // Get tick values for all monitors
 | 
						|
    this_unit.foreach_monitor(
 | 
						|
        [&ticks](Monitor* mon) {
 | 
						|
            ticks[mon] = mon->ticks();
 | 
						|
            return true;
 | 
						|
        });
 | 
						|
 | 
						|
    // Wait for all running monitors to advance at least one tick.
 | 
						|
    this_unit.foreach_monitor(
 | 
						|
        [&ticks](Monitor* mon) {
 | 
						|
            if (mon->is_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 (mon->ticks() == tick
 | 
						|
                           && (steady_clock::now() - start < seconds(60)))
 | 
						|
                    {
 | 
						|
                        std::this_thread::sleep_for(milliseconds(100));
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return true;
 | 
						|
        });
 | 
						|
}
 | 
						|
 | 
						|
void MonitorManager::destroy_all_monitors()
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    auto monitors = this_unit.clear();
 | 
						|
    for (auto monitor : monitors)
 | 
						|
    {
 | 
						|
        mxb_assert(!monitor->is_running());
 | 
						|
        delete monitor;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void MonitorManager::start_monitor(Monitor* monitor)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
 | 
						|
    // Only start the monitor if it's stopped.
 | 
						|
    if (!monitor->is_running())
 | 
						|
    {
 | 
						|
        if (!monitor->start())
 | 
						|
        {
 | 
						|
            MXS_ERROR("Failed to start monitor '%s'.", monitor->name());
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void MonitorManager::populate_services()
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    this_unit.foreach_monitor(
 | 
						|
        [](Monitor* pMonitor) -> bool {
 | 
						|
            pMonitor->populate_services();
 | 
						|
            return true;
 | 
						|
        });
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Start all monitors
 | 
						|
 */
 | 
						|
void MonitorManager::start_all_monitors()
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    this_unit.foreach_monitor(
 | 
						|
        [](Monitor* monitor) {
 | 
						|
            MonitorManager::start_monitor(monitor);
 | 
						|
            return true;
 | 
						|
        });
 | 
						|
}
 | 
						|
 | 
						|
void MonitorManager::stop_monitor(Monitor* monitor)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
 | 
						|
    /** Only stop the monitor if it is running */
 | 
						|
    if (monitor->is_running())
 | 
						|
    {
 | 
						|
        monitor->stop();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void MonitorManager::deactivate_monitor(Monitor* monitor)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    // This cannot be done with configure(), since other, module-specific config settings may depend on the
 | 
						|
    // "servers"-setting of the base monitor.
 | 
						|
    monitor->deactivate();
 | 
						|
    this_unit.move_to_deactivated_list(monitor);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Shutdown all running monitors
 | 
						|
 */
 | 
						|
void MonitorManager::stop_all_monitors()
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    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)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    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)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    monitor->show(dcb);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * List all the monitors
 | 
						|
 *
 | 
						|
 * @param dcb   DCB for printing output
 | 
						|
 */
 | 
						|
void MonitorManager::monitor_list(DCB* dcb)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    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_string());
 | 
						|
            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()
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    std::unique_ptr<ResultSet> set = ResultSet::create({"Monitor", "Status"});
 | 
						|
    this_unit.foreach_monitor(
 | 
						|
        [&set](Monitor* ptr) {
 | 
						|
            set->add_row({ptr->m_name, ptr->state_string()});
 | 
						|
            return true;
 | 
						|
        });
 | 
						|
    return set;
 | 
						|
}
 | 
						|
 | 
						|
Monitor* MonitorManager::server_is_monitored(const SERVER* server)
 | 
						|
{
 | 
						|
    Monitor* rval = nullptr;
 | 
						|
    auto mon_name = Monitor::get_server_monitor(server);
 | 
						|
    if (!mon_name.empty())
 | 
						|
    {
 | 
						|
        rval = find_monitor(mon_name.c_str());
 | 
						|
        mxb_assert(rval);
 | 
						|
    }
 | 
						|
    return rval;
 | 
						|
}
 | 
						|
 | 
						|
bool MonitorManager::create_monitor_config(const Monitor* monitor, const char* filename)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    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;
 | 
						|
    }
 | 
						|
 | 
						|
    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)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    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;
 | 
						|
}
 | 
						|
 | 
						|
bool MonitorManager::reconfigure_monitor(mxs::Monitor* monitor, const MXS_CONFIG_PARAMETER& parameters)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    // Backup monitor parameters in case configure fails.
 | 
						|
    auto orig = monitor->parameters();
 | 
						|
    // Stop/start monitor if it's currently running. If monitor was stopped already, this is likely
 | 
						|
    // managed by the caller.
 | 
						|
    bool stopstart = monitor->is_running();
 | 
						|
    if (stopstart)
 | 
						|
    {
 | 
						|
        monitor->stop();
 | 
						|
    }
 | 
						|
 | 
						|
    bool success = false;
 | 
						|
    if (monitor->configure(¶meters))
 | 
						|
    {
 | 
						|
        // Serialization must also succeed.
 | 
						|
        success = MonitorManager::monitor_serialize(monitor);
 | 
						|
    }
 | 
						|
 | 
						|
    if (!success)
 | 
						|
    {
 | 
						|
        // Try to restore old values, it should work.
 | 
						|
        MXB_AT_DEBUG(bool check = ) monitor->configure(&orig);
 | 
						|
        mxb_assert(check);
 | 
						|
    }
 | 
						|
 | 
						|
    if (stopstart && !monitor->start())
 | 
						|
    {
 | 
						|
        MXB_ERROR("Reconfiguration of monitor '%s' failed because monitor did not start.", monitor->name());
 | 
						|
    }
 | 
						|
    return success;
 | 
						|
}
 | 
						|
 | 
						|
bool MonitorManager::alter_monitor(mxs::Monitor* monitor, const std::string& key, const std::string& value,
 | 
						|
                                   std::string* error_out)
 | 
						|
{
 | 
						|
    const MXS_MODULE* mod = get_module(monitor->m_module.c_str(), MODULE_MONITOR);
 | 
						|
    if (!validate_param(config_monitor_params, mod->parameters, key, value, error_out))
 | 
						|
    {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    MXS_CONFIG_PARAMETER modified = monitor->parameters();
 | 
						|
    modified.set(key, value);
 | 
						|
 | 
						|
    bool success = MonitorManager::reconfigure_monitor(monitor, modified);
 | 
						|
    if (!success)
 | 
						|
    {
 | 
						|
        *error_out = string_printf(RECONFIG_FAILED, "changing a parameter");
 | 
						|
    }
 | 
						|
    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->to_json(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 = mon->to_json(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)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    json_t* rel = nullptr;
 | 
						|
 | 
						|
    string mon_name = Monitor::get_server_monitor(server);
 | 
						|
    if (!mon_name.empty())
 | 
						|
    {
 | 
						|
        rel = mxs_json_relationship(host, MXS_JSON_API_MONITORS);
 | 
						|
        mxs_json_add_relation(rel, mon_name.c_str(), CN_MONITORS);
 | 
						|
    }
 | 
						|
 | 
						|
    return rel;
 | 
						|
}
 | 
						|
 | 
						|
bool MonitorManager::set_server_status(SERVER* srv, int bit, string* errmsg_out)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    bool written = false;
 | 
						|
    Monitor* mon = MonitorManager::server_is_monitored(srv);
 | 
						|
    if (mon)
 | 
						|
    {
 | 
						|
        written = mon->set_server_status(srv, bit, errmsg_out);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        /* Set the bit directly */
 | 
						|
        srv->set_status(bit);
 | 
						|
        written = true;
 | 
						|
    }
 | 
						|
    return written;
 | 
						|
}
 | 
						|
 | 
						|
bool MonitorManager::clear_server_status(SERVER* srv, int bit, string* errmsg_out)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    bool written = false;
 | 
						|
    Monitor* mon = MonitorManager::server_is_monitored(srv);
 | 
						|
    if (mon)
 | 
						|
    {
 | 
						|
        written = mon->clear_server_status(srv, bit, errmsg_out);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        /* Clear bit directly */
 | 
						|
        srv->clear_status(bit);
 | 
						|
        written = true;
 | 
						|
    }
 | 
						|
    return written;
 | 
						|
}
 | 
						|
 | 
						|
bool MonitorManager::add_server_to_monitor(mxs::Monitor* mon, SERVER* server, std::string* error_out)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    bool success = false;
 | 
						|
    string server_monitor = Monitor::get_server_monitor(server);
 | 
						|
    if (!server_monitor.empty())
 | 
						|
    {
 | 
						|
        // Error, server is already monitored.
 | 
						|
        string error = string_printf("Server '%s' is already monitored by '%s', ",
 | 
						|
                                     server->name(), server_monitor.c_str());
 | 
						|
        error += (server_monitor == mon->name()) ? "cannot add again to the same monitor." :
 | 
						|
            "cannot add to another monitor.";
 | 
						|
        *error_out = error;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        // To keep monitor modifications straightforward, all changes should go through the same
 | 
						|
        // reconfigure-function. As the function accepts key-value combinations (so that they are easily
 | 
						|
        // serialized), construct the value here.
 | 
						|
        MXS_CONFIG_PARAMETER modified_params = mon->parameters();
 | 
						|
        string serverlist = modified_params.get_string(CN_SERVERS);
 | 
						|
        if (serverlist.empty())
 | 
						|
        {
 | 
						|
            // Unusual.
 | 
						|
            serverlist += server->name();
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            serverlist += string(", ") + server->name();
 | 
						|
        }
 | 
						|
        modified_params.set(CN_SERVERS, serverlist);
 | 
						|
        success = reconfigure_monitor(mon, modified_params);
 | 
						|
        if (!success)
 | 
						|
        {
 | 
						|
            *error_out = string_printf(RECONFIG_FAILED, "adding a server");
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return success;
 | 
						|
}
 | 
						|
 | 
						|
bool MonitorManager::remove_server_from_monitor(mxs::Monitor* mon, SERVER* server, std::string* error_out)
 | 
						|
{
 | 
						|
    mxb_assert(Monitor::is_admin_thread());
 | 
						|
    bool success = false;
 | 
						|
    string server_monitor = Monitor::get_server_monitor(server);
 | 
						|
    if (server_monitor != mon->name())
 | 
						|
    {
 | 
						|
        // Error, server is not monitored by given monitor.
 | 
						|
        string error;
 | 
						|
        if (server_monitor.empty())
 | 
						|
        {
 | 
						|
            error = string_printf("Server '%s' is not monitored by any monitor, ", server->name());
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            error = string_printf("Server '%s' is monitored by '%s', ",
 | 
						|
                                  server->name(), server_monitor.c_str());
 | 
						|
        }
 | 
						|
        error += string_printf("cannot remove it from '%s'.", mon->name());
 | 
						|
        *error_out = error;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        // Construct the new server list
 | 
						|
        auto params = mon->parameters();
 | 
						|
        auto names = config_break_list_string(params.get_string(CN_SERVERS));
 | 
						|
        names.erase(std::remove(names.begin(), names.end(), server->name()));
 | 
						|
        std::string servers = mxb::join(names, ",");
 | 
						|
        params.set(CN_SERVERS, servers);
 | 
						|
        success = MonitorManager::reconfigure_monitor(mon, params);
 | 
						|
        if (!success)
 | 
						|
        {
 | 
						|
            *error_out = string_printf(RECONFIG_FAILED, "removing a server");
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return success;
 | 
						|
}
 |