]> granicus.if.org Git - apache/commitdiff
1st cut of 'simple' tcp check... We reuse various proxy
authorJim Jagielski <jim@apache.org>
Fri, 15 Jan 2016 21:37:23 +0000 (21:37 +0000)
committerJim Jagielski <jim@apache.org>
Fri, 15 Jan 2016 21:37:23 +0000 (21:37 +0000)
function and so this *could* be more streamlined, but
use this to show how the other would work, since we need
brigades, SSL/TLS support, etc.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1724879 13f79535-47bb-0310-9956-ffa450edef68

modules/proxy/mod_proxy.c
modules/proxy/mod_proxy.h
modules/proxy/mod_proxy_hcheck.c
modules/proxy/proxy_util.c

index 901581bf531bb3d293d37db728feee47e835951e..459d8cd7343624dca7bb33a49cd9ef906abd9b8d 100644 (file)
@@ -44,14 +44,14 @@ APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup,
 static APR_OPTIONAL_FN_TYPE(set_worker_hc_param) *set_worker_hc_param_f = NULL;
 
 hcmethods_t hcmethods[] = {
-        {NONE, "NONE"},
-        {TCP, "TCP"},
-        {OPTIONS, "OPTIONS"},
-        {HEAD, "HEAD"},
-        {GET, "GET"},
-        {CPING, "CPING"},
-        {PROVIDER, "PROVIDER"},
-        {EOT, NULL}
+        {NONE, "NONE", 1},
+        {TCP, "TCP", 1},
+        {OPTIONS, "OPTIONS", 0},
+        {HEAD, "HEAD", 0},
+        {GET, "GET", 0},
+        {CPING, "CPING", 0},
+        {PROVIDER, "PROVIDER", 0},
+        {EOT, NULL, 1}
 };
 
 static const char * const proxy_id = "proxy";
index b9aadf23bd204820b01fe47d90bc01c0c7c8b194..cc5dab34f1f6d81cf271c4835c004684f1f60a53 100644 (file)
@@ -82,6 +82,7 @@ typedef enum {
 typedef struct {
     hcmethod_t method;
     char *name;
+    int implemented;
 } hcmethods_t;
 
 extern hcmethods_t hcmethods[];
index 96096bfbca4ca29a8f13ef5a7231966198701cd9..d035ed127f639f5f5139d24c5ad08cfbc91a7627 100644 (file)
@@ -45,7 +45,9 @@ typedef struct {
     apr_pool_t *p;
     apr_array_header_t *templates;
     apr_array_header_t *conditions;
+    /* TODO: Make below array/hashtable tagged to each worker */
     ap_watchdog_t *watchdog;
+    proxy_worker *hc;
     server_rec *s;
 } sctx_t;
 
@@ -55,11 +57,43 @@ static void *hc_create_config(apr_pool_t *p, server_rec *s)
     apr_pool_create(&ctx->p, p);
     ctx->templates = apr_array_make(ctx->p, 10, sizeof(hc_template_t));
     ctx->conditions = apr_array_make(ctx->p, 10, sizeof(hc_condition_t));
+    ctx->hc = NULL;
     ctx->s = s;
 
     return ctx;
 }
 
