<p>AFAIK there is no built-in module for this purpose, but you can use <code>shell</code> + <code>nc</code>:</p>

<pre><code>---
- hosts: all
  tasks:
    - shell: nc -z -w 1 -G 1 my.hostname.com {{ item }} || echo "Port {{ item }} is closed"
      with_items: [80,443,8443]
</code></pre>

CC BY-SA 3.0
2017-08-07T17:30:42.687Z
Thank you, this works also, but I opted to go with first suggestion as it allows me to further customize the play.
AWhitaker
CC BY-SA 4.0
2019-08-27T07:15:36.973Z
What is `-G 1` I can't find it in the man pages?
lonix
CC BY-SA 4.0
2020-10-16T04:46:49.503Z
@Ionix According to http://manpages.ubuntu.com/manpages/precise/en/man1/nc.traditional.1.html, it's source-routing pointer
windyzboy
CC BY-SA 3.0
2017-08-03T19:39:08.507Z
2017-08-03T19:39:08.507Z
Konstantin Suvorov
<p>You can use <a href="https://docs.ansible.com/ansible/2.5/modules/wait_for_module.html#synopsis" rel="nofollow noreferrer">wait_for</a> module for the same</p>

<p>example quoted from the documentation:</p>

<pre><code>- name: Wait 300 seconds for port 8000 of any IP to close active connections, don't start checking for 10 seconds
  wait_for:
    host: 0.0.0.0
    port: 8000
    delay: 10
    state: drained
</code></pre>

