7

I use Ansible to manage some web- and database servers which run websites for multiple vhosts. For each website I need to assign a database role to the dbservers group and a website role to the webservers group. So my playbook looks something like this:

- hosts: dbservers
  roles: 
      - { role: database, vhost: 'host1.com', db: 'customdb' }
      - { role: database, vhost: 'other.com' }

- hosts: webservers
  roles: 
      - { role: website, vhost: 'host1.com', db: 'customdb' }
      - { role: website, vhost: 'other.com' }

This works well, but it is ugly as I have to repeat everything twice. This is especially error-prone when changing some parameters from the default values (like db on vhost host1.com in this example).

Is there a way to write this so I can have a single list of vhosts with all the required parameters and automatically add the different roles to the different host groups for each vhost entry?

Sven
  • 246
  • 2
  • 8

3 Answers3

8

the most obvious answer - use complex variables (dictionaries) to hold your values, and then pass entire variable:

- layouts:
  - layout1:
      vhost: host1.com
      db: customdb
  - layout2:
      vhost: other.com

then use those to pass over to roles:

- hosts: dbservers
  roles:
  - { role: database, layout: layouts.layout1 }
  - { role: database, layout: layouts.layout2 }

- hosts: webservers
  roles:
  - { role: webserver, layout: layouts.layout1 }
  - { role: webserver, layout: layouts.layout2 }

I've done this successfully in the past. To populate layouts you can use various techniques: combining "group_vars/all" with "vars_files" with "host_vars" etc.

Droopy4096
  • 680
  • 4
  • 8
  • This will help to make sure I don't accidentally give different parameters to the web servers and the database servers. But still has lots of repetition, is there a way to get rid of that? – Sven Apr 07 '15 at 17:03
5

What I do is I create roles apache, which installs apache and does some configuration for all vhosts, apache-vhost, which installs a vhost, host1-com, and other-com. Then the playbook would be like this:

- hosts: host1-com-servers
  roles:
    - apache
    - host1-com

- hosts: other-com-servers
  roles:
    - apache
    - other-com

Now, host1-com will have this:

- meta:
  - dependencies:
    - role: apache-vhost
      server_name: host1.com
      server_aliases:
        - www.host1.com
      extras: |
        Alias /static /var/local/myapp/static
        <Location /static>
          Require all granted
        </Location>
        # Whatever else you want
      whatever_other_variables_apache-vhost_needs: XXX

(This is an implementation detail, but the apache-vhost role prepares some essential vhost configuration based on the variables passed to it, and also adds the extras variable as is inside the vhost configuration.)

Likewise for the databases, you can have a postgresql role, a postgresql-database role, and so on.

Antonis Christofides
  • 2,598
  • 2
  • 23
  • 35
4

Rather than group your hosts by function, you could group them by role and have Ansible run a given role on a host only if that host is found in the designated group for that role.

[role_db_customdb]
other.com

[role_db_otherdb]
host1.com

[role_website]
host1.com
other.com

You can even pass parameters to a role, as illustrated with the db parameter in the playbook below.

---
- hosts: all

  roles:
    - { role: database, db: 'customdb', when: inventory_hostname in groups.role_db_customdb }
    - { role: database, db: 'otherdb', when: inventory_hostname in groups.role_db_otherdb }
    - { role: website, when: inventory_hostname in groups.role_webservers }
Brian Showalter
  • 1,069
  • 9
  • 13
  • I see where this would make sense to do this, but this doesn't help with my problem. Each web site (vhost) needs to be configured on each web server and a database on each database server. So "host1.com" is configured on web1, web2 and web3 and gets a database called "customdb" on the database servers db1 and db2. – Sven Apr 07 '15 at 17:10