+static void hc_child_init(apr_pool_t *p, server_rec *s)
+{
+    proxy_worker *hc = NULL;
+
+    /* TODO */
+    while (s) {
+        sctx_t *ctx = (sctx_t *) ap_get_module_config(s->module_config,
+                                                      &proxy_hcheck_module);
+        if (!hc) {
+            ap_proxy_define_worker(ctx->p, &hc, NULL, NULL, "http://www.apache.org", 0);
+            PROXY_STRNCPY(hc->s->name,     "proxy:hcheck");
+            PROXY_STRNCPY(hc->s->hostname, "*");
+            PROXY_STRNCPY(hc->s->scheme,   "*");
+            hc->hash.def = hc->s->hash.def =
+                ap_proxy_hashfunc(hc->s->name, PROXY_HASHFUNC_DEFAULT);
+            hc->hash.fnv = hc->s->hash.fnv =
+                ap_proxy_hashfunc(hc->s->name, PROXY_HASHFUNC_FNV);
+            /* Do not disable worker in case of errors */
+            hc->s->status |= PROXY_WORKER_IGNORE_ERRORS;
+            /* Mark as the "generic" worker */
+            hc->s->status |= PROXY_WORKER_GENERIC;
+            ctx->hc = hc;
+            ap_proxy_initialize_worker(ctx->hc, s, ctx->p);
+            /* Enable address cache for generic reverse worker */
+            hc->s->is_address_reusable = 1;
+        }
+        ctx->hc = hc;
+        s = s->next;
+    }
+}
+
 /*
  * This serves double duty by not only validating (and creating)
  * the health-check template, but also ties into set_worker_param()
@@ -107,6 +141,10 @@ static const char *set_worker_hc_param(apr_pool_t *p,
         hcmethods_t *method = hcmethods;
         for (; method->name; method++) {
             if (!ap_casecmpstr(val, method->name)) {
+                if (!method->implemented) {
+                    return apr_psprintf(p, "Health check method %s not (yet) implemented",
+                                        val);
+                }
                 if (worker) {
                     worker->s->method = method->method;
                 } else {
@@ -119,8 +157,9 @@ static const char *set_worker_hc_param(apr_pool_t *p,
     }
     else if (!strcasecmp(key, "hcinterval")) {
         ival = atoi(val);
-        if (ival < 5)
-            return "Interval must be a positive value greater than 5 seconds";
+        if (ival < HCHECK_WATHCHDOG_INTERVAL)
+            return apr_psprintf(p, "Interval must be a positive value greater than %d seconds",
+                                HCHECK_WATHCHDOG_INTERVAL);
         if (worker) {
             worker->s->interval = apr_time_from_sec(ival);
         } else {
@@ -252,16 +291,93 @@ static const char *set_hc_template(cmd_parms *cmd, void *dummy, const char *arg)
 
     return NULL;
 }
+static void backend_cleanup(const char *proxy_function, proxy_conn_rec *backend,
+                            server_rec *s)
+{
+    if (backend) {
+        backend->close = 1;
+        ap_proxy_release_connection(proxy_function, backend, s);
+    }
+}
+
+static apr_status_t hc_check_tcp(sctx_t *ctx, apr_pool_t *p, proxy_worker *worker)
+{
+    int status;
+    apr_status_t err = APR_SUCCESS;
+    proxy_conn_rec *backend = NULL;
+    proxy_conn_pool *cp = ctx->hc->cp;
+
+    if (!worker->cp) {
+        apr_status_t rv;
+        rv = ap_proxy_initialize_worker(worker, ctx->s, ctx->p);
+        if (rv != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ctx->s, APLOGNO() "Cannot init worker");
+            return rv;
+        }
+        err = apr_sockaddr_info_get(&(cp->addr), worker->s->hostname, APR_UNSPEC,
+                                    worker->s->port, 0, ctx->p);
+
+        if (err != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO()
+                         "DNS lookup failure for: %s:%d",
+                         worker->s->hostname, (int)worker->s->port);
+            return err;
+        }
+    }
+    backend = (proxy_conn_rec *) apr_palloc(p, sizeof(proxy_conn_rec));
+    status = ap_proxy_acquire_connection("HCTCP", &backend, ctx->hc, ctx->s);
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO()
+                     "ap_proxy_acquire_connection (%d).", status);
+    if (status == OK) {
+        backend->addr = cp->addr;
+        status = ap_proxy_connect_backend("HCTCP", backend, ctx->hc, ctx->s);
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO()
+                         "ap_proxy_connect_backend (%d).", status);
+        if (status == OK) {
+            status = (ap_proxy_is_socket_connected(backend->sock) ? OK : !OK);
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO()
+                                 "ap_proxy_is_socket_connected (%d).", status);
+        }
+    }
+    ctx->hc->cp = cp;
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ctx->s, APLOGNO()
+                     "Health check TCP Status (%d).", status);
+    if (status != OK) {
+        backend_cleanup("HCTCP", backend, ctx->s);
+        return APR_EGENERAL;
+    }
+    return APR_SUCCESS;
+}
 
 static void hc_check(sctx_t *ctx, apr_pool_t *p, apr_time_t now,
                      proxy_worker *worker)
 {
     server_rec *s = ctx->s;
+    apr_status_t rv;
     /* TODO: REMOVE ap_log_error call */
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO()
                  "Health check (%s).", worker->s->name);
 
