Ansible: Check if service is listening on a specif

2020-07-06 06:54发布

问题:

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?

回答1:

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.



回答2:

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.



回答3:

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.



回答4:

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


标签: linux ansible