From: Baptiste Assmann Date: Mon, 2 Jul 2018 15:00:54 +0000 (+0200) Subject: BUG/MEDIUM: dns/server: fix incomatibility between SRV resolution and server state... X-Git-Tag: v1.9-dev2~102 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6d0f38f00dd7191f8502cfd0b6c96399370b786b;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: dns/server: fix incomatibility between SRV resolution and server state file Server state file has no indication that a server is currently managed by a DNS SRV resolution. And thus, both feature (DNS SRV resolution and server state), when used together, does not provide the expected behavior: a smooth experience... This patch introduce the "SRV record name" in the server state file and loads and applies it if found and wherever required. This patch applies to haproxy-dev branch only. For backport, a specific patch is provided for 1.8. --- diff --git a/doc/management.txt b/doc/management.txt index c78dc74862..17f15059e8 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -2130,6 +2130,7 @@ show servers state [] configuration. srv_fqdn: Server FQDN. srv_port: Server port. + srvrecord: DNS SRV record associated to this SRV. 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 88259281d1..8adc29baf6 100644 --- a/include/types/server.h +++ b/include/types/server.h @@ -126,10 +126,11 @@ enum srv_initaddr { "bk_f_forced_id " \ "srv_f_forced_id " \ "srv_fqdn " \ - "srv_port" + "srv_port " \ + "srvrecord" -#define SRV_STATE_FILE_MAX_FIELDS 19 -#define SRV_STATE_FILE_NB_FIELDS_VERSION_1 18 +#define SRV_STATE_FILE_MAX_FIELDS 20 +#define SRV_STATE_FILE_NB_FIELDS_VERSION_1 19 #define SRV_STATE_LINE_MAXLEN 512 /* server flags -- 32 bits */ diff --git a/src/proxy.c b/src/proxy.c index 73aa1187a7..c939e820c7 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -1429,6 +1429,7 @@ static int dump_servers_state(struct stream_interface *si, struct buffer *buf) char srv_addr[INET6_ADDRSTRLEN + 1]; time_t srv_time_since_last_change; int bk_f_forced_id, srv_f_forced_id; + char *srvrecord; /* we don't want to report any state if the backend is not enabled on this process */ if (px->bind_proc && !(px->bind_proc & pid_bit)) @@ -1458,18 +1459,23 @@ static int dump_servers_state(struct stream_interface *si, struct buffer *buf) bk_f_forced_id = px->options & PR_O_FORCED_ID ? 1 : 0; srv_f_forced_id = srv->flags & SRV_F_FORCED_ID ? 1 : 0; + srvrecord = NULL; + if (srv->srvrq && srv->srvrq->name) + srvrecord = srv->srvrq->name; + chunk_appendf(buf, "%d %s " "%d %s %s " "%d %d %d %d %ld " "%d %d %d %d %d " - "%d %d %s %u" + "%d %d %s %u %s" "\n", px->uuid, px->id, srv->puid, srv->id, srv_addr, srv->cur_state, srv->cur_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, srv->hostname ? srv->hostname : "-", srv->svc_port); + bk_f_forced_id, srv_f_forced_id, srv->hostname ? srv->hostname : "-", srv->svc_port, + srvrecord ? srvrecord : "-"); if (ci_putchk(si_ic(si), &trash) == -1) { si_applet_cant_put(si); return 0; diff --git a/src/server.c b/src/server.c index 78d5a0fcc3..766f5ded1c 100644 --- a/src/server.c +++ b/src/server.c @@ -2758,6 +2758,7 @@ static void srv_update_state(struct server *srv, int version, char **params) const char *fqdn; const char *port_str; unsigned int port; + char *srvrecord; fqdn = NULL; port = 0; @@ -2781,6 +2782,7 @@ static void srv_update_state(struct server *srv, int version, char **params) * srv_f_forced_id: params[12] * srv_fqdn: params[13] * srv_port: params[14] + * srvrecord: params[15] */ /* validating srv_op_state */ @@ -2913,6 +2915,13 @@ static void srv_update_state(struct server *srv, int version, char **params) } } + /* SRV record + * NOTE: in HAProxy, SRV records must start with an underscore '_' + */ + srvrecord = params[15]; + if (srvrecord && *srvrecord != '_') + srvrecord = NULL; + /* don't apply anything if one error has been detected */ if (msg->data) goto out; @@ -3045,6 +3054,48 @@ static void srv_update_state(struct server *srv, int version, char **params) } } } + /* If all the conditions below are validated, this means + * we're evaluating a server managed by SRV resolution + */ + else if (fqdn && !srv->hostname && srvrecord) { + int res; + + /* we can't apply previous state if SRV record has changed */ + if (srv->srvrq && strcmp(srv->srvrq->name, srvrecord) != 0) { + chunk_appendf(msg, ", SRV record mismatch between configuration ('%s') and state file ('%s) for server '%s'. Previous state not applied", srv->srvrq->name, srvrecord, srv->id); + HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock); + goto out; + } + + /* create or find a SRV resolution for this srv record */ + if (srv->srvrq == NULL && (srv->srvrq = find_srvrq_by_name(srvrecord, srv->proxy)) == NULL) + srv->srvrq = new_dns_srvrq(srv, srvrecord); + if (srv->srvrq == NULL) { + chunk_appendf(msg, ", can't create or find SRV resolution '%s' for server '%s'", srvrecord, srv->id); + HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock); + goto out; + } + + /* prepare DNS resolution for this server */ + res = srv_prepare_for_resolution(srv, fqdn); + if (res == -1) { + chunk_appendf(msg, ", can't allocate memory for DNS resolution for server '%s'", srv->id); + HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock); + goto out; + } + + /* configure check.port accordingly */ + if ((srv->check.state & CHK_ST_CONFIGURED) && + !(srv->flags & SRV_F_CHECKPORT)) + srv->check.port = port; + + /* Unset SRV_F_MAPPORTS for SRV records. + * SRV_F_MAPPORTS is unfortunately set by parse_server() + * because no ports are provided in the configuration file. + * This is because HAProxy will use the port found into the SRV record. + */ + srv->flags &= ~SRV_F_MAPPORTS; + } if (port_str) srv->svc_port = port; @@ -3301,6 +3352,7 @@ void apply_server_state(void) * srv_f_forced_id: params[16] => srv_params[12] * srv_fqdn: params[17] => srv_params[13] * srv_port: params[18] => srv_params[14] + * srvrecord: params[19] => srv_params[15] */ if (arg >= 4) { srv_params[srv_arg] = cur;