diff --git a/Documentation/Getting-Started/Configuration-Guide.md b/Documentation/Getting-Started/Configuration-Guide.md index e22d5341a..e65a8a3b2 100644 --- a/Documentation/Getting-Started/Configuration-Guide.md +++ b/Documentation/Getting-Started/Configuration-Guide.md @@ -793,6 +793,24 @@ be completely disabled to prevent access to it. Log authentication failures for the admin interface. This parameter expects a boolean value and is enabled by default. +#### `peer_hosts` + +The REST API URL of a remote peer MaxScale. This is used to communicate with +other MaxScale instances and can be a required parameter for some other features +in MaxScale. + +Note that currently only one URL is supported. Defining more than one is +considered a configuration error. + +#### `peer_user` + +Username used when connecting to remote MaxScale instances. + +#### `peer_password` + +Password used when connecting to remote MaxScale instances. This password can be +encrypted with `maxpasswd`. + #### _events_ MaxScale logs warnings and errors for various reasons and often it is self- diff --git a/include/maxscale/config.h b/include/maxscale/config.h index c2e2e31a7..a91af3f61 100644 --- a/include/maxscale/config.h +++ b/include/maxscale/config.h @@ -145,6 +145,9 @@ extern const char CN_OPTIONS[]; extern const char CN_PARAMETERS[]; extern const char CN_PASSIVE[]; extern const char CN_PASSWORD[]; +extern const char CN_PEER_HOSTS[]; +extern const char CN_PEER_PASSWORD[]; +extern const char CN_PEER_USER[]; extern const char CN_POLL_SLEEP[]; extern const char CN_PORT[]; extern const char CN_PROTOCOL[]; @@ -275,6 +278,9 @@ typedef struct time_t users_refresh_time; /**< How often the users can be refreshed */ uint64_t writeq_high_water; /**< High water mark of dcb write queue */ uint64_t writeq_low_water; /**< Low water mark of dcb write queue */ + char peer_hosts[MAX_ADMIN_HOST_LEN]; /**< The protocol, address and port for peers (currently only one) */ + char peer_user[MAX_ADMIN_HOST_LEN]; /**< Username for maxscale-to-maxscale traffic */ + char peer_password[MAX_ADMIN_HOST_LEN]; /**< Password for maxscale-to-maxscale traffic */ } MXS_CONFIG; /** diff --git a/include/maxscale/monitor.hh b/include/maxscale/monitor.hh index 30baf48ca..4e9801661 100644 --- a/include/maxscale/monitor.hh +++ b/include/maxscale/monitor.hh @@ -339,17 +339,15 @@ MXS_MONITOR_API MonitorApi::s_api = }; /** - * Get the master server of the monitor pointed by @c url + * Get the master server of the remote monitor * - * The URL must be in `http://hostname-of-maxscale:/v1/monitors/` - * format and must point to a single monitor resource. + * The `peer_hosts`, `peer_user` and `peer_password` parameters must have been defined for this + * to work. * - * TODO: Move the base URL and credentials into a global parameter - * - * @param url URL to a REST API endpoint for a monitor + * @param name The name of the remote monitor * * @return The host and port of the monitor or an empty string and 0 if an error occurred */ -std::pair mon_get_external_master(const std::string& url); +std::pair mon_get_external_master(const std::string& name); } diff --git a/include/maxscale/utils.hh b/include/maxscale/utils.hh index a87d5c4ef..01971f239 100644 --- a/include/maxscale/utils.hh +++ b/include/maxscale/utils.hh @@ -662,10 +662,12 @@ struct Result * Do a HTTP GET * * @param url URL to use + * @param user Username to use, optional + * @param passwor Password for the user, optional * * @return A Result */ -Result get(const std::string& url); +Result get(const std::string& url, const std::string& user = "", const std::string& password = ""); } diff --git a/server/core/config.cc b/server/core/config.cc index 3c6e59fda..31a3817ed 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -125,6 +126,9 @@ const char CN_OPTIONS[] = "options"; const char CN_PARAMETERS[] = "parameters"; const char CN_PASSIVE[] = "passive"; const char CN_PASSWORD[] = "password"; +const char CN_PEER_HOSTS[] = "peer_hosts"; +const char CN_PEER_PASSWORD[] = "peer_password"; +const char CN_PEER_USER[] = "peer_user"; const char CN_POLL_SLEEP[] = "poll_sleep"; const char CN_PORT[] = "port"; const char CN_PROTOCOL[] = "protocol"; @@ -2439,6 +2443,28 @@ handle_global_item(const char *name, const char *value) CN_DUMP_LAST_STATEMENTS); } } + else if (strcmp(name, CN_PEER_HOSTS) == 0) + { + if (strchr(value, ',')) + { + MXS_ERROR("Only a single host in '%s' is currently supported", CN_PEER_HOSTS); + return 0; + } + else + { + strcpy(gateway.peer_hosts, value); + } + } + else if (strcmp(name, CN_PEER_USER) == 0) + { + strcpy(gateway.peer_user, value); + } + else if (strcmp(name, CN_PEER_PASSWORD) == 0) + { + char* pw = decrypt_password(value); + strcpy(gateway.peer_password, pw); + MXS_FREE(pw); + } else { bool found = false; @@ -2624,6 +2650,10 @@ void config_set_global_defaults() gateway.passive = false; gateway.promoted_at = 0; + gateway.peer_hosts[0] = '\0'; + gateway.peer_user[0] = '\0'; + gateway.peer_password[0] = '\0'; + // Note: This is not a valid cache value: it is used to detect that the default value is used gateway.qc_cache_properties.max_size = -1; @@ -4261,6 +4291,8 @@ json_t* config_maxscale_to_json(const char* host) json_object_set_new(param, CN_ADMIN_SSL_KEY, json_string(cnf->admin_ssl_key)); json_object_set_new(param, CN_ADMIN_SSL_CERT, json_string(cnf->admin_ssl_cert)); json_object_set_new(param, CN_ADMIN_SSL_CA_CERT, json_string(cnf->admin_ssl_ca_cert)); + json_object_set_new(param, CN_PEER_HOSTS, json_string(cnf->peer_hosts)); + json_object_set_new(param, CN_PEER_USER, json_string(cnf->peer_user)); json_object_set_new(param, CN_PASSIVE, json_boolean(cnf->passive)); json_object_set_new(param, CN_QUERY_CLASSIFIER, json_string(cnf->qc_name)); diff --git a/server/core/monitor.cc b/server/core/monitor.cc index e0c8f0471..eaa31ac32 100644 --- a/server/core/monitor.cc +++ b/server/core/monitor.cc @@ -2869,7 +2869,8 @@ void MonitorInstance::run_one_tick() static bool remote_server_is_master(const std::string& url, std::string* host, int* port) { bool rval = false; - auto res = mxs::http::get(url); + auto res = mxs::http::get(url, config_get_global_options()->peer_user, + config_get_global_options()->peer_password); json_t* state = mxs_json_pointer(res.body.get(), "data/attributes/state"); json_t* json_host = mxs_json_pointer(res.body.get(), "data/attributes/parameters/address"); json_t* json_port = mxs_json_pointer(res.body.get(), "data/attributes/parameters/port"); @@ -2889,12 +2890,16 @@ static bool remote_server_is_master(const std::string& url, std::string* host, i return rval; } -std::pair mon_get_external_master(const std::string& url) +std::pair mon_get_external_master(const std::string& name) { std::string host; int port = 0; + std::string url = config_get_global_options()->peer_hosts; + + auto res = mxs::http::get(url + "/v1/monitors/" + name, + config_get_global_options()->peer_user, + config_get_global_options()->peer_password); - auto res = mxs::http::get(url); json_t* remote = mxs_json_pointer(res.body.get(), "data/relationships/servers/links/self"); json_t* arr = mxs_json_pointer(res.body.get(), "data/relationships/servers/data"); diff --git a/server/core/utils.cc b/server/core/utils.cc index 00bb660a2..19e554e4e 100644 --- a/server/core/utils.cc +++ b/server/core/utils.cc @@ -1255,7 +1255,7 @@ size_t header_callback(char *ptr, size_t size, size_t nmemb, void *userdata) namespace http { -Result get(const std::string& url) +Result get(const std::string& url, const std::string& user, const std::string& password) { Result res; char errbuf[CURL_ERROR_SIZE + 1] = ""; @@ -1271,6 +1271,12 @@ Result get(const std::string& url) curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &res.headers); + if (!user.empty() && !password.empty()) + { + curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + curl_easy_setopt(curl, CURLOPT_USERPWD, (user + ":" + password).c_str()); + } + long code = 0; // needs to be a long if (curl_easy_perform(curl) == CURLE_OK)