An HTTP service for xinetd written in bash
This is written as a starting framework example for servicing HTTP requests to obtain health of some local service that is desired to be monitored. It can also be used on the command line to obtain the same health information.
If you need a monitoring application that is heavy in client connections, or needs to store stateful information, consider writing a daemon that runs on its own as opposed to an xinetd application. However, if your needs are light, and you want HTTP REST-like capabilities, perhaps this meets your needs.
Version 0.3 was updated to parse HA Proxy's X-Haproxy-Server-State
HTTP
header when HAProxy uses the configuration option httpchk
with http-check send-state
. By default, this xinetd script can send results back to HA Proxy
with both option tcp-check
and option httpchk
without differing
configuration. See HA Proxy Use below.
Edit the xinetdhttpservice.sh file, modifying the script at the bottom to add your custom code. Look for the section titled "Add your health checking logic below". You can modify or remove the example code that is in this section.
#
# Add your health checking logic below
#
# If --http-status is provided, http_response() function will send the value in
# an HTTP response. Otherwise the value is displayed alone.
#
# If something unhealthy was detected, then:
decrease_health_value
# display health value response, and exit
display_health_value
# send a http_response of 200
http_response 200 "Success"
# End of program
This function will obtain the value of a paramter provided in the HTTP request.
# if GET Request URI (GET_REQ_URI) is "/?uptime=seconds&format=json"
format_value=$(get_http_req_uri_params_value "format")
# Result: format_value == json
This function will obtain the value of a paramter provided in the HTTP request header X-Haproxy-Server-State.
# if X-Haproxy-Server-State: UP; name=backend/server; node=haproxy-name; weight=1/2; scur=0/1; qcur=0; throttle=86%
HA_NAME=$(get_haproxy_server_state_value name)
# Result: HA_NAME == backend/server
HA_WEIGHT=$(get_haproxy_server_state_value weight)
# Result: HA_WEIGHT == 1/2
HA_STATE=$(get_haproxy_server_state_value state)
# Result: HA_STATE == UP
This function will return a HTTP response and exit. It will do nothing and return if the --http-response option is not set to 1, or if the request came from the command line and not as a HTTP request.
http_response 301 "I did not find what you were looking for."
This function will decrease the global health value
decrease_health_value
This function displays the global helath value in a HTTP response or standard output for the command line, and then exits.
display_health_value
linux$ xinetdhttpservice.sh --help
xinetd_http_service 0.3
https://github.com/rglaue/xinetd_bash_http_service
Copyright (C) 2018 Russell Glaue, CAIT, WIU <http://www.cait.org>
Usage: xinetd_http_service [options]
Description: bash script called by xinetd to service a HTTP request; a farmework for reporting on health
Options:
-h, --help show this help message and exit
--version show program's version number and exit
--verbose Display verbose messages
--http-status returns HTTP status for healthiness
when called by command line, default is --http-status=0
--health-value Show a value consistent with the health of this node
100% healthy is 0, value decreases with health status
--weight-value Show a weighted value based on the health value
--max-weight=n Start with this weight as max, default=100
--inverse-weight Inverse the weighted value
--show-headers Show the parsed HTTP headers instead of displaying health
-- Optional, specifically ends reading of options
Examples:
xinetd_http_service # Returns HTTP status
xinetd_http_service --health-value # Returns a number based on healthiness
echo "GET /weight-value?max-weight=200 HTTP/1.1" | xinetd_http_service
linux$ echo "GET /test123?var1=val1 HTTP/1.0" | xinetdhttpservice.sh --http-status --show-headers
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: close
Content-Length: 179
HTTP_REQ_VERSION=HTTP/1.0
HTTP_REQUEST=GET /test123?var1=val1 HTTP/1.0
HTTP_REQ_URI=/test123?var1=val1
HTTP_REQ_URI_PATH=/test123
HTTP_REQ_METHOD=GET
HTTP_REQ_URI_PARAMS=var1=val1
linux$ xinetdhttpservice.sh --show-headers <<HTTP_EOF
POST /weight-value?max-weight=200 HTTP/1.1
User-Agent: noagent/1.0
Host: 127.0.0.1:8080
Accept: */*
Content-Length: 78
Content-Type: application/x-www-form-urlencoded
{
"type": "json",
"key": "animal",
"color": "brown",
"name": "bear"
}
HTTP_EOF
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: close
Content-Length: 515
HTTP_CONTENT_LENGTH=78
HTTP_USER_AGENT=noagent/1.0
HTTP_REQ_VERSION=HTTP/1.1
HTTP_POST_CONTENT={
HTTP_ACCEPT=*/*
HTTP_CONTENT_TYPE=application/x-www-form-urlencoded
HTTP_REQUEST=POST /weight-value?max-weight=200 HTTP/1.1
HTTP_REQ_URI=/weight-value?max-weight=200
HTTP_REQ_URI_PATH=/weight-value
HTTP_REQ_METHOD=POST
HTTP_REQ_URI_PARAMS=max-weight=200
HTTP_SERVER=127.0.0.1:8080
--BEGIN:HTTP_POST_CONTENT--
{
"type": "json",
"key": "animal",
"color": "brown",
"name": "bear"
}
--END:HTTP_POST_CONTENT--
At the top of the xinetdhttpservice.sh bash script, there is a global variable that define the maximum allowed length of posted data. Posted data that has a length greater than this will be cut off.
MAX_HTTP_POST_LENGTH=200
If a non-compliant HTTP client is posting data that is shorter than the Content-Length, then the READ_BUFFER_LENGTH should be set to 1. By default this value is the size of the Content-Length, which is more efficient.
# If the value of Content-Length is greater than the actual content, then
# read will timeout and never allow the collection from standard input.
# This is overcome by reading one character at a time.
#READ_BUFFER_LENGTH=1
# If you are sure the value of Content-Length always equals the length of the
# content, then all of standard input can be read in at one time
READ_BUFFER_LENGTH=$DATA_LENGTH
Note: The maximum length of posted data that is accepted is the Content-Length or the MAX_HTTP_POST_LENGTH, whichever is shorter. If the HTTP client is posting data, yet provides a Content-Length of 0, no data will be read in.
linux$ echo "GET /test123?var1=val1 HTTP/1.0" | xinetdhttpservice.sh --http-status
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: close
Content-Length: 7
Success
linux$ xinetdhttpservice.sh
Success
linux$ echo "GET /weight-value?inverse-weight=0&max-weight=120 HTTP/1.0" | xinetdhttpservice.sh
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: close
Content-Length: 16
WEIGHT_VALUE=119
To configure this script as an xinetd service, add the xinetdhttpservice_config file to the system /etc/xinetd.d/ directory.
Then restart xinetd
CentOS-Flavors$ systemctl restart xinetd
Then query the service via a HTTP call
linux$ curl http://0.0.0.0:8080/weight-value?inverse-weight=0&max-weight=120
WEIGHT_VALUE=119
First setup the xinetd service, as described previously. Once setup, you should
be able to get the service status via TCP or HTTP check in HAProxy. This can be
tested as follows. Both TCP and HTTP checks will work without differing
configuration in the xinetd_bash_http_service script because the http_response
function only delivers output if the client made an HTTP request.
# TCP Checks
shell$ echo | nc 192.168.2.11 8080
Service OK
# HTTP Checks
shell$ curl http://192.168.2.11:8080
Service OK
# At the end of your xinetd_bash_http_service script
# send the HTTP response and exit
http_response 200 "Service OK"
# or send a TCP response and exit
echo "Service OK"
exit 0
# end of script
frontend some-fe-server
bind 192.168.1.1:1234
mode tcp
default_backend some-be-server-pool
# Both of these backends will work, but use http checks with the
# 'http-check send-state' if you want to receive the HA Proxy state.
# tcp checks
#backend some-be-server-pool
# option tcp-check
# tcp-check expect string "Service OK"
# server srv1 192.168.2.11:80 check port 8080
# server srv2 192.168.2.12:80 check port 8080
# http checks
backend some-be-server-pool
option httpchk GET /
http-check send-state
http-check expect string "Service OK"
server srv1 192.168.2.11:80 check port 8080
server srv2 192.168.2.12:80 check port 8080
Copyright (C) 2018 Center for the Application of Information Technologies, Western Illinois University. All rights reserved.
Apache License 2.0, see LICENSE.
This program is free software.