Disbalance
Disbalance

Reputation: 121

Find substring in ansible_hostname

I need to check all the cities in the country variable list to see if they contain the city name in the Ansible hostname variable.

It means running hosts can contain a city name in its own hostname.

- name:  Find city
  gather_facts: true
  hosts: 10.72.45.12
  vars:
    counties:
      Canada: ["ontario", "toronto", "montreal"]
      Germany: ["berlin", "munich", "hamburg"]
      USA: ["chicago", "ostin", "seattle"]
  tasks:

         - name: Getting counties by city
           set_fact:
             country: >-
               {% for city in counties %}
               {% if '{{ city }}' in '{{ ansible_hostname }}' %}
               Canada
               {% elif '{{ city }}' in '{{ ansible_hostname }}' %}
               Germany
               {% elif '{{ city }}' in '{{ ansible_hostname }}' %}
               USA
               {% else %}
               Earth
               {% endif %}
               {% endfor %}

         - debug:
            var: country

Upvotes: 3

Views: 405

Answers (2)

Vladimir Botka
Vladimir Botka

Reputation: 68384

Create dictionary cities

    - set_fact:
        cities: "{{ cities|d({})|combine(dict(item.value|product([item.key]))) }}"
      loop: "{{ countries|dict2items }}"

gives

  cities:
    austin: USA
    berlin: Germany
    chicago: USA
    hamburg: Germany
    montreal: Canada
    munich: Germany
    ontario: Canada
    seattle: USA
    toronto: Canada

Then select the cities

- hosts: foo_ontario_bar,foo_berlin_bar,foo_seattle_bar,foo_brussels_bar
  vars:
    countries:
      Canada: [ontario, toronto, montreal]
      Germany: [berlin, munich, hamburg]
      USA: [chicago, austin, seattle]
  tasks:
    - set_fact:
        cities: "{{ cities|d({})|combine(dict(item.value|product([item.key]))) }}"
      loop: "{{ countries|dict2items }}"
      run_once: true

    - debug:
        msg: >-
          {{ inventory_hostname }} match
          {{ _cities|zip(_countries)|map('join', '/')|list }}
      vars:
        _cities: "{{ cities|select('in', inventory_hostname) }}"
        _countries: "{{ _cities|map('extract', cities)|list }}"

gives (abridged)

  msg: foo_ontario_bar match ['ontario/Canada']
  msg: foo_berlin_bar match ['berlin/Germany']
  msg: foo_seattle_bar match ['seattle/USA']
  msg: foo_brussels_bar match []

Upvotes: 1

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

Reputation: 39324

Some errors in your code

  • Jinja delimiters do not nest. If you are inside a statement delimiter {% ... %}, you do not need an expression delimiter {{ ... }}:
    {% if city in ansible_hostname %}
    
  • You will need a nested loop, as the cities are in a list in your countries dictionary
  • The syntax to loop on a dictionary is a little bit different than the one to loop on a list:
    {% for key, value in my_dict.items() %}
    

With all this, you can construct the two tasks:

- set_fact:
    country: >-
      {% for country, cities in countries.items() -%}
        {% for city in cities if city in ansible_hostname -%}
          {{ country }}
        {%- endfor %}
      {%- endfor %}
  vars:
    countries:
      Canada: ["ontario", "toronto", "montreal"]
      Germany: ["berlin", "munich", "hamburg"]
      USA: ["chicago", "austin", "seattle"]

- debug:
    var: country | default('Earth', true)

Which could yield something like:

ok: [foo_ontario_bar] => 
  country | default('Earth', true): Canada
ok: [foo_berlin_bar] => 
  country | default('Earth', true): Germany
ok: [foo_seattle_bar] => 
  country | default('Earth', true): USA
ok: [foo_brussels_bar] => 
  country | default('Earth', true): Earth

Upvotes: 2

Related Questions