You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ji...@apache.org on 2015/12/29 17:12:09 UTC
svn commit: r1722177 - in /httpd/httpd/trunk/modules/proxy: config.m4
mod_proxy.c mod_proxy.h mod_proxy_hcheck.c
Author: jim
Date: Tue Dec 29 16:12:04 2015
New Revision: 1722177
URL: http://svn.apache.org/viewvc?rev=1722177&view=rev
Log:
Commit framework impl of health-check module plus
required changes. The actual health checking is
currently in progress, but wanted to add in at
this stage.
Added:
httpd/httpd/trunk/modules/proxy/mod_proxy_hcheck.c
Modified:
httpd/httpd/trunk/modules/proxy/config.m4
httpd/httpd/trunk/modules/proxy/mod_proxy.c
httpd/httpd/trunk/modules/proxy/mod_proxy.h
Modified: httpd/httpd/trunk/modules/proxy/config.m4
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/config.m4?rev=1722177&r1=1722176&r2=1722177&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/config.m4 (original)
+++ httpd/httpd/trunk/modules/proxy/config.m4 Tue Dec 29 16:12:04 2015
@@ -10,6 +10,10 @@ else
proxy_mods_enable=most
fi
+if test "$proxy_mods_enable" = "no"; then
+ enable_proxy_hcheck=no
+fi
+
proxy_objs="mod_proxy.lo proxy_util.lo"
APACHE_MODULE(proxy, Apache proxy module, $proxy_objs, , $proxy_mods_enable)
@@ -68,6 +72,7 @@ APACHE_MODULE(serf, [Reverse proxy modul
])
APACHE_MODULE(proxy_express, mass reverse-proxy module. Requires --enable-proxy., , , $proxy_mods_enable,, proxy)
+APACHE_MODULE(proxy_hcheck, reverse-proxy health-check module. Requires --enable-proxy and --enable-watchdog., , , $enable_proxy_hcheck,, watchdog)
APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current])
Modified: httpd/httpd/trunk/modules/proxy/mod_proxy.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy.c?rev=1722177&r1=1722176&r2=1722177&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy.c (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy.c Tue Dec 29 16:12:04 2015
@@ -36,6 +36,13 @@ APR_DECLARE_OPTIONAL_FN(char *, ssl_var_
#define MAX(x,y) ((x) >= (y) ? (x) : (y))
#endif
+/*
+ * We do health-checks only if that (sub)module is loaded in. This
+ * allows for us to continue as is w/o requiring mod_watchdog for
+ * those implementations which aren't using health checks
+ */
+static APR_OPTIONAL_FN_TYPE(set_worker_hc_param) *set_worker_hc_param_f = NULL;
+
static const char * const proxy_id = "proxy";
apr_global_mutex_t *proxy_mutex = NULL;
@@ -274,7 +281,11 @@ static const char *set_worker_param(apr_
PROXY_STRNCPY(worker->s->flusher, val);
}
else {
- return "unknown Worker parameter";
+ if (set_worker_hc_param_f) {
+ return set_worker_hc_param_f(p, worker, key, val, NULL);
+ } else {
+ return "unknown Worker parameter";
+ }
}
return NULL;
}
@@ -2667,6 +2678,7 @@ static int proxy_post_config(apr_pool_t
proxy_ssl_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable);
proxy_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
proxy_ssl_val = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
+ set_worker_hc_param_f = APR_RETRIEVE_OPTIONAL_FN(set_worker_hc_param);
ap_proxy_strmatch_path = apr_strmatch_precompile(pconf, "path=", 0);
ap_proxy_strmatch_domain = apr_strmatch_precompile(pconf, "domain=", 0);
@@ -2889,7 +2901,8 @@ static void register_hooks(apr_pool_t *p
* make sure that we are called after the mpm
* initializes.
*/
- static const char *const aszPred[] = { "mpm_winnt.c", "mod_proxy_balancer.c", NULL};
+ static const char *const aszPred[] = { "mpm_winnt.c", "mod_proxy_balancer.c",
+ "mod_proxy_hcheck.c", NULL};
/* handler */
ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST);
Modified: httpd/httpd/trunk/modules/proxy/mod_proxy.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy.h?rev=1722177&r1=1722176&r2=1722177&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy.h (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy.h Tue Dec 29 16:12:04 2015
@@ -359,6 +359,7 @@ typedef struct {
char redirect[PROXY_WORKER_MAX_ROUTE_SIZE]; /* temporary balancing redirection route */
char flusher[PROXY_WORKER_MAX_SCHEME_SIZE]; /* flush provider used by mod_proxy_fdpass */
char uds_path[PROXY_WORKER_MAX_NAME_SIZE]; /* path to worker's unix domain socket if applicable */
+ char hurl[PROXY_WORKER_MAX_ROUTE_SIZE]; /* health check url */
int lbset; /* load balancer cluster set */
int retries; /* number of retries on this worker */
int lbstatus; /* Current lbstatus */
@@ -368,6 +369,9 @@ typedef struct {
int hmax; /* Hard maximum on the total number of connections */
int flush_wait; /* poll wait time in microseconds if flush_auto */
int index; /* shm array index */
+ int method; /* method to use for health check */
+ int passes; /* number of successes for check to pass */
+ int fails; /* number of failures for check to fail */
proxy_hashes hash; /* hash of worker name */
unsigned int status; /* worker status bitfield */
enum {
@@ -384,6 +388,7 @@ typedef struct {
apr_interval_time_t acquire; /* acquire timeout when the maximum number of connections is exceeded */
apr_interval_time_t ping_timeout;
apr_interval_time_t conn_timeout;
+ apr_interval_time_t interval;
apr_size_t recv_buffer_size;
apr_size_t io_buffer_size;
apr_size_t elected; /* Number of times the worker was elected */
@@ -519,6 +524,10 @@ struct proxy_balancer_method {
#define PROXY_DECLARE_DATA __declspec(dllimport)
#endif
+APR_DECLARE_OPTIONAL_FN(const char *, set_worker_hc_param,
+ (apr_pool_t *, proxy_worker *,
+ const char *, const char *, void *));
+
APR_DECLARE_EXTERNAL_HOOK(proxy, PROXY, int, scheme_handler, (request_rec *r,
proxy_worker *worker, proxy_server_conf *conf, char *url,
const char *proxyhost, apr_port_t proxyport))
Added: httpd/httpd/trunk/modules/proxy/mod_proxy_hcheck.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy_hcheck.c?rev=1722177&view=auto
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy_hcheck.c (added)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy_hcheck.c Tue Dec 29 16:12:04 2015
@@ -0,0 +1,279 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mod_proxy.h"
+#include "mod_watchdog.h"
+
+module AP_MODULE_DECLARE_DATA proxy_hcheck_module;
+
+#define HCHECK_WATHCHDOG_NAME ("_proxy_hcheck_")
+/* default to health check every 30 seconds */
+#define HCHECK_WATHCHDOG_SEC (30)
+/* The watchdog runs every 5 seconds, which is also the minimal check */
+#define HCHECK_WATHCHDOG_INTERVAL (5)
+
+static char *methods[] = {
+ "NULL", "OPTIONS", "HEAD", "GET", "POST", "CPING"
+};
+
+typedef struct hcheck_template_t {
+ char *name;
+ int method;
+ int passes;
+ int fails;
+ apr_interval_time_t interval;
+ char *hurl;
+} hcheck_template_t;
+
+static apr_pool_t *ptemplate = NULL;
+static apr_array_header_t *templates = NULL;
+static ap_watchdog_t *watchdog;
+
+/*
+ * This is not as clean as it should be, because we are using
+ * the same to both update the actual worker as well as verifying
+ * and populating the health check 'template' as well.
+ */
+static const char *set_worker_hc_param(apr_pool_t *p,
+ proxy_worker *worker,
+ const char *key,
+ const char *val,
+ void *tmp)
+{
+ int ival;
+ hcheck_template_t *ctx;
+
+ if (!worker && !tmp) {
+ return "Bad call to set_worker_hc_param()";
+ }
+ ctx = (hcheck_template_t *)tmp;
+ if (!strcasecmp(key, "hcheck")) {
+ hcheck_template_t *template;
+ template = (hcheck_template_t *)templates->elts;
+ for (ival = 0; ival < templates->nelts; ival++, template++) {
+ if (!ap_casecmpstr(template->name, val)) {
+ worker->s->method = template->method;
+ worker->s->interval = template->interval;
+ worker->s->passes = template->passes;
+ worker->s->fails = template->fails;
+ PROXY_STRNCPY(worker->s->hurl, template->hurl);
+ return NULL;
+ }
+ }
+ return apr_psprintf(p, "Unknown HCheckTemplate name: %s", val);
+ }
+ else if (!strcasecmp(key, "method")) {
+ for (ival = 1; ival < sizeof(methods); ival++) {
+ if (!ap_casecmpstr(val, methods[ival])) {
+ if (worker) {
+ worker->s->method = ival;
+ } else {
+ ctx->method = ival;
+ }
+ return NULL;
+ }
+ }
+ return "Unknown method";
+ }
+ else if (!strcasecmp(key, "interval")) {
+ ival = atoi(val);
+ if (ival < 5)
+ return "Interval must be a positive value greater than 5 seconds";
+ if (worker) {
+ worker->s->interval = apr_time_from_sec(ival);
+ } else {
+ ctx->interval = apr_time_from_sec(ival);
+ }
+ }
+ else if (!strcasecmp(key, "passes")) {
+ ival = atoi(val);
+ if (ival < 0)
+ return "Passes must be a positive value";
+ if (worker) {
+ worker->s->passes = ival;
+ } else {
+ ctx->passes = ival;
+ }
+ }
+ else if (!strcasecmp(key, "fails")) {
+ ival = atoi(val);
+ if (ival < 0)
+ return "Fails must be a positive value";
+ if (worker) {
+ worker->s->fails = ival;
+ } else {
+ ctx->fails = ival;
+ }
+ }
+ else if (!strcasecmp(key, "hurl")) {
+ if (strlen(val) >= sizeof(worker->s->hurl))
+ return apr_psprintf(p, "Health check hurl length must be < %d characters",
+ (int)sizeof(worker->s->hurl));
+ if (worker) {
+ PROXY_STRNCPY(worker->s->hurl, val);
+ } else {
+ ctx->hurl = apr_pstrdup(p, val);
+ }
+ }
+ else {
+ return "unknown Worker hcheck parameter";
+ }
+ return NULL;
+}
+
+static const char *set_hcheck(cmd_parms *cmd, void *dummy, const char *arg)
+{
+ char *name = NULL;
+ char *word, *val;
+ hcheck_template_t template;
+ hcheck_template_t *tpush;
+ const char *err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS);
+ if (err)
+ return err;
+
+ template.name = ap_getword_conf(cmd->temp_pool, &arg);
+ template.method = template.passes = template.fails = 1;
+ template.interval = apr_time_from_sec(HCHECK_WATHCHDOG_SEC);
+ template.hurl = NULL;
+ while (*arg) {
+ word = ap_getword_conf(cmd->pool, &arg);
+ val = strchr(word, '=');
+ if (!val) {
+ return "Invalid HCheckTemplate parameter. Parameter must be "
+ "in the form 'key=value'";
+ }
+ else
+ *val++ = '\0';
+ err = set_worker_hc_param(cmd->pool, NULL, word, val, &template);
+
+ if (err)
+ return apr_pstrcat(cmd->temp_pool, "HCheckTemplate: ", err, " ", word, "=", val, "; ", name, NULL);
+ /* No error means we have a valid template */
+ tpush = (hcheck_template_t *)apr_array_push(templates);
+ memcpy(tpush, &template, sizeof(hcheck_template_t));
+ }
+
+ return NULL;
+}
+
+static apr_status_t hc_watchdog_callback(int state, void *data,
+ apr_pool_t *pool)
+{
+ apr_status_t rv = APR_SUCCESS;
+ apr_time_t cur, now;
+
+
+ switch (state) {
+ case AP_WATCHDOG_STATE_STARTING:
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO()
+ "%s watchdog started.",
+ HCHECK_WATHCHDOG_NAME);
+ break;
+ case AP_WATCHDOG_STATE_RUNNING:
+ cur = now = apr_time_sec(apr_time_now());
+ /*
+ while ((now - cur) < apr_time_sec(ctx->interval)) {
+ break;
+ }
+ */
+ break;
+ case AP_WATCHDOG_STATE_STOPPING:
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO()
+ "stopping %s watchdog.",
+ HCHECK_WATHCHDOG_NAME);
+
+ break;
+ }
+ return rv;
+}
+
+static int hc_pre_config(apr_pool_t *p, apr_pool_t *plog,
+ apr_pool_t *ptemp)
+{
+ if (!ptemplate) {
+ apr_pool_create(&ptemplate, p);
+ }
+ if (!templates) {
+ templates = apr_array_make(ptemplate, 10, sizeof(hcheck_template_t));
+ }
+ return OK;
+}
+
+static int hc_post_config(apr_pool_t *p, apr_pool_t *plog,
+ apr_pool_t *ptemp, server_rec *s)
+{
+ apr_status_t rv;
+ APR_OPTIONAL_FN_TYPE(ap_watchdog_get_instance) *hc_watchdog_get_instance;
+ APR_OPTIONAL_FN_TYPE(ap_watchdog_register_callback) *hc_watchdog_register_callback;
+
+ hc_watchdog_get_instance = APR_RETRIEVE_OPTIONAL_FN(ap_watchdog_get_instance);
+ hc_watchdog_register_callback = APR_RETRIEVE_OPTIONAL_FN(ap_watchdog_register_callback);
+ if (!hc_watchdog_get_instance || !hc_watchdog_register_callback) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO()
+ "mod_watchdog is required");
+ return !OK;
+ }
+
+ rv = hc_watchdog_get_instance(&watchdog,
+ HCHECK_WATHCHDOG_NAME,
+ 0, 1, p);
+ if (rv) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO()
+ "Failed to create watchdog instance (%s)",
+ HCHECK_WATHCHDOG_NAME);
+ return !OK;
+ }
+ rv = hc_watchdog_register_callback(watchdog,
+ apr_time_from_sec(HCHECK_WATHCHDOG_INTERVAL),
+ NULL,
+ hc_watchdog_callback);
+ if (rv) {
+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO()
+ "Failed to register watchdog callback (%s)",
+ HCHECK_WATHCHDOG_NAME);
+ return !OK;
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO()
+ "watchdog callback registered (%s)", HCHECK_WATHCHDOG_NAME);
+ return OK;
+}
+
+static const command_rec command_table[] = {
+ AP_INIT_RAW_ARGS("HCheckTemplate", set_hcheck, NULL, OR_FILEINFO,
+ "Health check template"),
+ { NULL }
+};
+
+static void hc_register_hooks(apr_pool_t *p)
+{
+ static const char *const runAfter[] = { "mod_watchdog.c", NULL};
+ APR_REGISTER_OPTIONAL_FN(set_worker_hc_param);
+ ap_hook_pre_config(hc_pre_config, NULL, NULL, APR_HOOK_LAST);
+ ap_hook_post_config(hc_post_config, NULL, runAfter, APR_HOOK_LAST);
+}
+
+/* the main config structure */
+
+AP_DECLARE_MODULE(proxy_hcheck) =
+{
+ STANDARD20_MODULE_STUFF,
+ NULL, /* create per-dir config structures */
+ NULL, /* merge per-dir config structures */
+ NULL, /* create per-server config structures */
+ NULL, /* merge per-server config structures */
+ command_table, /* table of config file commands */
+ hc_register_hooks /* register hooks */
+};