Mo Tawakol
Mo Tawakol

Reputation: 87

How to create a service that will respond to an HTTP request by running a bash script and returning the output?

I have a DO loadbalancer setup in front of a MySQL Group Replication setup. What I need to do is create a health check for the loadbalancer via an http request.

What I've come up with so far is to create a bash script (code below) that basically checks if MySQL is up and running and then run this via xinetd on port 9201.

However, when I curl to http://ip:port from another server it never reads any output from my bash file and just connection reset by peer (after connecting and timing out).

I'm very new to all this, so I'm not sure if what I'm doing is even correct in the slightest.

service mysqlchk
{ 
        flags           = REUSE
        socket_type     = stream
        protocol        = tcp
        port            = 9201
        wait            = no
        user            = root
        server          = /opt/mysqlchk.sh
        disable         = no
        log_type        = FILE /var/log/xinetd.log
        log_on_success  = DURATION EXIT HOST PID USERID
        log_on_failure  = ATTEMPT HOST USERID
        only_from       = 0.0.0.0/0
}

Bash (Found online)

MYSQL_HOST="ip"
MYSQL_PORT="3306"
MYSQL_USERNAME="user"
MYSQL_PASSWORD="=password"

#
# We perform a simple query that should return a few results :-p

ERROR_MSG=`/usr/bin/mysql --host=$MYSQL_HOST --port=$MYSQL_PORT -- 
user=$MYSQL_USERNAME --password=$MYSQL_PASSWORD -e "show databases;" 
2>/dev/null`

#
# Check the output. If it is not empty then everything is fine and we 
return
# something. Else, we just do not return anything.
#
if [ "$ERROR_MSG" != "" ]
then
        # mysql is fine, return http 200
        /bin/echo -e "HTTP/1.1 200 OK\r\n"
        /bin/echo -e "Content-Type: Content-Type: text/plain\r\n"
        /bin/echo -e "\r\n"
        /bin/echo -e "MySQL is running.\r\n"
        /bin/echo -e "\r\n"
else
        # mysql is not fine, return http 503
        /bin/echo -e  "HTTP/1.1 503 Service Unavailable\r\n"
        /bin/echo -e "Content-Type: Content-Type: text/plain\r\n"
        /bin/echo -e "\r\n"
        /bin/echo -e "MySQL is *down*.\r\n"
        /bin/echo -e "\r\n"
fi

What's returned when I curl:

curl -v http://ip:9201/
*   Trying ip...
* TCP_NODELAY set
* Connected to ip (ip) port 9201 (#0)
> GET / HTTP/1.1
> Host: ip:9201
> User-Agent: curl/7.58.0
> Accept: */*
> 
* Recv failure: Connection reset by peer
* stopped the pause stream!
* Closing connection 0
curl: (56) Recv failure: Connection reset by peer

I'm not sure if the issue is because I'm just responding incorrectly to the request or?

EDIT: Running the bash script manually returns the right output based on if it can connect or not. I don't think there's a syntactical error in the bash itself, just the way it responds to an http request possibly.

Upvotes: 0

Views: 1622

Answers (2)

MattBianco
MattBianco

Reputation: 1531

Change the occurrences of echo -e into echo -ne if you get too many LF chars in the output (or remove the \n from the end of each line).

You may need to add correct Content-Length: headers to the output as well.

Also, make sure the script works without relying on any environment variables, such as $PATH.

I use these functions return the OK or FAIL responses in my script:

return_ok()
{
    echo -ne "HTTP/1.1 200 OK\r\n"
    echo -ne "Content-Type: text/html\r\n"
    echo -ne "Content-Length: 47\r\n"
    echo -ne "\r\n"
    echo -ne "<html><body>MySQL is running.</body></html>\r\n"
    echo -ne "\r\n"
    exit 0
}

return_fail()
{
    echo -ne "HTTP/1.1 503 Service Unavailable\r\n"
    echo -ne "Content-Type: text/html\r\n"
    echo -ne "Content-Length: 46\r\n"
    echo -ne "\r\n"
    echo -ne "<html><body>MySQL is *down*.</body></html>\r\n"
    echo -ne "\r\n"
    exit 1
}

Upvotes: 0

Diego Torres Milano
Diego Torres Milano

Reputation: 69218

xinetd listens for incoming requests over a network and launches the appropriate service for that request. Requests are made using port numbers as identifiers and xinetd usually launches another daemon to handle the request.

In you case, you are launching a script. Make sure it's executable, have the right permission and add the corresponding shebang

#! /bin/bash

Then try

telnet ip 9201

Upvotes: 0

Related Questions