-    return;
+    switch (worker->s->method) {
+        case TCP:
+            rv = hc_check_tcp(ctx, p, worker);
+            break;
+
+        default:
+            rv = APR_ENOTIMPL;
+            break;
+    }
+    if (rv == APR_ENOTIMPL) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO()
+                         "Somehow tried to use unimplemented hcheck method: %d", (int)worker->s->method);
+        return;
+    }
+    /* TODO Honor fails and passes */
+    ap_proxy_set_wstatus('#', (rv == APR_SUCCESS ? 0 : 1), worker);
+    if (rv != APR_SUCCESS) {
+        worker->s->error_time = now;
+    }
+    worker->s->updated = now;
 }
 
 static apr_status_t hc_watchdog_callback(int state, void *data,
@@ -296,21 +412,23 @@ static apr_status_t hc_watchdog_callback(int state, void *data,
                     int n;
                     proxy_worker **workers;
                     proxy_worker *worker;
+                    ap_proxy_sync_balancer(balancer, s, conf);
                     workers = (proxy_worker **)balancer->workers->elts;
                     for (n = 0; n < balancer->workers->nelts; n++) {
                         worker = *workers;
                         /* TODO: REMOVE ap_log_error call */
                         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO()
-                                     "Checking worker: %s:%d (%lu %lu %lu)",
+                                     "Checking %s worker: %s / %d (%lu %lu %lu)", balancer->s->name,
                                      worker->s->name, worker->s->method, (unsigned long)now,
                                      (unsigned long)worker->s->updated, (unsigned long)worker->s->interval);
-                        if (worker->s->method && (now > worker->s->updated + worker->s->interval)) {
+                        if ((worker->s->method != NONE) && (now > worker->s->updated + worker->s->interval)) {
                             hc_check(ctx, p, now, worker);
                         }
                         workers++;
                     }
                 }
                 apr_pool_destroy(p);
+                /* s = s->next; */
             }
             break;
 
@@ -379,6 +497,7 @@ static void hc_register_hooks(apr_pool_t *p)
     static const char *const runAfter[] = { "mod_watchdog.c", "mod_proxy_balancer.c", NULL};
     APR_REGISTER_OPTIONAL_FN(set_worker_hc_param);
     ap_hook_post_config(hc_post_config, NULL, runAfter, APR_HOOK_LAST);
+    ap_hook_child_init(hc_child_init, NULL, NULL, APR_HOOK_MIDDLE);
 }
 
 /* the main config structure */
index 86182e807c09166233e45014422bde2fc9b1f058..6aaa17fdb22880eea6c130012d695810c84649a1 100644 (file)
@@ -1742,6 +1742,7 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
 
     memset(wshared, 0, sizeof(proxy_worker_shared));
 
+    wshared->port = (uri.port ? uri.port : ap_proxy_port_of_scheme(uri.scheme));
     if (uri.port && uri.port == ap_proxy_port_of_scheme(uri.scheme)) {
         uri.port = 0;
     }
@@ -1756,7 +1757,6 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p,
     if (PROXY_STRNCPY(wshared->hostname, uri.hostname) != APR_SUCCESS) {
         return apr_psprintf(p, "worker hostname (%s) too long", uri.hostname);
     }
-    wshared->port = uri.port;
     wshared->flush_packets = flush_off;
     wshared->flush_wait = PROXY_FLUSH_WAIT;
     wshared->is_address_reusable = 1;
@@ -2914,6 +2914,8 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
          * no further connections to the worker could be made
          */
         if (!connected) {
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO() "Usable not connected");
+
             if (!(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) {
                 worker->s->error_time = apr_time_now();
                 worker->s->status |= PROXY_WORKER_IN_ERROR;
@@ -2945,6 +2947,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
         if (connected) {
             socket_cleanup(conn);
         }
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO() "Not usable");
         return DECLINED;
     }
 }