x300n
x300n

Reputation: 331

Ansible: allocate unique ports to services

I have a role that creates a service that should bind to a unique port from within a specific range defined in a vars file.

---
    ports:
     - 9200
     - 9201
     - 9202
     - 9203
     - 9204

I do a quick check if these ports are bound already on the remote machine using wait_for before executing the role:

- hosts: all
  become: yes
  vars_files:
    - ports.yml

  pre_tasks:  
    - wait_for:
        host: 127.0.0.1
        port: "{{ item }}"
        state: started         # Port should be open
        delay: 0               # No wait before first check (sec)
        timeout: 1             # Stop checking after timeout (sec)
      ignore_errors: yes
      register: echo
      with_items: "{{ ports }}"

  roles:
    - azure_exporter

I would like to iterate through the ports, run the check above, and exits the loop once the port is found available. Then store that port in a variable and pass it to the role so that the service is gauranteed a unique port everytime the playbook executes.

I am stuck at finding a way to:

Upvotes: 2

Views: 878

Answers (1)

β.εηοιτ.βε
β.εηοιτ.βε

Reputation: 39169

Exiting a loop in Ansible is not really something you can achieve, this said, you can skip values you don't want to process as soon has you have found the port you were looking for.

So what you can do is loop on your ports, and skip all other values as soon as there is indeed a port that is not present. Then, with the rescue of a block, you can assign the port you found to a fact that you can then use later.

Given the playbook:

- hosts: all
  gather_facts: no
  pre_tasks:
    - block:
        - wait_for:
            host: 127.0.0.1
            port: "{{ item }}"
            state: present         
            timeout: 1  
          register: ports_status
          loop: "{{ ports }}"
          when: ports_status is not defined or ports_status is not failed
          vars:
            ports:
              - 9200
              - 9201
              - 9202
              - 9203
              - 9204

      rescue:  
        - set_fact:
            port: "{{ (ports_status.results | select('failed') | first).item }}"

  tasks:
    - debug:
        var: port
  • This would yields this result when no port is open:
    PLAY [all] *******************************************************************************************************
    
    TASK [wait_for] **************************************************************************************************
    failed: [localhost] (item=9200) => changed=false 
      ansible_loop_var: item
      elapsed: 1
      item: 9200
      msg: Timeout when waiting for 127.0.0.1:9200
    skipping: [localhost] => (item=9201) 
    skipping: [localhost] => (item=9202) 
    skipping: [localhost] => (item=9203) 
    skipping: [localhost] => (item=9204) 
    
    TASK [set_fact] **************************************************************************************************
    ok: [localhost]
    
    TASK [debug] *****************************************************************************************************
    ok: [localhost] => 
      port: '9200'
    
    PLAY RECAP *******************************************************************************************************
    localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=1    ignored=0 
    
  • And if you open the port 9200 with a simple nc -l -p 9200 then it starts giving:
    PLAY [all] *******************************************************************************************************
    
    TASK [wait_for] **************************************************************************************************
    ok: [localhost] => (item=9200)
    failed: [localhost] (item=9201) => changed=false 
      ansible_loop_var: item
      elapsed: 1
      item: 9201
      msg: Timeout when waiting for 127.0.0.1:9201
    skipping: [localhost] => (item=9202) 
    skipping: [localhost] => (item=9203) 
    skipping: [localhost] => (item=9204) 
    
    TASK [set_fact] **************************************************************************************************
    ok: [localhost]
    
    TASK [debug] *****************************************************************************************************
    ok: [localhost] => 
      port: '9201'
    
    PLAY RECAP *******************************************************************************************************
    localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=1    ignored=0   
    

Upvotes: 2

Related Questions