CC BY-SA 4.0
2018-07-17T11:06:39.060Z
Please try to format your post properly, all site on StackExchange network allow the same markdown, documentation for formatting is [here](https://devops.stackexchange.com/help/formatting)
Tensibai
CC BY-SA 4.0
2018-07-17T11:07:33.470Z
BTW I fail too see what this answer adds which is not in RichVel answer already
Tensibai
CC BY-SA 4.0
2018-07-17T10:27:55.610Z
2018-07-17T11:05:13.383Z
2018-07-17T11:05:13.383Z
user128364
<p>We use our tool dda-serverspec (<a href="https://github.com/DomainDrivenArchitecture/dda-serverspec-crate" rel="nofollow noreferrer">https://github.com/DomainDrivenArchitecture/dda-serverspec-crate</a>) for such tasks. You may define your expectation </p>

<p><code>{:netcat [{:host "mywebserver.com" :port "443"}
          {:host "telnet mywebserver.com" :port "80"}
          {:host "telnet mywebserver.com" :port "8443"}]}
</code></p>

<p>and test these expectation either against localhost or remote by ssh.
For remote tests you've to define a targets:</p>

<p><code>{:existing [{:node-name "test-vm1"<br>
             :node-ip "35.157.19.218"}<br>
            {:node-name "test-vm2"
             :node-ip "18.194.113.138"}]
 :provisioning-user
  {:login "ubuntu"}}
</code></p>

<p>You may run the test by <code>java -jar dda-serverspec.jar --targets targets.edn serverspec.edn</code></p>

CC BY-SA 4.0
2018-10-26T13:34:55.817Z
2018-10-26T13:34:55.817Z
jerger
<p>You can use the Ansible <a href="https://docs.ansible.com/ansible/latest/collections/ansible/builtin/wait_for_module.html" rel="noreferrer">wait_for</a> module which checks a specific TCP port is open.</p>
<p>Since in this case, all ports should be open already, we can use a minimal no. of retries, just enough to cover network issues:</p>
<pre><code>- name: Check all port numbers are accessible from the current host
  wait_for:
    host: mywebserver.com
    port: &quot;{{ item }}&quot;
    state: started         # Port should be open
    delay: 0               # No wait before first check (sec)
    timeout: 3             # Stop checking after timeout (sec)
  ignore_errors: yes
  with_items:
    - 443
    - 80
    - 80443
</code></pre>
<p>By default, Ansible will check once every second (configurable in Ansible 2.3 using the <code>sleep</code> attribute), so this will check 3 times per port.</p>
<p>Run this in a playbook against your inventory of 400+ hosts - Ansible will check in parallel that all hosts can reach <code>mywebserver.com</code> on those ports.</p>
<ul>
<li>the parallelism is subject to the <a href="http://docs.ansible.com/ansible/latest/intro_configuration.html#forks" rel="noreferrer">forks setting</a> in your <code>ansible.cfg</code>.</li>
</ul>
<p>We use <code>ignore_errors: yes</code> here so that any errors are marked in red but do not stop execution.</p>
<p>Open ports are reported as <code>ok</code> items in output and closed ports are reported as <code>failed</code> (you must use <code>-vv</code> flag on <code>ansible-playbook</code> to see this output).</p>
<h3>Fine-tuning output</h3>
<p>If you want more specific output for the success and failure cases, the code must be more complex, adding a second task:</p>
<ul>
<li><code>wait_for</code> task must <code>register</code> a variable</li>
<li>the second task produces output using <code>debug</code> based on success/failure condition (e.g. using Jinja2 <a href="https://stackoverflow.com/a/14215034/992887">conditional expression</a>)</li>
<li>then you need to put both these tasks in an include file (without any <code>with_items</code> loop), and write a main playbook task that uses an <code>include</code> ... <code>with_items</code> to call the include file once per port.</li>
</ul>

CC BY-SA 3.0
2017-08-05T18:18:25.007Z
Importantly they'd need to set `host: mywebserver.com`.
Xiong Chiamiov
CC BY-SA 3.0
2017-08-06T09:02:43.087Z
@XiongChiamiov - `host: x` is not required.  I just re-tested with Ansible 2.3.1 and the `host` attribute of `wait_for` tasks defaults to the current server being processed from inventory.
RichVel
CC BY-SA 3.0
2017-08-06T15:18:45.007Z
Exactly, which is why OP needs to override it: they're testing connectivity *to another webserver* from all of their servers (re-read the question).
Xiong Chiamiov
CC BY-SA 3.0
2017-08-07T06:47:17.733Z
Good point, have updated the answer with `hosts` attribute.
RichVel
CC BY-SA 3.0
2017-08-07T17:29:43.870Z
Thank you! This works for me, and gives me enough to work on.
AWhitaker
CC BY-SA 4.0
2018-07-18T11:00:34.657Z
Have to mention that wait_for works only for TCP ports
storm
CC BY-SA 4.0
2018-07-28T06:45:52.987Z
@storm - good point, edited to mention TCP only for wait_for.  However, checking for open UDP ports is hard because it has no concept of a connection (only what the application defines) - a UDP check would require various steps beyond scope of Ansible - see [this answer](https://networkengineering.stackexchange.com/a/26542/20183).
RichVel
CC BY-SA 4.0
2019-02-14T09:36:13.883Z
Ansible 2.5 has deprecated `with_items` etc, replacing them with the `loop` construct - see [this section](https://docs.ansible.com/ansible/latest/porting_guides/porting_guide_2.5.html#with-items) of the Ansible 2.5 porting guide.  You might want to do a `set_fact` to create a `ports` fact containing list of ports, then use `ports` instead of the `items` in porting guide.
RichVel
CC BY-SA 4.0
2021-04-09T09:48:40.947Z
Actually Ansible 2.5 did not deprecate with_items and other lookup-based loops, though it did deprecate some other with* loops - see the top of docs page on loops.  However, it  is possible to re-write them with the `loop` construct.
RichVel
CC BY-SA 4.0
2017-08-04T13:34:02.313Z
2020-10-16T06:32:18.853Z
2020-10-16T06:32:18.853Z
RichVel
<p>I'm new to Ansible. Here's my task ...</p>

<p>I have 400+ hosts, and I need to verify if 5 different ports are open from their end to our web server.</p>

<p>Individually, I could log in and run:</p>

<pre><code>telnet mywebserver.com 443
telnet mywebserver.com 80
telnet mywebserver.com 8443
</code></pre>

<p>..and so on..</p>

<p>What module or plugin could be used in Ansible so I could automate this, and have it report the results (whether open or closed ports) back to my Ansible server?</p>

<ansible><testing><ports>
Ansible: Other option available for telnet check of open ports?
AWhitaker
# Ansible: Other option available for telnet check of open ports?

(Asked by: username_0 on 2017-08-03)

I'm new to Ansible. Here's my task ...
I have 400+ hosts, and I need to verify if 5 different ports are open from their end to our web server.
Individually, I could log in and run:
telnet mywebserver.com 443
telnet mywebserver.com 80
telnet mywebserver.com 8443

..and so on..
What module or plugin could be used in Ansible so I could automate this, and have it report the results (whether open or closed ports) back to my Ansible server?

**Tags:** ansible, testing, ports


---

## 4 answers

### Answer by username_7 on 2017-08-04. Score: 37 | Accepted answer

You can use the Ansible wait_for module which checks a specific TCP port is open.
Since in this case, all ports should be open already, we can use a minimal no. of retries, just enough to cover network issues:
- name: Check all port numbers are accessible from the current host
  wait_for:
    host: mywebserver.com
    port: "{{ item }}"
    state: started         # Port should be open
    delay: 0               # No wait before first check (sec)
    timeout: 3             # Stop checking after timeout (sec)
  ignore_errors: yes
  with_items:
    - 443
    - 80
    - 80443

By default, Ansible will check once every second (configurable in Ansible 2.3 using the sleep attribute), so this will check 3 times per port.
Run this in a playbook against your inventory of 400+ hosts - Ansible will check in parallel that all hosts can reach mywebserver.com on those ports.

the parallelism is subject to the forks setting in your ansible.cfg.

We use ignore_errors: yes here so that any errors are marked in red but do not stop execution.
Open ports are reported as ok items in output and closed ports are reported as failed (you must use -vv flag on ansible-playbook to see this output).
Fine-tuning output
If you want more specific output for the success and failure cases, the code must be more complex, adding a second task:

wait_for task must register a variable
the second task produces output using debug based on success/failure condition (e.g. using Jinja2 conditional expression)
then you need to put both these tasks in an include file (without any with_items loop), and write a main playbook task that uses an include ... with_items to call the include file once per port.

> **Comments:**
> **username_8**: Importantly they'd need to set `host: mywebserver.com`.  
> **username_7**: @XiongChiamiov - `host: x` is not required.  I just re-tested with Ansible 2.3.1 and the `host` attribute of `wait_for` tasks defaults to the current server being processed from inventory.  
> **username_8**: Exactly, which is why OP needs to override it: they're testing connectivity *to another webserver* from all of their servers (re-read the question).  
> **username_7**: Good point, have updated the answer with `hosts` attribute.  
> **username_0**: Thank you! This works for me, and gives me enough to work on.  
> **username_9**: Have to mention that wait_for works only for TCP ports  
> **username_7**: @username_9 - good point, edited to mention TCP only for wait_for.  However, checking for open UDP ports is hard because it has no concept of a connection (only what the application defines) - a UDP check would require various steps beyond scope of Ansible - see [this answer](https://networkengineering.stackexchange.com/a/26542/20183).  
> **username_7**: Ansible 2.5 has deprecated `with_items` etc, replacing them with the `loop` construct - see [this section](https://docs.ansible.com/ansible/latest/porting_guides/porting_guide_2.5.html#with-items) of the Ansible 2.5 porting guide.  You might want to do a `set_fact` to create a `ports` fact containing list of ports, then use `ports` instead of the `items` in porting guide.  
> **username_7**: Actually Ansible 2.5 did not deprecate with_items and other lookup-based loops, though it did deprecate some other with* loops - see the top of docs page on loops.  However, it  is possible to re-write them with the `loop` construct.  

---

### Answer by username_1 on 2017-08-03. Score: 2

AFAIK there is no built-in module for this purpose, but you can use shell + nc:
---
- hosts: all
  tasks:
    - shell: nc -z -w 1 -G 1 my.hostname.com {{ item }} || echo "Port {{ item }} is closed"
      with_items: [80,443,8443]

> **Comments:**
> **username_0**: Thank you, this works also, but I opted to go with first suggestion as it allows me to further customize the play.  
> **username_2**: What is `-G 1` I can't find it in the man pages?  
> **username_3**: @Ionix According to http://manpages.ubuntu.com/manpages/precise/en/man1/nc.traditional.1.html, it's source-routing pointer  

---

### Answer by username_4 on 2018-07-17. Score: 0

You can use wait_for module for the same
example quoted from the documentation:
- name: Wait 300 seconds for port 8000 of any IP to close active connections, don't start checking for 10 seconds
  wait_for:
    host: 0.0.0.0
    port: 8000
    delay: 10
    state: drained

> **Comments:**
> **username_5**: Please try to format your post properly, all site on StackExchange network allow the same markdown, documentation for formatting is [here](https://devops.stackexchange.com/help/formatting)  
> **username_5**: BTW I fail too see what this answer adds which is not in username_7 answer already  

---

### Answer by username_6 on 2018-10-26. Score: 0

We use our tool dda-serverspec (<https://github.com/DomainDrivenArchitecture/dda-serverspec-crate>) for such tasks. You may define your expectation

`{:netcat [{:host "mywebserver.com" :port "443"}
{:host "telnet mywebserver.com" :port "80"}
{:host "telnet mywebserver.com" :port "8443"}]}`

and test these expectation either against localhost or remote by ssh.
For remote tests you've to define a targets:

`{:existing [{:node-name "test-vm1"  
:node-ip "35.157.19.218"}  
{:node-name "test-vm2"
:node-ip "18.194.113.138"}]
:provisioning-user
{:login "ubuntu"}}`

You may run the test by `java -jar dda-serverspec.jar --targets targets.edn serverspec.edn`


---

