Add credentials for remove REST API calls
The base URL and credentials used for REST API calls can now be defined in the [maxscale] section. This allows encrypted passwords to be used.
This commit is contained in:
@ -793,6 +793,24 @@ be completely disabled to prevent access to it.
|
|||||||
Log authentication failures for the admin interface. This parameter expects a
|
Log authentication failures for the admin interface. This parameter expects a
|
||||||
boolean value and is enabled by default.
|
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_
|
#### _events_
|
||||||
|
|
||||||
MaxScale logs warnings and errors for various reasons and often it is self-
|
MaxScale logs warnings and errors for various reasons and often it is self-
|
||||||
|
@ -145,6 +145,9 @@ extern const char CN_OPTIONS[];
|
|||||||
extern const char CN_PARAMETERS[];
|
extern const char CN_PARAMETERS[];
|
||||||
extern const char CN_PASSIVE[];
|
extern const char CN_PASSIVE[];
|
||||||
extern const char CN_PASSWORD[];
|
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_POLL_SLEEP[];
|
||||||
extern const char CN_PORT[];
|
extern const char CN_PORT[];
|
||||||
extern const char CN_PROTOCOL[];
|
extern const char CN_PROTOCOL[];
|
||||||
@ -275,6 +278,9 @@ typedef struct
|
|||||||
time_t users_refresh_time; /**< How often the users can be refreshed */
|
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_high_water; /**< High water mark of dcb write queue */
|
||||||
uint64_t writeq_low_water; /**< Low 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;
|
} MXS_CONFIG;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -339,17 +339,15 @@ MXS_MONITOR_API MonitorApi<MonitorInstance>::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:<rest-api-port>/v1/monitors/<name-of-monitor>`
|
* The `peer_hosts`, `peer_user` and `peer_password` parameters must have been defined for this
|
||||||
* format and must point to a single monitor resource.
|
* to work.
|
||||||
*
|
*
|
||||||
* TODO: Move the base URL and credentials into a global parameter
|
* @param name The name of the remote monitor
|
||||||
*
|
|
||||||
* @param url URL to a REST API endpoint for a monitor
|
|
||||||
*
|
*
|
||||||
* @return The host and port of the monitor or an empty string and 0 if an error occurred
|
* @return The host and port of the monitor or an empty string and 0 if an error occurred
|
||||||
*/
|
*/
|
||||||
std::pair<std::string, int> mon_get_external_master(const std::string& url);
|
std::pair<std::string, int> mon_get_external_master(const std::string& name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -662,10 +662,12 @@ struct Result
|
|||||||
* Do a HTTP GET
|
* Do a HTTP GET
|
||||||
*
|
*
|
||||||
* @param url URL to use
|
* @param url URL to use
|
||||||
|
* @param user Username to use, optional
|
||||||
|
* @param passwor Password for the user, optional
|
||||||
*
|
*
|
||||||
* @return A Result
|
* @return A Result
|
||||||
*/
|
*/
|
||||||
Result get(const std::string& url);
|
Result get(const std::string& url, const std::string& user = "", const std::string& password = "");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
#include <maxscale/paths.h>
|
#include <maxscale/paths.h>
|
||||||
#include <maxscale/pcre2.h>
|
#include <maxscale/pcre2.h>
|
||||||
#include <maxscale/router.h>
|
#include <maxscale/router.h>
|
||||||
|
#include <maxscale/secrets.h>
|
||||||
#include <maxscale/spinlock.h>
|
#include <maxscale/spinlock.h>
|
||||||
#include <maxscale/utils.h>
|
#include <maxscale/utils.h>
|
||||||
#include <maxscale/utils.hh>
|
#include <maxscale/utils.hh>
|
||||||
@ -125,6 +126,9 @@ const char CN_OPTIONS[] = "options";
|
|||||||
const char CN_PARAMETERS[] = "parameters";
|
const char CN_PARAMETERS[] = "parameters";
|
||||||
const char CN_PASSIVE[] = "passive";
|
const char CN_PASSIVE[] = "passive";
|
||||||
const char CN_PASSWORD[] = "password";
|
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_POLL_SLEEP[] = "poll_sleep";
|
||||||
const char CN_PORT[] = "port";
|
const char CN_PORT[] = "port";
|
||||||
const char CN_PROTOCOL[] = "protocol";
|
const char CN_PROTOCOL[] = "protocol";
|
||||||
@ -2439,6 +2443,28 @@ handle_global_item(const char *name, const char *value)
|
|||||||
CN_DUMP_LAST_STATEMENTS);
|
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
|
else
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@ -2624,6 +2650,10 @@ void config_set_global_defaults()
|
|||||||
gateway.passive = false;
|
gateway.passive = false;
|
||||||
gateway.promoted_at = 0;
|
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
|
// 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;
|
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_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_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_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_PASSIVE, json_boolean(cnf->passive));
|
||||||
|
|
||||||
json_object_set_new(param, CN_QUERY_CLASSIFIER, json_string(cnf->qc_name));
|
json_object_set_new(param, CN_QUERY_CLASSIFIER, json_string(cnf->qc_name));
|
||||||
|
@ -2869,7 +2869,8 @@ void MonitorInstance::run_one_tick()
|
|||||||
static bool remote_server_is_master(const std::string& url, std::string* host, int* port)
|
static bool remote_server_is_master(const std::string& url, std::string* host, int* port)
|
||||||
{
|
{
|
||||||
bool rval = false;
|
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* 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_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");
|
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;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::string, int> mon_get_external_master(const std::string& url)
|
std::pair<std::string, int> mon_get_external_master(const std::string& name)
|
||||||
{
|
{
|
||||||
std::string host;
|
std::string host;
|
||||||
int port = 0;
|
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* 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");
|
json_t* arr = mxs_json_pointer(res.body.get(), "data/relationships/servers/data");
|
||||||
|
|
||||||
|
@ -1255,7 +1255,7 @@ size_t header_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
|
|||||||
namespace http
|
namespace http
|
||||||
{
|
{
|
||||||
|
|
||||||
Result get(const std::string& url)
|
Result get(const std::string& url, const std::string& user, const std::string& password)
|
||||||
{
|
{
|
||||||
Result res;
|
Result res;
|
||||||
char errbuf[CURL_ERROR_SIZE + 1] = "";
|
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_HEADERFUNCTION, header_callback);
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &res.headers);
|
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
|
long code = 0; // needs to be a long
|
||||||
|
|
||||||
if (curl_easy_perform(curl) == CURLE_OK)
|
if (curl_easy_perform(curl) == CURLE_OK)
|
||||||
|
Reference in New Issue
Block a user