Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to gather localhost facts in Ansible while gather_facts is set to "no" for all hosts in Ansible?

Tags:

ansible

My playbook uses routers as the hosts to perform tasks on. I have disabled facts for the hosts but I need to get access to ansible_date_time from the local host that I'm running the playbook on. The local host is an Ubuntu VM.

This is what my playbook looks like:

---
- hosts: lab
  gather_facts: no

  tasks:   
    - name: Run block tasks
      delegate_to: 127.0.0.1
      block:
        - name: Get cert serial number using OpenSSL
          shell: |
            openssl s_client -connect {{ inventory_hostname }}:50051 2>/dev/null  | sed -n -e '/BEGIN\ CERTIFICATE/,/END\ CERTIFICATE/ p' |openssl x509 -noout -serial  | cut -d'=' -f2 | sed -e 's/\(.*\)/\L\1/'
          register: serialNum
      
        - name: Print Serial Numbers
          debug:
            msg: "{{ serialNum.stdout_lines }}"

    - name: Ansible fact - ansible_date_time
      # gather_facts: yes
      delegate_to: 127.0.0.1
      debug:
        var: ansible_date_time.date

I can't put gather_facts: yes in the last task since that errors out.

If I enable gather_facts: yes at the play level then I get the facts of the routers which is not what I want.

Running the playbook as above gives me the following message:

TASK [Ansible fact - ansible_date_time] ***************************************************************************************************************************************************
ok: [router1.mgt.net] => {
    "ansible_date_time.date": "VARIABLE IS NOT DEFINED!"
}

Is this possible to do with Ansible?

like image 659
stminion001 Avatar asked Jan 24 '23 07:01

stminion001


2 Answers

The task setup can be used for this. This is actually the task called behind the scene, by Ansible, when you have gather_facts: yes.

For this, you don't even need to gather all facts, you can do with a minimal subset of them, with the parameter gather_subset.

Given the playbook:

- hosts: localhost
  gather_facts: no

  tasks:
    - setup:
        gather_subset:
          - 'min'
    - debug:
        var: ansible_date_time.date

This will yield the recap:

PLAY [localhost] *************************************************************************************************

TASK [setup] *****************************************************************************************************
ok: [localhost]

TASK [debug] *****************************************************************************************************
ok: [localhost] => 
  ansible_date_time.date: '2021-07-08'

PLAY RECAP *******************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
like image 135
β.εηοιτ.βε Avatar answered Jun 09 '23 00:06

β.εηοιτ.βε


I'm not 100% sure I got your use case but here is my take.

Before going further, a few notes.

  • Delegating to 127.0.0.1 is globally a bad practice as it might use ssh rather than the local connection plugin and force you to define a host in your inventory rather than using the implicit localhost
  • We need to gather facts from localhost to get its ansible_date_time info. We will do this in a separate play and assign the value as a play var in the next one for ease of use. There are many other ways to deal with this but the bottom line is the use of the hostvars magic variable to get a fact from a specific host.
  • If you find gathering the full set of facts from localhost is too resource intensive, you can mix my proposition with the one from @β.εηοιτ.βε

Here is how I would fix your playbook (not fully tested)

---
- name: Gather facts from localhost for later use
  hosts: localhost
  # If facts gathering is disabled in ansible.cfg you will
  # have to turn it on explicitly (i.e. `gather_facts: true`)
  

- name: Do the actual work on lab routers
  hosts: lab
  gather_facts: no

  vars:
    # Get current date from localhost in a play var
    current_date: "{{ hostvars['localhost'].ansible_date_time.date }}"

  tasks:   
    - name: Get cert serial number using OpenSSL
      shell: |
        openssl s_client -connect {{ inventory_hostname }}:50051 2>/dev/null  | sed -n -e '/BEGIN\ CERTIFICATE/,/END\ CERTIFICATE/ p' |openssl x509 -noout -serial  | cut -d'=' -f2 | sed -e 's/\(.*\)/\L\1/'
      register: serialNum
      delegate_to: localhost
      
    - name: Print Serial Numbers
      debug:
        msg: "{{ serialNum.stdout_lines }}"

    - name: Show date from localhost gathered at very beginning
      debug:
        var: current_date
like image 38
Zeitounator Avatar answered Jun 09 '23 01:06

Zeitounator