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 */
+};