Search code examples
bashnetwork-programmingansiblehosts

List name server from resolv.conf with hostname in one line per host


I need to get the DNS server(s) from my network, I tried using:

- hosts: localhost
  gather_facts: no

  tasks:
    - name: check resolv.conf exists
      stat:
        path: /etc/resolv.conf
      register: resolv_conf
    - name: check nameservers list in resolv.conf
      debug:
        msg: "{{ contents }}"
      vars:
        contents: "{{ lookup('file', '/etc/resolv.conf') | regex_findall('\\s*nameserver\\s*(.*)') }}"
      when: resolv_conf.stat.exists == True

But this does not quite gives the result I need.

Will it be possible to write a playbook in such a way that the result looks like the below?

hostname;dns1;dns2;dnsN


Solution

  • The declaration below gives the list of nameservers

    nameservers: "{{ lookup('file', '/etc/resolv.conf').splitlines()|
                     select('match', '^nameserver.*$')|
                     map('split', ' ')|
                     map('last')|list }}"
    

    You can join the hostname and the items on the list

    msg: "{{ inventory_hostname }};{{ nameservers|join(';') }}"
    

    Notes

    1. Example of a complete playbook for testing
    - hosts: localhost
    
      vars:
    
        nameservers: "{{ lookup('file', '/etc/resolv.conf').splitlines()|
                         select('match', '^nameserver.*$')|
                         map('split', ' ')|
                         map('last')|list }}"
    
      tasks:
        - debug:
            var: nameservers
        - debug:
            msg: |
              {{ inventory_hostname }};{{ nameservers|join(';') }}
    

    1. The simplified declaration below works fine if there is no nameserver.* in the comments
    nameservers: "{{ lookup('file', '/etc/resolv.conf')|
                     regex_findall('\\s*nameserver\\s*(.*)') }}"
    

    Unfortunately, the Linux default file /etc/resolv.conf contains the comment:

    | # run "systemd-resolve --status" to see details about the actual nameservers.

    This regex will match nameservers.

    nameservers:
      - s.
    

    You can solve this problem by putting at least one space behind the keyword nameserver.

                     regex_findall('\\s*nameserver\\s+(.*)') }}"
    

    However, this won't help if there is the keyword nameserver in the comment.


    Q: "No filter named 'split'"

    A: There is no filter split in Ansible less than 2.11. Use regex_replace instead

    nameservers: "{{ lookup('file', '/etc/resolv.conf').splitlines()|
                     select('match', '^nameserver.*$')|
                     map('regex_replace', '^(.*) (.*)$', '\\2')|list }}"