Home > Software design >  List name server from resolv.conf with hostname in one line per host
List name server from resolv.conf with hostname in one line per host

Time:11-08

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

CodePudding user response:

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 }}"

CodePudding user response:

Since your regex_findall already creates you a list with all DNS servers, you just need to add the hostname to that list and join the whole list with a semicolon.

- name: check nameservers list in resolv.conf
  debug:
    msg: >-
      {{
        (
          [ ansible_hostname ]  
          lookup('file', '/etc/resolv.conf', errors='ignore')
            | regex_findall('\s*nameserver\s*(.*)')
        ) | join(';')
      }}

Which will result in something like (b176263884e6 being the actual hostname of a container):

TASK [check nameservers list in resolv.conf] *****************************
ok: [localhost] => 
  msg: b176263884e6;1.1.1.1;4.4.4.4;8.8.8.8

Note that you don't even need the stat task, as you can ignore errors of the lookup with errors='ignore'.

This will, then, give you only the hostname, along with a warning:

TASK [check nameservers list in resolv.conf] *****************************
[WARNING]: Unable to find '/etc/resolv.conf' in expected paths 
(use -vvvvv to see paths)
ok: [localhost] => 
  msg: b176263884e6
  • Related