imp1sh
imp1sh

Reputation: 83

access other host's dictionary variable

Assume I have this hosts.yml

alpinehosts:
  hosta:
  hostb:

Those are hosta's hostvars in ./host_vars/hosta.yml (reverse proxy)

rproxyitems:
- rproxyfqdn: "pageA.com"
  comment: "This ia website A"
  rproxyaltfqdn: "alternativeA1.com alternativeA2.com"
  rproxytarget: "http://destinationA"
- rproxyfqdn: "pageB.com"
  comment: "This ia website B"
  rproxyaltfqdn: "alternativeB1.com alternativeBb.com"
  rproxytarget: "http://destinationB"

On the host the requests get redirected to I want to have nginx to have server_name just as in reverse proxy. Write once, use many.

That is my destination webhost ./host_vars/hostb.yml (Webserver requests get redirected to)

nginxvhost:
- fqdn: pageA.com
  servername: {{ hostvars[hosta].rproxyitems[rproxyfqdn[pageA.com]] }}
  serveraltname: {{ hostvars[hosta].rproxyitems[rproxyfqdn[pageA.com]].rproxyaltfqdn }}
  comment: "This is website A target webservice"
- fqdn: pageB.com
  servername: {{ hostvars[hosta].rproxyitems[rproxyfqdn[pageB.com]] }}
  serveraltname: {{ hostvars[hosta].rproxyitems[rproxyfqdn[pageB.com]].rproxyaltfqdn }}
  comment: "This is website B target webservice"

My way doesn't work but I hope you get the idea. How can I just access the other's host (hostA) dictionary variable elements? I could type the values manually of course, but I don't like the concept. I would like to define once, and use often.

For error look at screenshot.error message

Upvotes: 1

Views: 268

Answers (1)

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

Reputation: 39129

Well you are quite close to your solution, because hostvars[hosta].rproxyitems definitely shows you are on the right track.
But since pageA.com and pageB.com are values of a list and not keys or a dictionary, this is making your task more complex.

Two solutions for your issue:

  1. With your actual list structure, you can use the Jinja filter select and the match test of Ansible, to match an element of your list having a specific rproxyfqdn: rproxyitems | selectattr('rproxyfqdn', 'match', 'pageA.com'). This will return you a list, so if you know for sure you always have only one item matching, just adding a first filter would do.
    Given the playbook
    - hosts: hostb
      gather_facts: no
    
      tasks:
        - debug:
            msg: "{{ nginxvhost }}"
          vars:
            nginxvhost:
              - fqdn: pageA.com
                servername: "{{ (hostvars['hosta'].rproxyitems | selectattr('rproxyfqdn', 'match', 'pageA.com') | first).rproxytarget }}"
                serveraltname: "{{ (hostvars['hosta'].rproxyitems | selectattr('rproxyfqdn', 'match', 'pageA.com') | first).rproxyaltfqdn }}"
                comment: "This is website A target webservice"
              - fqdn: pageB.com
                servername: "{{ (hostvars['hosta'].rproxyitems | selectattr('rproxyfqdn', 'match', 'pageB.com') | first).rproxytarget }}"
                serveraltname: "{{ (hostvars['hosta'].rproxyitems | selectattr('rproxyfqdn', 'match', 'pageB.com') | first).rproxyaltfqdn }}"
                comment: "This is website B target webservice"
    
    This gives the recap:
    PLAY [hostb] ***************************************************
    
    TASK [debug] ***************************************************
    ok: [hostb] => {
        "msg": [
            {
                "comment": "This is website A target webservice",
                "fqdn": "pageA.com",
                "serveraltname": "alternativeA1.com alternativeA2.com",
                "servername": "http://destinationA"
            },
            {
                "comment": "This is website B target webservice",
                "fqdn": "pageB.com",
                "serveraltname": "alternativeB1.com alternativeBb.com",
                "servername": "http://destinationB"
            }
        ]
    }
    
  2. You could also slightly change your data structure and use a dictionary instead of a list, making it way easier to access a specific entry:
    rproxyitems:
      pageA.com:
        comment: "This ia website A"
        rproxyaltfqdn: "alternativeA1.com alternativeA2.com"
        rproxytarget: "http://destinationA"
      pageB.com:
        comment: "This ia website B"
        rproxyaltfqdn: "alternativeB1.com alternativeBb.com"
        rproxytarget: "http://destinationB"
    
    Which allow us to a direct access to rproxyitems['pageA.com'] and makes the playbook simpler:
    - hosts: hostb
      gather_facts: no
    
      tasks:
        - debug:
            msg: "{{ nginxvhost }}"
          vars:
            nginxvhost:
              - fqdn: pageA.com
                servername: "{{ hostvars['hosta'].rproxyitems['pageA.com'].rproxytarget }}"
                serveraltname: "{{ hostvars['hosta'].rproxyitems['pageA.com'].rproxyaltfqdn }}"
                comment: "This is website A target webservice"
              - fqdn: pageB.com
                servername: "{{ hostvars['hosta'].rproxyitems['pageB.com'].rproxytarget }}"
                serveraltname: "{{ hostvars['hosta'].rproxyitems['pageB.com'].rproxyaltfqdn }}"
                comment: "This is website B target webservice"
    
    This, will give the same recap as above.

Upvotes: 2

Related Questions