mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-03-31 23:58:16 +00:00
MINOR: checks: update dynamic environment variables in external checks
commit 9ede66b0
introduced an environment variable (HAPROXY_SERVER_CURCONN) that
was supposed to be dynamically updated, but it was set only once, during its
initialization.
Most of the code provided in this previous patch has been rewritten in order to
easily update the environment variables without reallocating memory during each
check.
Now, HAPROXY_SERVER_CURCONN will contain the current number of connections on
the server at the time of the check.
This commit is contained in:
parent
56efc4896b
commit
ac92a065d7
@ -80,6 +80,32 @@ enum {
|
||||
HCHK_STATUS_SIZE
|
||||
};
|
||||
|
||||
/* environment variables memory requirement for different types of data */
|
||||
#define EXTCHK_SIZE_EVAL_INIT 0 /* size determined during the init phase,
|
||||
* such environment variables are not updatable. */
|
||||
#define EXTCHK_SIZE_ULONG 20 /* max string length for an unsigned long value */
|
||||
|
||||
/* external checks environment variables */
|
||||
enum {
|
||||
EXTCHK_PATH = 0,
|
||||
|
||||
/* Proxy specific environment variables */
|
||||
EXTCHK_HAPROXY_PROXY_NAME, /* the backend name */
|
||||
EXTCHK_HAPROXY_PROXY_ID, /* the backend id */
|
||||
EXTCHK_HAPROXY_PROXY_ADDR, /* the first bind address if available (or empty) */
|
||||
EXTCHK_HAPROXY_PROXY_PORT, /* the first bind port if available (or empty) */
|
||||
|
||||
/* Server specific environment variables */
|
||||
EXTCHK_HAPROXY_SERVER_NAME, /* the server name */
|
||||
EXTCHK_HAPROXY_SERVER_ID, /* the server id */
|
||||
EXTCHK_HAPROXY_SERVER_ADDR, /* the server address */
|
||||
EXTCHK_HAPROXY_SERVER_PORT, /* the server port if available (or empty) */
|
||||
EXTCHK_HAPROXY_SERVER_MAXCONN, /* the server max connections */
|
||||
EXTCHK_HAPROXY_SERVER_CURCONN, /* the current number of connections on the server */
|
||||
|
||||
EXTCHK_SIZE
|
||||
};
|
||||
|
||||
|
||||
/* health status for response tracking */
|
||||
enum {
|
||||
@ -161,6 +187,11 @@ struct check_status {
|
||||
char *desc; /* long description */
|
||||
};
|
||||
|
||||
struct extcheck_env {
|
||||
char *name; /* environment variable name */
|
||||
int vmaxlen; /* value maximum length, used to determine the required memory allocation */
|
||||
};
|
||||
|
||||
struct analyze_status {
|
||||
char *desc; /* description */
|
||||
unsigned char lr[HANA_OBS_SIZE]; /* result for l4/l7: 0 = ignore, 1 - error, 2 - OK */
|
||||
|
124
src/checks.c
124
src/checks.c
@ -96,6 +96,20 @@ static const struct check_status check_statuses[HCHK_STATUS_SIZE] = {
|
||||
[HCHK_STATUS_PROCOK] = { CHK_RES_PASSED, "PROCOK", "External check passed" },
|
||||
};
|
||||
|
||||
const struct extcheck_env extcheck_envs[EXTCHK_SIZE] = {
|
||||
[EXTCHK_PATH] = { "PATH", EXTCHK_SIZE_EVAL_INIT },
|
||||
[EXTCHK_HAPROXY_PROXY_NAME] = { "HAPROXY_PROXY_NAME", EXTCHK_SIZE_EVAL_INIT },
|
||||
[EXTCHK_HAPROXY_PROXY_ID] = { "HAPROXY_PROXY_ID", EXTCHK_SIZE_EVAL_INIT },
|
||||
[EXTCHK_HAPROXY_PROXY_ADDR] = { "HAPROXY_PROXY_ADDR", EXTCHK_SIZE_EVAL_INIT },
|
||||
[EXTCHK_HAPROXY_PROXY_PORT] = { "HAPROXY_PROXY_PORT", EXTCHK_SIZE_EVAL_INIT },
|
||||
[EXTCHK_HAPROXY_SERVER_NAME] = { "HAPROXY_SERVER_NAME", EXTCHK_SIZE_EVAL_INIT },
|
||||
[EXTCHK_HAPROXY_SERVER_ID] = { "HAPROXY_SERVER_ID", EXTCHK_SIZE_EVAL_INIT },
|
||||
[EXTCHK_HAPROXY_SERVER_ADDR] = { "HAPROXY_SERVER_ADDR", EXTCHK_SIZE_EVAL_INIT },
|
||||
[EXTCHK_HAPROXY_SERVER_PORT] = { "HAPROXY_SERVER_PORT", EXTCHK_SIZE_EVAL_INIT },
|
||||
[EXTCHK_HAPROXY_SERVER_MAXCONN] = { "HAPROXY_SERVER_MAXCONN", EXTCHK_SIZE_EVAL_INIT },
|
||||
[EXTCHK_HAPROXY_SERVER_CURCONN] = { "HAPROXY_SERVER_CURCONN", EXTCHK_SIZE_ULONG },
|
||||
};
|
||||
|
||||
static const struct analyze_status analyze_statuses[HANA_STATUS_SIZE] = { /* 0: ignore, 1: error, 2: OK */
|
||||
[HANA_STATUS_UNKNOWN] = { "Unknown", { 0, 0 }},
|
||||
|
||||
@ -1574,50 +1588,60 @@ static int init_pid_list(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define EXTCHECK_ARG_MAX 5
|
||||
#define EXTCHECK_ENV_ROOM 16
|
||||
|
||||
#define EXTCHECK_ADD_ENV(check, envname, value, idx) { if (external_check_add_env(check, envname, value, idx)) goto err; }
|
||||
/* helper macro to set an environment variable and jump to a specific label on failure. */
|
||||
#define EXTCHK_SETENV(check, envidx, value, fail) { if (extchk_setenv(check, envidx, value)) goto fail; }
|
||||
|
||||
/*
|
||||
* helper function to allocate enough space for new environment variables used
|
||||
* by external checks.
|
||||
* helper function to allocate enough memory to store an environment variable.
|
||||
* It will also check that the environment variable is updatable, and silently
|
||||
* fail if not.
|
||||
*/
|
||||
static int external_check_add_env(struct check *check, const char *envname, const char *value, int *idx)
|
||||
static int extchk_setenv(struct check *check, int idx, const char *value)
|
||||
{
|
||||
int len, ret;
|
||||
char *envname;
|
||||
int vmaxlen;
|
||||
|
||||
if (*idx % EXTCHECK_ENV_ROOM == 0) {
|
||||
/* Allocate enough space to store new environment variables */
|
||||
char **tmp = realloc(check->envp, (EXTCHECK_ENV_ROOM * ((*idx / EXTCHECK_ENV_ROOM) + 1) + 1) * sizeof(check->envp));
|
||||
if (tmp == NULL) {
|
||||
Alert("Failed to allocate memory for new environment variables. Aborting\n");
|
||||
return 1;
|
||||
} else {
|
||||
check->envp = tmp;
|
||||
}
|
||||
if (idx < 0 || idx >= EXTCHK_SIZE) {
|
||||
Alert("Illegal environment variable index %d. Aborting.\n", idx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
envname = extcheck_envs[idx].name;
|
||||
vmaxlen = extcheck_envs[idx].vmaxlen;
|
||||
|
||||
/* Check if the environment variable is already set, and silently reject
|
||||
* the update if this one is not updatable. */
|
||||
if ((vmaxlen == EXTCHK_SIZE_EVAL_INIT) && (check->envp[idx]))
|
||||
return 0;
|
||||
|
||||
/* Instead of sending NOT_USED, sending an empty value is preferable */
|
||||
if (strcmp(value, "NOT_USED") == 0) {
|
||||
value = "";
|
||||
}
|
||||
len = strlen(envname) + strlen(value) + 1;
|
||||
check->envp[*idx] = malloc(len + 1);
|
||||
check->envp[*idx + 1] = NULL;
|
||||
if (!check->envp[*idx]) {
|
||||
|
||||
len = strlen(envname) + 1;
|
||||
if (vmaxlen == EXTCHK_SIZE_EVAL_INIT)
|
||||
len += strlen(value);
|
||||
else
|
||||
len += vmaxlen;
|
||||
|
||||
if (!check->envp[idx])
|
||||
check->envp[idx] = malloc(len + 1);
|
||||
|
||||
if (!check->envp[idx]) {
|
||||
Alert("Failed to allocate memory for the environment variable '%s'. Aborting.\n", envname);
|
||||
return 1;
|
||||
}
|
||||
ret = snprintf(check->envp[*idx], len + 1, "%s=%s", envname, value);
|
||||
ret = snprintf(check->envp[idx], len + 1, "%s=%s", envname, value);
|
||||
if (ret < 0) {
|
||||
Alert("Failed to store the environment variable '%s'. Reason : %s. Aborting.\n", envname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
else if (ret != len) {
|
||||
else if (ret > len) {
|
||||
Alert("Environment variable '%s' was truncated. Aborting.\n", envname);
|
||||
return 1;
|
||||
}
|
||||
(*idx)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1627,7 +1651,6 @@ static int prepare_external_check(struct check *check)
|
||||
struct proxy *px = s->proxy;
|
||||
struct listener *listener = NULL, *l;
|
||||
int i;
|
||||
int envidx = 0;
|
||||
const char *path = px->check_path ? px->check_path : DEF_CHECK_PATH;
|
||||
char buf[256];
|
||||
|
||||
@ -1641,11 +1664,17 @@ static int prepare_external_check(struct check *check)
|
||||
}
|
||||
|
||||
check->curpid = NULL;
|
||||
check->envp = NULL;
|
||||
|
||||
check->argv = calloc(EXTCHECK_ARG_MAX + 1, sizeof(check->argv));
|
||||
if (!check->argv)
|
||||
check->envp = calloc((EXTCHK_SIZE + 1), sizeof(char *));
|
||||
if (!check->envp) {
|
||||
Alert("Failed to allocate memory for environment variables. Aborting\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
check->argv = calloc(6, sizeof(char *));
|
||||
if (!check->argv) {
|
||||
Alert("Starting [%s:%s] check: out of memory.\n", px->id, s->id);
|
||||
goto err;
|
||||
}
|
||||
|
||||
check->argv[0] = px->check_command;
|
||||
|
||||
@ -1668,6 +1697,7 @@ static int prepare_external_check(struct check *check)
|
||||
check->argv[2] = strdup("NOT_USED");
|
||||
}
|
||||
else {
|
||||
Alert("Starting [%s:%s] check: unsupported address family.\n", px->id, s->id);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1676,28 +1706,36 @@ static int prepare_external_check(struct check *check)
|
||||
port_to_str(&s->addr, buf, sizeof(buf));
|
||||
check->argv[4] = strdup(buf);
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
if (!check->argv[i])
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (!check->argv[i]) {
|
||||
Alert("Starting [%s:%s] check: out of memory.\n", px->id, s->id);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
EXTCHECK_ADD_ENV(check, "PATH", path, &envidx);
|
||||
EXTCHK_SETENV(check, EXTCHK_PATH, path, err);
|
||||
/* Add proxy environment variables */
|
||||
EXTCHECK_ADD_ENV(check, "HAPROXY_PROXY_NAME", px->id, &envidx);
|
||||
EXTCHECK_ADD_ENV(check, "HAPROXY_PROXY_ID", ultoa_r(px->uuid, buf, sizeof(buf)), &envidx);
|
||||
EXTCHECK_ADD_ENV(check, "HAPROXY_PROXY_ADDR", check->argv[1], &envidx);
|
||||
EXTCHECK_ADD_ENV(check, "HAPROXY_PROXY_PORT", check->argv[2], &envidx);
|
||||
EXTCHK_SETENV(check, EXTCHK_HAPROXY_PROXY_NAME, px->id, err);
|
||||
EXTCHK_SETENV(check, EXTCHK_HAPROXY_PROXY_ID, ultoa_r(px->uuid, buf, sizeof(buf)), err);
|
||||
EXTCHK_SETENV(check, EXTCHK_HAPROXY_PROXY_ADDR, check->argv[1], err);
|
||||
EXTCHK_SETENV(check, EXTCHK_HAPROXY_PROXY_PORT, check->argv[2], err);
|
||||
/* Add server environment variables */
|
||||
EXTCHECK_ADD_ENV(check, "HAPROXY_SERVER_NAME", s->id, &envidx);
|
||||
EXTCHECK_ADD_ENV(check, "HAPROXY_SERVER_ID", ultoa_r(s->puid, buf, sizeof(buf)), &envidx);
|
||||
EXTCHECK_ADD_ENV(check, "HAPROXY_SERVER_ADDR", check->argv[3], &envidx);
|
||||
EXTCHECK_ADD_ENV(check, "HAPROXY_SERVER_PORT", check->argv[4], &envidx);
|
||||
EXTCHECK_ADD_ENV(check, "HAPROXY_SERVER_MAXCONN", ultoa_r(s->maxconn, buf, sizeof(buf)), &envidx);
|
||||
EXTCHECK_ADD_ENV(check, "HAPROXY_SERVER_CURCONN", ultoa_r(s->cur_sess, buf, sizeof(buf)), &envidx);
|
||||
EXTCHK_SETENV(check, EXTCHK_HAPROXY_SERVER_NAME, s->id, err);
|
||||
EXTCHK_SETENV(check, EXTCHK_HAPROXY_SERVER_ID, ultoa_r(s->puid, buf, sizeof(buf)), err);
|
||||
EXTCHK_SETENV(check, EXTCHK_HAPROXY_SERVER_ADDR, check->argv[3], err);
|
||||
EXTCHK_SETENV(check, EXTCHK_HAPROXY_SERVER_PORT, check->argv[4], err);
|
||||
EXTCHK_SETENV(check, EXTCHK_HAPROXY_SERVER_MAXCONN, ultoa_r(s->maxconn, buf, sizeof(buf)), err);
|
||||
EXTCHK_SETENV(check, EXTCHK_HAPROXY_SERVER_CURCONN, ultoa_r(s->cur_sess, buf, sizeof(buf)), err);
|
||||
|
||||
/* Ensure that we don't leave any hole in check->envp */
|
||||
for (i = 0; i < EXTCHK_SIZE; i++)
|
||||
if (!check->envp[i])
|
||||
EXTCHK_SETENV(check, i, "", err);
|
||||
|
||||
return 1;
|
||||
err:
|
||||
if (check->envp) {
|
||||
for (i = 0; i < envidx; i++)
|
||||
for (i = 0; i < EXTCHK_SIZE; i++)
|
||||
free(check->envp[i]);
|
||||
free(check->envp);
|
||||
check->envp = NULL;
|
||||
@ -1728,6 +1766,7 @@ err:
|
||||
*/
|
||||
static int connect_proc_chk(struct task *t)
|
||||
{
|
||||
char buf[256];
|
||||
struct check *check = t->context;
|
||||
struct server *s = check->server;
|
||||
struct proxy *px = s->proxy;
|
||||
@ -1749,6 +1788,7 @@ static int connect_proc_chk(struct task *t)
|
||||
/* Child */
|
||||
extern char **environ;
|
||||
environ = check->envp;
|
||||
extchk_setenv(check, EXTCHK_HAPROXY_SERVER_CURCONN, ultoa_r(s->cur_sess, buf, sizeof(buf)));
|
||||
execvp(px->check_command, check->argv);
|
||||
Alert("Failed to exec process for external health check: %s. Aborting.\n",
|
||||
strerror(errno));
|
||||
|
Loading…
Reference in New Issue
Block a user