Creation of dict on the fly

54 views
Skip to first unread message

Rick Kasten

unread,
Dec 20, 2014, 12:16:24 AM12/20/14
to ansible...@googlegroups.com
I have to create a haproxy config file with data from an unknown number of backend servers. The number is unknown, because based on the environment I need to run the playbook in, the number of backend servers could be 1 to several. My backend servers in haproxy.cfg need to defined something like this:

backend                       backend_nodes
    description               Web Servers
    balance                   roundrobin  
    server                    web01 10.0.2.1:8080 check
    server                    web02 10.0.2.3:8080 check
    server                    web03 10.0.2.3:8080 check

So on any given run of the playbook, I need to define the dict 'backend_servers' for X items (to generate the server lines above):

  - name: <server_name>
    ip: <server_IP>
    port: <http_port>
    params: <params>


With that block repeated for every server in groups['web_servers']. I tried using set_facts, but that can't define dict types. I have to do this as a dict, because different inventories will have different numbers of hosts in groups['web_servers'], and I can't hard-code this into my playbook or template, because the playbook will be used to configure different haproxy roles with different parameters, so this role needs to remain generic.

Timothy Gerla

unread,
Dec 20, 2014, 12:34:43 AM12/20/14
to ansible-project
I wonder if there might be a simpler way to approach this, but you could use a trick I have used a couple of times and use a template to generate a yaml data structure. Something like:

backend_servers.j2:

---
{% for x in groups['web_servers'] %}
- name: {{ x }}
  ip: {{ hostvars[x]['ansible_eth0']['ipv4']['address'] }}
  port: 8080
  params: blargh
{% endfor %}

Now, you can load this in the playbook like this:

- name: set the fact
  set_fact:
    backend_servers: "{{ lookup('template', 'backend_servers.j2')|from_yaml }}"

(Note that you need to use the "complex arguments" form and not the "set_fact: key=value" form, otherwise you will end up with a string and not a dict.)

This seems a little convoluted to me--and I don't fully understand why you couldn't simply template the haproxy.cfg file and just push the logic for the servers into the template, but I've used this pattern a couple of times when a simpler solution was not available.

-Tim

--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
To post to this group, send email to ansible...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/95c5422a-e604-4742-b282-0dc9c8265117%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Rick Kasten

unread,
Dec 20, 2014, 3:29:28 PM12/20/14
to ansible...@googlegroups.com
I like your yaml template idea, but I did end up pushing the logic off into my backend.cfg.j2 template:

{% for server in groups['web_servers'] %}
    server                    {{ server }} {{ hostvars[server].ansible_fqdn }}:{{ hostvars[server].http_port }} params
{% endfor %}


This is based off my current model where role 'haproxy/common' handles the global and default settings and role 'haproxy/web_servers' handles backend, frontend and listen settings. This should suffice going forward as long as other uses of haproxy get their own 'haproxy/other_backend' roles.
Reply all
Reply to author
Forward
0 new messages