]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: cli: add check-addr command
authorWilliam Dauchy <wdauchy@gmail.com>
Thu, 11 Feb 2021 21:51:23 +0000 (22:51 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 12 Feb 2021 15:04:52 +0000 (16:04 +0100)
this patch allows to set server health check address at runtime. In
order to align with `addr` command, also allow to set port optionnaly.
This led to a small refactor in order to use the same function for both
`check-addr` and `check-port` commands.
for `check-port`, we however don't permit the change anymore if checks
are not enabled on the server.

This command becomes more and more useful for people having a consul
like architecture:
- the backend server is located on a container with its own IP
- the health checks are done the consul instance located on the host
  with the host IP

Signed-off-by: William Dauchy <wdauchy@gmail.com>
doc/management.txt
src/server.c

index b74aba7697d753644f7224acaa89c3d01050520e..bff770e4ebe1a77aca4ab372e88c874651679c17 100644 (file)
@@ -1842,6 +1842,10 @@ set server <backend>/<server> health [ up | stopping | down ]
   switch a server's state regardless of some slow health checks for example.
   Note that the change is propagated to tracking servers if any.
 
+set server <backend>/<server> check-addr <ip4 | ip6> [port <port>]
+  Change the IP address used for server health checks.
+  Optionally, change the port used for server health checks.
+
 set server <backend>/<server> check-port <port>
   Change the port used for health checking to <port>
 
index dff211f7650e43330883119026aafcc65c6cd79a..67e488742c1f1c4ddd85d860650a38032ea04ffb 100644 (file)
@@ -54,6 +54,8 @@ static int srv_set_fqdn(struct server *srv, const char *fqdn, int dns_locked);
 static void srv_state_parse_line(char *buf, const int version, char **params, char **srv_params);
 static int srv_state_get_version(FILE *f);
 static void srv_cleanup_connections(struct server *srv);
+static const char *update_server_check_addr_port(struct server *s, const char *addr,
+                                                const char *port);
 
 /* List head of all known server keywords */
 static struct srv_kw_list srv_keywords = {
@@ -3574,6 +3576,59 @@ int update_server_addr(struct server *s, void *ip, int ip_sin_family, const char
        return 0;
 }
 
+/* update server health check address and port
+ * addr must be ip4 or ip6, it won't be resolved
+ * if one error occurs, don't apply anything
+ * must be called with the server lock held.
+ */
+static const char *update_server_check_addr_port(struct server *s, const char *addr,
+                                                const char *port)
+{
+       struct sockaddr_storage sk;
+       struct buffer *msg;
+       int new_port;
+
+       msg = get_trash_chunk();
+       chunk_reset(msg);
+
+       if (!(s->check.state & CHK_ST_ENABLED)) {
+               chunk_strcat(msg, "health checks are not enabled on this server");
+               goto out;
+       }
+       if (addr) {
+               memset(&sk, 0, sizeof(struct sockaddr_storage));
+               if (str2ip2(addr, &sk, 0) == NULL) {
+                       chunk_appendf(msg, "invalid addr '%s'", addr);
+                       goto out;
+               }
+       }
+       if (port) {
+               if (strl2irc(port, strlen(port), &new_port) != 0) {
+                       chunk_appendf(msg, "provided port is not an integer");
+                       goto out;
+               }
+               if (new_port < 0 || new_port > 65535) {
+                       chunk_appendf(msg, "provided port is invalid");
+                       goto out;
+               }
+               /* prevent the update of port to 0 if MAPPORTS are in use */
+               if ((s->flags & SRV_F_MAPPORTS) && new_port == 0) {
+                       chunk_appendf(msg, "can't unset 'port' since MAPPORTS is in use");
+                       goto out;
+               }
+       }
+out:
+       if (msg->data)
+               return msg->area;
+       else {
+               if (addr)
+                       s->check.addr = sk;
+               if (port)
+                       s->check.port = new_port;
+       }
+       return NULL;
+}
+
 /*
  * This function update a server's addr and port only for AF_INET and AF_INET6 families.
  *
@@ -4406,23 +4461,32 @@ static int cli_parse_set_server(char **args, char *payload, struct appctx *appct
                                cli_err(appctx, "cannot allocate memory for new string.\n");
                }
        }
-       else if (strcmp(args[3], "check-port") == 0) {
-               int i = 0;
-               if (strl2irc(args[4], strlen(args[4]), &i) != 0) {
-                       cli_err(appctx, "'set server <srv> check-port' expects an integer as argument.\n");
-                       goto out_unlock;
-               }
-               if ((i < 0) || (i > 65535)) {
-                       cli_err(appctx, "provided port is not valid.\n");
+       else if (strcmp(args[3], "check-addr") == 0) {
+               char *addr = NULL;
+               char *port = NULL;
+               if (strlen(args[4]) == 0) {
+                       cli_err(appctx, "set server <b>/<s> check-addr requires"
+                                       " an address and optionally a port.\n");
                        goto out_unlock;
                }
-               /* prevent the update of port to 0 if MAPPORTS are in use */
-               if ((sv->flags & SRV_F_MAPPORTS) && (i == 0)) {
-                       cli_err(appctx, "can't unset 'port' since MAPPORTS is in use.\n");
+               addr = args[4];
+               if (strcmp(args[5], "port") == 0)
+                       port = args[6];
+               warning = update_server_check_addr_port(sv, addr, port);
+               if (warning)
+                       cli_msg(appctx, LOG_WARNING, warning);
+       }
+       else if (strcmp(args[3], "check-port") == 0) {
+               char *port = NULL;
+               if (strlen(args[4]) == 0) {
+                       cli_err(appctx, "set server <b>/<s> check-port requires"
+                                       " a port.\n");
                        goto out_unlock;
                }
-               sv->check.port = i;
-               cli_msg(appctx, LOG_NOTICE, "health check port updated.\n");
+               port = args[4];
+               warning = update_server_check_addr_port(sv, NULL, port);
+               if (warning)
+                       cli_msg(appctx, LOG_WARNING, warning);
        }
        else if (strcmp(args[3], "addr") == 0) {
                char *addr = NULL;
@@ -4476,8 +4540,9 @@ static int cli_parse_set_server(char **args, char *payload, struct appctx *appct
 #endif
        } else {
                cli_err(appctx,
-                       "'set server <srv>' only supports 'agent', 'health', 'state',"
-                       " 'weight', 'addr', 'fqdn', 'check-port' and 'ssl'.\n");
+                       "'set server <srv>' only supports 'agent', 'health', "
+                       "'state', 'weight', 'addr', 'fqdn', 'check-addr', "
+                       "'check-port' and 'ssl'.\n");
        }
  out_unlock:
        HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);