3

I am trying to have Ansible read a file and select the first match of my search parameter as well as remove unneeded text.

For example, I have the file below

<Proxy balancer://${balancerNameEAPI}>
#  BalancerMember https://server1.domain.com:port hctemplate=tcp
  BalancerMember https://server2.domain.com:port hctemplate=tcp
  ProxySet lbmethod=bybusyness
</Proxy>
<Proxy balancer://${balancerNamePAPI}>
#  BalancerMember https://server1.domain.com:port hctemplate=tcp
  BalancerMember https://server2.domain.com:port hctemplate=tcp
  ProxySet lbmethod=bybusyness
</Proxy>
<Proxy balancer://${balancerNameSAPI}>
#  BalancerMember https://server1.domain.com:port hctemplate=tcp
  BalancerMember https://server2.domain.com:port hctemplate=tcp
  ProxySet lbmethod=bybusyness
</Proxy>

I am needing to take action on the commented out standby host which in this case is server1.

I'm using the below script to read this config file and pull out the lines containing the correct host.

---
- name: test read file
  hosts: localhost
  gather_facts: false

  vars:
    source_file: /files/test/test.cfg
    host_to_patch: []

  tasks:

    - set_fact:
        host_to_patch: "{{ host_to_patch + [ item ] }}"
      with_lines: "cat {{ source_file }}"
      when: item is search('^#  BalancerMember https://server')

    - debug:
        var: host_to_patch

This of course gives me the output of the entire line three times where I'm only interested in the server1.domain.com portion of the line and at that I only need the first match. I'm wanting to tell Ansible this is the target hostname for another play further along in the playbook. The reason for this being that the servers in the file are an active standby pair and I need to do them one at a time starting with the standby host which could be different from month to month.

Below is the current output of what I have

ok: [localhost] => {
    "host_to_patch": [
        "#  BalancerMember https://server1.domain.com:port hctemplate=tcp",
        "#  BalancerMember https://server1.domain.com:port hctemplate=tcp",
        "#  BalancerMember https://server1.domain.com:port hctemplate=tcp"
    ]
}

Please let me know if any further info would be helpful and thanks in advance!

U880D
  • 8,601
  • 6
  • 24
  • 40
ITMike89
  • 57
  • 7

2 Answers2

1

Use Case

I am trying to have Ansible read a file and select the first match of my search parameter as well as remove unneeded text.

It is assumed that the structure within your configuration example file stays as it is provided and you are looking for a full Ansible equivalent to How do I grep a word after a match?

- name: Gather standby hostname
  shell:
    cmd: grep -Po 'https://\K.*' test.cfg | head -1 | cut -d ':' -f 1
  register: standby_hostname

Solution

You may have a look into the slurp module – Slurps a file from remote nodes and the minimal example playbook

---
- hosts: localhost
  become: false
  gather_facts: false

  tasks:

  - name: Read config file
    slurp:
      src: test.cfg
    register: config

  - name: Show config file
    debug:
      msg: "{{ config['content'] | b64decode }}"

  - name: Show first result
    debug:
      msg: "{{ config['content'] | b64decode | regex_findall('https://(.+)') | first | split(':') | first }}"

which will result into the output of

TASK [Show first result] ******
ok: [localhost] =>
  msg: server1.domain.com

The slurp module is used

... for fetching a base64 encoded blob containing the data in a remote file.

Therefore the b64decode filter – Decode a base64 string is necessary for further processing.

The regex_findall filter – extract all regex matches from string with https:// and behind the match (.+).

As it will provide a list, the Jinja2 Filter first will give only the first result.

The split filter – split a string into a list together with first filter is then used to get the left side of the : separated result set.

Similar Q&A

Further Documentation

U880D
  • 8,601
  • 6
  • 24
  • 40
0

Given the file

shell> cat /tmp/config.xml 
<Proxy balancer://${balancerNameEAPI}>
  #  BalancerMember https://server1.domain.com:65535 hctemplate=tcp
  BalancerMember https://server2.domain.com:65535 hctemplate=tcp
  ProxySet lbmethod=bybusyness
</Proxy>
<Proxy balancer://${balancerNamePAPI}>
  #  BalancerMember https://server1.domain.com:65535 hctemplate=tcp
  BalancerMember https://server2.domain.com:65535 hctemplate=tcp
  ProxySet lbmethod=bybusyness
</Proxy>
<Proxy balancer://${balancerNameSAPI}>
  #  BalancerMember https://server1.domain.com:65535 hctemplate=tcp
  BalancerMember https://server2.domain.com:65535 hctemplate=tcp
  ProxySet lbmethod=bybusyness
</Proxy>

Read the file

    - name: Read config file
      slurp:
        src: /tmp/config.xml
      register: config

and declare the variables

  _regex1: '^\s*#\s*BalancerMember https://server.*$'
  _regex2: '\bhttps\S*'
  hosts_to_patch: "{{ (config.content|b64decode).splitlines()|
                      select('regex', _regex1)|
                      map('regex_search', _regex2)|
                      map('urlsplit', 'hostname')|
                      unique }}"

gives

  hosts_to_patch:
  - server1.domain.com

Example of a complete playbook for testing

- hosts: localhost

  vars:

    _regex1: '^\s*#\s*BalancerMember https://server.*$'
    _regex2: '\bhttps\S*'
    hosts_to_patch: "{{ (config.content|b64decode).splitlines()|
                        select('regex', _regex1)|
                        map('regex_search', _regex2)|
                        map('urlsplit', 'hostname')|
                        unique }}"
      
  tasks:

    - name: Read config file
      slurp:
        src: /tmp/config.xml
      register: config

    - debug:
        var: hosts_to_patch
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63