[prev in list] [next in list] [prev in thread] [next in thread]
List: keepalived-devel
Subject: [Keepalived-devel] [PATCH] Make http(s) healthchecker check for regular expression
From: Anders Henke <anders.henke () 1und1 ! de>
Date: 2012-02-09 15:04:25
Message-ID: 20120209150425.GH9364 () 1und1 ! de
[Download RAW message or body]
Hi,
we've been investigating a few minor issues with LVS and keepalived; a
freelance developer at my team also prepared a couple of smaller patches
to resolve those issues we'd like to contribute to the general
LVS/keepalived public.
The patches are based upon commit
91c61a85dccffd00dd6e887d24302443e412433d
from http://master.formilux.org/git/people/alex/keepalived.git, but
of course to apply to newer releases as well.
=== Regex content check for http(s) healthcheckers
Usually, checking for the digest of a static (testing-only) website is
fine to check wether some service is available; in some setups, we do
need some way to also check more "dynamic" content and not only the
testing code by checking the content of a http(s) website.
Over the last few years, we did so using a check_misc command, but chose
to implement an option to the keepalived-internal healtchecker as well.
The attached patch uses the regex functions of ICU/libicuuc to check
for a regular expression within the first 4000 byte of returned content.
Best,
Anders
--
1&1 Internet AG Expert Systems Architect (IT Operations)
Brauerstrasse 48 v://49.721.91374.0
D-76135 Karlsruhe f://49.721.91374.225
Amtsgericht Montabaur HRB 6484
Vorstände: Henning Ahlert, Ralph Dommermuth, Matthias Ehrlich, Robert Hoffmann,
Markus Huhn, Hans-Henning Kettler, Dr. Oliver Mauss, Jan Oetjen
Aufsichtsratsvorsitzender: Michael Scheeren
["0001-Implement-http-s-check-for-regular-expression.patch" (text/x-diff)]
> From 2e2a1a4aab20ea5f164ac9116767c5006bc61ec8 Mon Sep 17 00:00:00 2001
From: Alexander Holler <alexander.holler@1und1.de>
Date: Wed, 23 Nov 2011 09:28:38 +0100
Subject: [PATCH 1/3] Implement http(s) check for regular expression.
---
configure.in | 4 ++
keepalived/check/check_http.c | 87 +++++++++++++++++++++++++++++++++++++++
keepalived/include/check_http.h | 5 ++
3 files changed, 96 insertions(+), 0 deletions(-)
diff --git a/configure.in b/configure.in
index fd41a9d..9c3624c 100644
--- a/configure.in
+++ b/configure.in
@@ -44,12 +44,16 @@ dnl [do we really need this ?] AC_CHECK_HEADERS(linux/netlink.h \
linux/rtnetlink. AC_CHECK_HEADERS(openssl/ssl.h openssl/md5.h \
openssl/err.h,,AC_MSG_ERROR([
!!! OpenSSL is not properly installed on your system. !!!
!!! Can not include OpenSSL headers files. !!!]))
+AC_CHECK_HEADERS(unicode/uregex.h unicode/ustring.h,,AC_MSG_ERROR([
+ !!! ICU is not properly installed on your system. !!!
+ !!! Can not include ICU header files. !!!]))
AC_CHECK_DECL([ETHERTYPE_IPV6],[],[CFLAGS="$CFLAGS -DETHERTYPE_IPV6=0x86dd"],
[[@%:@include <net/ethernet.h>]])
dnl ----[ Checks for libraries ]----
AC_CHECK_LIB(crypto, MD5_Init,,AC_MSG_ERROR([OpenSSL libraries are required]))
AC_CHECK_LIB(ssl, SSL_CTX_new,,AC_MSG_ERROR([OpenSSL libraries are required]))
+AC_CHECK_LIB(icui18n, uregex_openC_44,,AC_MSG_ERROR([ICU libraries are required]))
AC_CHECK_LIB(popt, poptGetContext,,AC_MSG_ERROR([Popt libraries is required]))
AC_CHECK_LIB(nl, nl_handle_alloc,
[
diff --git a/keepalived/check/check_http.c b/keepalived/check/check_http.c
index 0d1a12c..063919b 100644
--- a/keepalived/check/check_http.c
+++ b/keepalived/check/check_http.c
@@ -22,6 +22,8 @@
*/
#include <openssl/err.h>
+#include <unicode/uregex.h>
+#include <unicode/ustring.h>
#include "check_http.h"
#include "check_ssl.h"
#include "check_api.h"
@@ -40,6 +42,9 @@ free_url(void *data)
url_t *url = data;
FREE(url->path);
FREE(url->digest);
+ FREE(url->regex_pattern);
+ if(url->regexp)
+ uregex_close(url->regexp);
FREE(url);
}
@@ -54,6 +59,9 @@ dump_url(void *data)
if (url->status_code)
log_message(LOG_INFO, " HTTP Status Code = %d",
url->status_code);
+ if (url->regex_pattern)
+ log_message(LOG_INFO, " regex = %s",
+ url->regex_pattern);
}
void
@@ -180,6 +188,21 @@ digest_handler(vector strvec)
}
void
+regex_handler(vector strvec)
+{
+ http_checker_t *http_get_chk = CHECKER_GET();
+ url_t *url = LIST_TAIL_DATA(http_get_chk->url);
+
+ url->regex_pattern = CHECKER_VALUE_STRING(strvec);
+ if (!url->regexp) {
+ UErrorCode status = U_ZERO_ERROR;
+ url->regexp = uregex_openC(url->regex_pattern, 0, NULL, &status);
+ if (U_FAILURE(status))
+ log_message(LOG_INFO, "Failed setting up regular expression pattern (%s).", \
u_errorName(status)); + }
+}
+
+void
status_code_handler(vector strvec)
{
http_checker_t *http_get_chk = CHECKER_GET();
@@ -203,6 +226,7 @@ install_http_check_keyword(void)
install_keyword("path", &path_handler);
install_keyword("digest", &digest_handler);
install_keyword("status_code", &status_code_handler);
+ install_keyword("regex", ®ex_handler);
install_sublevel_end();
install_sublevel_end();
}
@@ -223,6 +247,7 @@ install_ssl_check_keyword(void)
install_keyword("path", &path_handler);
install_keyword("digest", &digest_handler);
install_keyword("status_code", &status_code_handler);
+ install_keyword("regex", ®ex_handler);
install_sublevel_end();
install_sublevel_end();
}
@@ -323,6 +348,8 @@ epilog(thread_t * thread, int method, int t, int c)
SSL_free(req->ssl);
if (req->buffer)
FREE(req->buffer);
+ if (req->buffer_regex)
+ FREE(req->buffer_regex);
FREE(req);
http_arg->req = NULL;
close(thread->u.fd);
@@ -478,6 +505,56 @@ http_handle_response(thread_t * thread, unsigned char digest[16]
}
}
+ /* Continue with REGEXP */
+ if (fetched_url->regexp) {
+ /* Search the regular expression */
+ if( req->buffer_regex_len) {
+ UErrorCode status = U_ZERO_ERROR;
+ UChar *text = MALLOC(req->buffer_regex_len*2+1);
+ req->buffer_regex[req->buffer_regex_len] = 0;
+ u_uastrncpy(text, req->buffer_regex, req->buffer_regex_len);
+ uregex_setText(fetched_url->regexp, text, req->buffer_regex_len, &status);
+ uregex_setTimeLimit(fetched_url->regexp, 500, &status);
+ r = (uregex_find(fetched_url->regexp, 0, &status) == FALSE);
+ FREE(text);
+ if (U_FAILURE(status))
+ log_message(LOG_INFO, "Failed setting up regular expression (%s).", \
u_errorName(status)); + }
+ else
+ r = 1; /* No HTML code received to check teh pattern against */
+ if (r) {
+ /* check if server is currently alive */
+ if (svr_checker_up(checker->id, checker->rs)) {
+ log_message(LOG_INFO,
+ "Regex error to [%s]:%d url[%s].",
+ inet_sockaddrtos(&http_get_check->dst),
+ ntohs(inet_sockaddrport(&http_get_check->dst)),
+ fetched_url->path);
+ smtp_alert(checker->rs, NULL, NULL,
+ "DOWN",
+ "=> CHECK failed on service"
+ " : HTTP regex not found <=");
+ update_svr_checker_state(DOWN, checker->id
+ , checker->vs
+ , checker->rs);
+ } else {
+ /*
+ * We set retry iterator to max value to not retry
+ * when service is already know as die.
+ */
+ http_arg->retry_it = http_get_check->nb_get_retry;
+ }
+ return epilog(thread, 2, 0, 1);
+ } else {
+ if (!svr_checker_up(checker->id, checker->rs))
+ log_message(LOG_INFO, "Regex success to [%s]:%d url(%d)."
+ , inet_sockaddrtos(&http_get_check->dst)
+ , ntohs(inet_sockaddrport(&http_get_check->dst))
+ , http_arg->url_it + 1);
+ return epilog(thread, 1, 1, 0) + 1;
+ }
+ }
+
return epilog(thread, 1, 0, 0) + 1;
}
@@ -492,6 +569,9 @@ http_process_response(request_t *req, int r)
req->status_code = extract_status_code(req->buffer, req->len);
r = req->len - (req->extracted - req->buffer);
if (r) {
+ req->buffer_regex = (char *) MALLOC(MAX_BUFFER_LENGTH+1);
+ memmove(req->buffer_regex, req->extracted, r);
+ req->buffer_regex_len = r;
memmove(req->buffer, req->extracted, r);
MD5_Update(&req->context, req->buffer, r);
r = 0;
@@ -499,6 +579,11 @@ http_process_response(request_t *req, int r)
req->len = r;
}
} else if (req->len) {
+ if (req->buffer_regex_len < MAX_BUFFER_LENGTH) {
+ size_t to_copy = (req->buffer_regex_len + req->len < MAX_BUFFER_LENGTH ) ? \
req->len : MAX_BUFFER_LENGTH - req->buffer_regex_len; + memmove(req->buffer_regex + \
req->buffer_regex_len, req->buffer, to_copy); + req->buffer_regex_len += to_copy;
+ }
MD5_Update(&req->context, req->buffer,
req->len);
req->len = 0;
@@ -607,6 +692,8 @@ http_response_thread(thread_t * thread)
/* Allocate & clean the get buffer */
req->buffer = (char *) MALLOC(MAX_BUFFER_LENGTH);
+ req->buffer_regex = NULL;
+ req->buffer_regex_len = 0;
req->extracted = NULL;
req->len = 0;
req->error = 0;
diff --git a/keepalived/include/check_http.h b/keepalived/include/check_http.h
index 221bb91..92a95e4 100644
--- a/keepalived/include/check_http.h
+++ b/keepalived/include/check_http.h
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <openssl/md5.h>
#include <openssl/ssl.h>
+#include <unicode/uregex.h>
/* local includes */
#include "check_data.h"
@@ -40,6 +41,8 @@
/* ssl specific thread arguments defs */
typedef struct _request {
char *buffer;
+ char *buffer_regex;
+ size_t buffer_regex_len;
char *extracted;
int error;
int status_code;
@@ -59,6 +62,8 @@ typedef struct _http_arg {
typedef struct _url {
char *path;
char *digest;
+ char *regex_pattern;
+ URegularExpression *regexp;
int status_code;
} url_t;
--
1.7.6.5
["0002-Document-new-option-regex.patch" (text/x-diff)]
>From b3402f53beb6733f484509137fe6e0689ef805ed Mon Sep 17 00:00:00 2001
From: Alexander Holler <alexander.holler@1und1.de>
Date: Mon, 12 Dec 2011 10:27:50 +0100
Subject: [PATCH 2/3] Document new option regex.
---
doc/keepalived.conf.SYNOPSIS | 3 +++
doc/man/man5/keepalived.conf.5 | 5 ++++-
2 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/doc/keepalived.conf.SYNOPSIS b/doc/keepalived.conf.SYNOPSIS
index ddbc1c1..18d5966 100644
--- a/doc/keepalived.conf.SYNOPSIS
+++ b/doc/keepalived.conf.SYNOPSIS
@@ -332,11 +332,14 @@ virtual_server group <STRING> { # VS group declaration
url { # A set of url to test
path <STRING> # Path
digest <STRING> # Digest computed with genhash
+ regex <STRING> # Regular expression searched for in
+ # the first 4000 bytes of the response
status_code <INTEGER> # status code returned into the HTTP
} # header.
url {
path <STRING>
digest <STRING>
+ regex <STRING>
status_code <INTEGER>
}
...
diff --git a/doc/man/man5/keepalived.conf.5 b/doc/man/man5/keepalived.conf.5
index b8db9fe..f1d727e 100644
--- a/doc/man/man5/keepalived.conf.5
+++ b/doc/man/man5/keepalived.conf.5
@@ -396,10 +396,13 @@ A virtual_server can be a declaration of one of
#eg path / , or path /mrtg2/
path <STRING>
# healthcheck needs status_code
- # or status_code and digest
+ # or status_code and digest or regex
# Digest computed with genhash
# eg digest 9b3a0c85a887a256d6939da88aabd8cd
digest <STRING>
+ # Regular expression which is searched in the first
+ # 4000 bytes of the response
+ regex <STRING>
# status code returned in the HTTP header
# eg status_code 200
status_code <INT>
--
1.7.6.5
["0003-Add-libicuuc-as-requirement.patch" (text/x-diff)]
>From 6b800da9ccbc57e313b978f9f530134200af7e43 Mon Sep 17 00:00:00 2001
From: Alexander Holler <alexander.holler@1und1.de>
Date: Wed, 4 Jan 2012 13:57:59 +0100
Subject: [PATCH 3/3] Add libicuuc as requirement
---
configure.in | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/configure.in b/configure.in
index 9c3624c..27badfe 100644
--- a/configure.in
+++ b/configure.in
@@ -54,6 +54,7 @@ dnl ----[ Checks for libraries ]----
AC_CHECK_LIB(crypto, MD5_Init,,AC_MSG_ERROR([OpenSSL libraries are required]))
AC_CHECK_LIB(ssl, SSL_CTX_new,,AC_MSG_ERROR([OpenSSL libraries are required]))
AC_CHECK_LIB(icui18n, uregex_openC_44,,AC_MSG_ERROR([ICU libraries are required]))
+AC_CHECK_LIB(icuuc, u_uastrncpy_44,,AC_MSG_ERROR([ICU libraries are required]))
AC_CHECK_LIB(popt, poptGetContext,,AC_MSG_ERROR([Popt libraries is required]))
AC_CHECK_LIB(nl, nl_handle_alloc,
[
--
1.7.6.5
------------------------------------------------------------------------------
Virtualization & Cloud Management Using Capacity Planning
Cloud computing makes use of virtualization - but cloud computing
also focuses on allowing computing to be delivered as a service.
http://www.accelacomm.com/jaw/sfnl/114/51521223/
_______________________________________________
Keepalived-devel mailing list
Keepalived-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/keepalived-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic