MINOR: server: cli: Add server FQDNs to server-state file and stats socket.
This patch adds a new stats socket command to modify server
FQDNs at run time.
Its syntax:
set server <backend>/<server> fqdn <FQDN>
This patch also adds FQDNs to server state file at the end
of each line for backward compatibility ("-" if not present).
diff --git a/doc/management.txt b/doc/management.txt
index 3368277..d1ea1f6 100644
--- a/doc/management.txt
+++ b/doc/management.txt
@@ -1650,6 +1650,9 @@
Change a server's weight to the value passed in argument. This is the exact
equivalent of the "set weight" command below.
+set server <backend>/<server> fqdn <FQDN>
+ Change a server's FQDN to the value passed in argument.
+
set ssl ocsp-response <response>
This command is used to update an OCSP Response for a certificate (see "crt"
on "bind" lines). Same controls are performed as during the initial loading of
@@ -1962,6 +1965,9 @@
0x20 = SRV_ADMF_RMAINT
The server is in maintenance because of an
IP address resolution failure.
+ 0x40 = SRV_ADMF_HMAINT
+ The server FQDN was set from stats socket.
+
srv_uweight: User visible server's weight.
srv_iweight: Server's initial weight.
srv_time_since_last_change: Time since last operational change.
@@ -2003,6 +2009,7 @@
configuration.
srv_f_forced_id: Flag to know if the server's ID is forced by
configuration.
+ srv_fqdn: Server FQDN.
show sess
Dump all known sessions. Avoid doing this on slow connections as this can
diff --git a/include/types/server.h b/include/types/server.h
index 8d68dcb..83b1e80 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -82,6 +82,7 @@
SRV_ADMF_IDRAIN = 0x10, /* the server has inherited the drain status from a tracked server */
SRV_ADMF_DRAIN = 0x18, /* mask to check if any drain flag is present */
SRV_ADMF_RMAINT = 0x20, /* the server is down because of an IP address resolution failure */
+ SRV_ADMF_HMAINT = 0x40, /* the server FQDN has been set from socket stats */
};
/* options for servers' "init-addr" parameter
@@ -103,7 +104,26 @@
#define SRV_STATE_FILE_VERSION 1
#define SRV_STATE_FILE_VERSION_MIN 1
#define SRV_STATE_FILE_VERSION_MAX 1
-#define SRV_STATE_FILE_FIELD_NAMES "be_id be_name srv_id srv_name srv_addr srv_op_state srv_admin_state srv_uweight srv_iweight srv_time_since_last_change srv_check_status srv_check_result srv_check_health srv_check_state srv_agent_state bk_f_forced_id srv_f_forced_id"
+#define SRV_STATE_FILE_FIELD_NAMES \
+ "be_id " \
+ "be_name " \
+ "srv_id " \
+ "srv_name " \
+ "srv_addr " \
+ "srv_op_state " \
+ "srv_admin_state " \
+ "srv_uweight " \
+ "srv_iweight " \
+ "srv_time_since_last_change " \
+ "srv_check_status " \
+ "srv_check_result " \
+ "srv_check_health " \
+ "srv_check_state " \
+ "srv_agent_state " \
+ "bk_f_forced_id " \
+ "srv_f_forced_id " \
+ "srv_fqdn"
+
#define SRV_STATE_FILE_MAX_FIELDS 18
#define SRV_STATE_FILE_NB_FIELDS_VERSION_1 18
#define SRV_STATE_LINE_MAXLEN 512
diff --git a/src/cfgparse.c b/src/cfgparse.c
index d44949a..f167321 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -8492,8 +8492,6 @@
newsrv->id, newsrv->resolvers_id);
cfgerr++;
} else {
- free(newsrv->resolvers_id);
- newsrv->resolvers_id = NULL;
if (newsrv->resolution)
newsrv->resolution->resolvers = curr_resolvers;
}
diff --git a/src/proxy.c b/src/proxy.c
index dc70213..f6a3214 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -1458,13 +1458,13 @@
"%d %s %s "
"%d %d %d %d %ld "
"%d %d %d %d %d "
- "%d %d"
+ "%d %d %s"
"\n",
px->uuid, px->id,
srv->puid, srv->id, srv_addr,
srv->state, srv->admin, srv->uweight, srv->iweight, (long int)srv_time_since_last_change,
srv->check.status, srv->check.result, srv->check.health, srv->check.state, srv->agent.state,
- bk_f_forced_id, srv_f_forced_id);
+ bk_f_forced_id, srv_f_forced_id, srv->hostname ? srv->hostname : "-");
if (bi_putchk(si_ic(si), &trash) == -1) {
si_applet_cant_put(si);
return 0;
diff --git a/src/server.c b/src/server.c
index 69c1ec3..85da083 100644
--- a/src/server.c
+++ b/src/server.c
@@ -46,6 +46,7 @@
static void srv_update_state(struct server *srv, int version, char **params);
static int srv_apply_lastaddr(struct server *srv, int *err_code);
+static int srv_set_fqdn(struct server *srv, const char *fqdn);
/* List head of all known server keywords */
static struct srv_kw_list srv_keywords = {
@@ -1652,16 +1653,18 @@
/*
* Allocate <srv> server dns resolution.
* May be safely called with a default server as <src> argument (without hostname).
+ * Returns -1 in case of any allocation failure, 0 if not.
*/
-static void srv_alloc_dns_resolution(struct server *srv, const char *hostname)
+static int srv_alloc_dns_resolution(struct server *srv, const char *hostname)
{
char *hostname_dn;
int hostname_dn_len;
struct dns_resolution *dst_dns_rslt;
if (!hostname)
- return;
+ return 0;
+ free(srv->hostname);
srv->hostname = strdup(hostname);
dst_dns_rslt = calloc(1, sizeof *dst_dns_rslt);
hostname_dn_len = dns_str_to_dn_label_len(hostname);
@@ -1687,13 +1690,41 @@
/* a first resolution has been done by the configuration parser */
srv->resolution->last_resolution = 0;
- return;
+ if (srv->resolvers_id) {
+ struct dns_resolvers *curr_resolvers;
+ int found = 0;
+
+ list_for_each_entry(curr_resolvers, &dns_resolvers, list) {
+ if (!strcmp(curr_resolvers->id, srv->resolvers_id)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ goto err;
+ srv->resolution->resolvers = curr_resolvers;
+ }
+ else
+ goto err;
+
+ return 0;
err:
free(srv->hostname);
srv->hostname = NULL;
free(hostname_dn);
free(dst_dns_rslt);
+ return -1;
+}
+
+static void srv_free_dns_resolution(struct server *srv)
+{
+ if (!srv->resolution)
+ return;
+
+ free(srv->resolution->hostname_dn);
+ free(srv->resolution);
+ srv->resolution = NULL;
}
/*
@@ -2888,7 +2919,10 @@
int srv_check_state, srv_agent_state;
int bk_f_forced_id;
int srv_f_forced_id;
+ int fqdn_set_by_cli;
+ const char *fqdn;
+ fqdn = NULL;
msg = get_trash_chunk();
switch (version) {
case 1:
@@ -2907,6 +2941,7 @@
* srv_agent_state: params[10]
* bk_f_forced_id: params[11]
* srv_f_forced_id: params[12]
+ * srv_fqdn: params[13]
*/
/* validating srv_op_state */
@@ -2925,9 +2960,12 @@
p = NULL;
errno = 0;
srv_admin_state = strtol(params[2], &p, 10);
+ fqdn_set_by_cli = !!(srv_admin_state & SRV_ADMF_HMAINT);
- /* inherited statuses will be recomputed later */
- srv_admin_state &= ~SRV_ADMF_IDRAIN & ~SRV_ADMF_IMAINT;
+ /* inherited statuses will be recomputed later.
+ * Also disable SRV_ADMF_HMAINT flag (set from stats socket fqdn).
+ */
+ srv_admin_state &= ~SRV_ADMF_IDRAIN & ~SRV_ADMF_IMAINT & ~SRV_ADMF_HMAINT;
if ((p == params[2]) || errno == EINVAL || errno == ERANGE ||
(srv_admin_state != 0 &&
@@ -3018,6 +3056,14 @@
if (p == params[12] || errno == EINVAL || errno == ERANGE || !((srv_f_forced_id == 0) || (srv_f_forced_id == 1)))
chunk_appendf(msg, ", invalid srv_f_forced_id value '%s'", params[12]);
+ /* validating srv_fqdn */
+ fqdn = params[13];
+ if (fqdn && *fqdn == '-')
+ fqdn = NULL;
+ if (fqdn && (strlen(fqdn) > DNS_MAX_NAME_SIZE || invalid_domainchar(fqdn))) {
+ chunk_appendf(msg, ", invalid srv_fqdn value '%s'", params[13]);
+ fqdn = NULL;
+ }
/* don't apply anything if one error has been detected */
if (msg->len)
@@ -3122,6 +3168,34 @@
/* load server IP address */
srv->lastaddr = strdup(params[0]);
+
+ if (fqdn && srv->hostname) {
+ if (!strcmp(srv->hostname, fqdn)) {
+ /* Here we reset the 'set from stats socket FQDN' flag
+ * to support such transitions:
+ * Let's say initial FQDN value is foo1 (in configuration file).
+ * - FQDN changed from stats socket, from foo1 to foo2 value,
+ * - FQDN changed again from file configuration (with the same previous value
+ set from stats socket, from foo1 to foo2 value),
+ * - reload for any other reason than a FQDN modification,
+ * the configuration file FQDN matches the fqdn server state file value.
+ * So we must reset the 'set from stats socket FQDN' flag to be consistent with
+ * any futher FQDN modification.
+ */
+ srv->admin &= ~SRV_ADMF_HMAINT;
+ }
+ else {
+ /* If the FDQN has been changed from stats socket,
+ * apply fqdn state file value (which is the value set
+ * from stats socket).
+ */
+ if (fqdn_set_by_cli) {
+ srv_set_fqdn(srv, fqdn);
+ srv->admin |= SRV_ADMF_HMAINT;
+ }
+ }
+ }
+
break;
default:
chunk_appendf(msg, ", version '%d' not supported", version);
@@ -3152,8 +3226,8 @@
char *cur, *end;
char mybuf[SRV_STATE_LINE_MAXLEN];
int mybuflen;
- char *params[SRV_STATE_FILE_MAX_FIELDS];
- char *srv_params[SRV_STATE_FILE_MAX_FIELDS];
+ char *params[SRV_STATE_FILE_MAX_FIELDS] = {0};
+ char *srv_params[SRV_STATE_FILE_MAX_FIELDS] = {0};
int arg, srv_arg, version, diff;
FILE *f;
char *filepath;
@@ -3331,12 +3405,18 @@
while (isspace(*cur))
++cur;
- if (cur == end)
+ /* Ignore empty or commented lines */
+ if (cur == end || *cur == '#')
continue;
- /* ignore comment line */
- if (*cur == '#')
+ /* truncated lines */
+ if (mybuf[mybuflen - 1] != '\n') {
+ Warning("server-state file '%s': truncated line\n", filepath);
continue;
+ }
+
+ /* Removes trailing '\n' */
+ mybuf[mybuflen - 1] = '\0';
/* we're now ready to move the line into *srv_params[] */
params[0] = cur;
@@ -3364,6 +3444,7 @@
* srv_agent_state: params[14] => srv_params[10]
* bk_f_forced_id: params[15] => srv_params[11]
* srv_f_forced_id: params[16] => srv_params[12]
+ * srv_fqdn: params[17] => srv_params[13]
*/
if (arg >= 4) {
srv_params[srv_arg] = cur;
@@ -4016,6 +4097,16 @@
return 0;
}
+/* Set the server's FDQN (->hostname) from <hostname>.
+ * Returns -1 if failed, 0 if not.
+ */
+int srv_set_fqdn(struct server *srv, const char *hostname)
+{
+ srv_free_dns_resolution(srv);
+
+ return srv_alloc_dns_resolution(srv, hostname);
+}
+
/* Sets the server's address (srv->addr) from srv->lastaddr which was filled
* from the state file. This is suited for initial address configuration.
* Returns 0 on success otherwise a non-zero error code. In case of error,
@@ -4139,6 +4230,46 @@
return return_code;
}
+const char *update_server_fqdn(struct server *server, const char *fqdn, const char *updater)
+{
+
+ struct chunk *msg;
+
+ msg = get_trash_chunk();
+ chunk_reset(msg);
+
+ if (!strcmp(fqdn, server->hostname)) {
+ chunk_appendf(msg, "no need to change the FDQN");
+ goto out;
+ }
+
+ if (strlen(fqdn) > DNS_MAX_NAME_SIZE || invalid_domainchar(fqdn)) {
+ chunk_appendf(msg, "invalid fqdn '%s'", fqdn);
+ goto out;
+ }
+
+ chunk_appendf(msg, "%s/%s changed its FQDN from %s to %s",
+ server->proxy->id, server->id, server->hostname, fqdn);
+
+ if (srv_set_fqdn(server, fqdn) < 0) {
+ chunk_reset(msg);
+ chunk_appendf(msg, "could not update %s/%s FQDN",
+ server->proxy->id, server->id);
+ goto out;
+ }
+
+ /* Flag as FQDN set from stats socket. */
+ server->admin |= SRV_ADMF_HMAINT;
+
+ out:
+ if (updater)
+ chunk_appendf(msg, " by '%s'", updater);
+ chunk_appendf(msg, "\n");
+
+ return msg->str;
+}
+
+
/* Expects to find a backend and a server in <arg> under the form <backend>/<server>,
* and returns the pointer to the server. Otherwise, display adequate error messages
* on the CLI, sets the CLI's state to CLI_ST_PRINT and returns NULL. This is only
@@ -4319,8 +4450,20 @@
}
srv_clr_admin_flag(sv, SRV_ADMF_RMAINT);
}
+ else if (strcmp(args[3], "fqdn") == 0) {
+ if (!*args[4]) {
+ appctx->ctx.cli.msg = "set server <b>/<s> fqdn requires a FQDN.\n";
+ appctx->st0 = CLI_ST_PRINT;
+ return 1;
+ }
+ warning = update_server_fqdn(sv, args[4], "stats socket command");
+ if (warning) {
+ appctx->ctx.cli.msg = warning;
+ appctx->st0 = CLI_ST_PRINT;
+ }
+ }
else {
- appctx->ctx.cli.msg = "'set server <srv>' only supports 'agent', 'health', 'state', 'weight', 'addr' and 'check-port'.\n";
+ appctx->ctx.cli.msg = "'set server <srv>' only supports 'agent', 'health', 'state', 'weight', 'addr', 'fqdn' and 'check-port'.\n";
appctx->st0 = CLI_ST_PRINT;
}
return 1;