How would you go about using Ansible to confirm whether a service is running on a specific port?
For example:
- Is Apache running on port 80?
- Is MySQL listening on port 3912?
- Is Tomcat listening on port 8080?
I understand that there are the service
and wait_for
commands, which individually check if a service is running and if a port is in use - but I've not found anything so far to check if a particular service is listening on a particular port. service
and wait_for
will indicate there's a service and a port, but there's no guarantee that the port is taken by that particular service - it could be taken by anything. wait_for
, as I understand it, simply checks if it's being used.
There is a regex_search
parameter on wait_for
which mentions searching in a socket connection for a particular string, but as I understand it this is simply reading any information that comes down that socket rather than having any access to what is sending that information.
How can we go about this?
There are a couple of ways of interpreting your question, so I'm going to try to answer them both:
Verifying a network service
If your goal is to verify that a particular port is serving a particular application protocol, I would check this by running an appropriate client.
For checking Apache and Tomcat, I would GET
a specific url and check the result code. For example:
- name: check if apache is running
command: curl -sf http://webserver/check_url
And similarly for Tomcat.
For checking MySQL, I would use the MySQL client:
- name: check if mysql is running
command: mysql -h dbhost -P dbport -e 'select 1'
Verifying what process owns a socket
If you actually wanted to see what process was holding a particular port open, I guess you could combine ss
and grep
, but that seems weird and unnecessary. Something like:
- name: check if httpd has port 80 open
shell: ss -tp state listening sport = :80 | grep httpd
If you want to check a particular process id, you could so something similar with lsof
:
- name: check that pid {{apache_pid}} is listening on port 80
shell: lsof -p 1036 -P | grep 'TCP \*:80'
But again, I don't necessarily find these options particularly useful. The service checks in the earlier section seem to be more appropriate.
Perhaps you are looking at this problem with a wrong approach.
You would use configuration management systems(like Ansible) to make changes to your system, but you would use something like Serverspec
to ensure that correct processes are listening on correct ports.
Furthermore, your playbooks should be constructed in such a way that you are never in an ambiguous situation where different services could be listening on the same ports.
There's no built-in module in ansible that will verify a combination of a port and a service. What you will likely need to do is figure out an appropriate call to a command like netstat and invoke that via the command or shell modules. For example on a linux box the following command will show you what process is listening on port 80:
$ netstat -tunlp | grep ":80 " | sed -e 's/.*\///'
httpd
So from Ansible you'd probably want to do something like this:
- name: Get service on port 80
shell: netstat -tunlp | grep ":80 " | sed -e 's/.*\///'
register: results
- name: See what netstat returned
debug: var=results
If you want to be a bit fancier you could write a shell script that encapsulates the netstat call and does some more detailed parsing/validation of the output before returning the results to ansible. But then you'd need to install that script prior to invoking it.
AFAIK there is no built-in module that does this. Probably it is trivial to do it using the shell module or writing a small shell command that performs all checks.
You can use the fuser
command to check what process is listening at a given TCP port:
$ sudo fuser -n tcp 80
80/tcp: 20031 20080 20081
You can use ps
to see the name of the process:
$ ps hp 20031,20080,20081 -o comm
apache2
apache2
apache2
Combining everything:
$ ps hp `fuser -n tcp 80 2> /dev/null | cut -d ' ' -f 2` -o comm
apache2
$ ps hp `fuser -n tcp 80 2> /dev/null | cut -d ' ' -f 2` -o comm | grep apache2 -q
$ echo $? # should be 0 if apache2 is listening on port 80
0