16

The problem is best described with an example:

There are two roles:

  • mailserver: a basic mail server configuration
  • mailinglist: mailing list application

The mailing list software needs the mailserver to transport incoming mails to the mailing list software's "virtual inbox". This requires some configuration of the mail server. But the mailserver does not know about the mailing list role, nor other roles with similar configuration requirements.

What I would like to do is this:

  • mailinglist (and other similar roles) stores the transport configuration in a variable transport_config. This could be a "transport map" like $email => $spool.
  • mailinglist depends on the mailserver role.
  • mailserver configures it's "transport" using the variable transport_config.

Is there a way to do something like this in Ansible? Or another solution to this problem? It's not possible to use role variables like {role: mailserver, transport_config: ...}, as there may be more than one role depending on the mailserver.

What I can think of is a workaround: The mailserver reads/parses a configuration directory where transport maps are defined. mailinglist and other roles add files to this directory. The problem here is that this often requires a "configuration builder" which reads such configuration directories and generates the main configuration file.

techraf
  • 64,883
  • 27
  • 193
  • 198
Christian
  • 4,042
  • 4
  • 26
  • 28
  • you reported you can't use `dotdee` or `assemble` because they can't assemble lines. Can you give us an example of the configuration syntax you need for your `mailserver`? – LeoRochael Jul 10 '15 at 15:42
  • It's something like `transport_config = file:/etc/mailserver/transport_foo, file:/etc/mailserver/transport_bar`. – Christian Jul 13 '15 at 06:24
  • Are line continuations allowed in that syntax? Like finishing a line with ` \ ` to continue the content in the next line? Maybe like this you could use `assemble` to put each transport in a line by itself with a continuation. – LeoRochael Jul 14 '15 at 14:02

5 Answers5

25

You can accomplish this using role dependencies.

In the mailinglist role under roles/mailinglist/meta/main.yml, add something like this:

---
dependencies:
  - { role: mailserver, transport_config: ... }

Do the same for any other similar roles.

dshepherd
  • 4,989
  • 4
  • 39
  • 46
Ben Whaley
  • 32,811
  • 7
  • 87
  • 85
  • As written in the question, it's not possible to do that. Thanks anyway! – Christian Jul 15 '14 at 07:44
  • Actually, you misunderstand my answer. The role dependency lives within the mailinglist role. Other roles that also depend on `mailserver` can have their own dependencies in their own `meta/main.yml` and the `transport_config` variable would vary accordingly. Please reconsider the answer. – Ben Whaley Jul 15 '14 at 16:29
  • 2
    But this will run the mailserver role multiple times, each overwriting the last mailserver configuration. – Christian Jul 16 '14 at 10:59
  • `allow_duplicates: false` https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#running-role-dependencies-multiple-times-in-one-play – shellwhale Aug 05 '22 at 07:06
4

In response to your comment about a "configuration builder", see the assemble ansible module. The tricky part might be getting all the files into one place, before you run the assemble module.

Otherwise, tima's suggestion of host_ and group_vars makes sense.

Martin M.
  • 707
  • 7
  • 16
encoded
  • 1,166
  • 8
  • 4
  • Ah nice, didn't know aubout this module. Sadly it won't work with my example, as the transport configuration happens in one line in the config file. Eg. `transport_config = foo:bar, foo2:bar2, ...`. – Christian Jul 09 '14 at 11:12
  • 2
    In my use case, the comma separated values can split multiple lines, so this actually works. And possibly it will work for most use cases. – Christian Jul 13 '15 at 06:28
4

I know this is long answered, but I only just found a workable solution, and it's a little sneaky.

I use a third settings role, which has no tasks, only variables in a defaults/main.yml. The docs are a bit vague on this, but values here get rippled to all dependent roles, so if both roles depend on settings through their meta/main.yml files, both get a common set of values. These are overridable in the usual ways, through a group_vars file.

The surprise to me was that since, yes, the settings role is used more than once, it doesn't matter because there are no tasks in it, and that data can flow from there up the chain of dependencies.

It's an entirely new form of data flow in Ansible that I didn't know was possible.

Stuart Watt
  • 5,242
  • 2
  • 24
  • 31
2

Consider managing the mailserver configuration file with something like dotdee:

With dotdee, you assemble your final configuration file from a series of files placed in a .d directory.

In your case, the mailinglist role and others depending on mailserver would drop configuration snippets in a .d directory (created by the mailserver role) and run a command to update the mailserver configuration file like dotdee --update /path/to/mailserver/conf.

LeoRochael
  • 14,191
  • 6
  • 32
  • 38
  • 1
    Looks like the `assemble` module of Ansible, but has the same weakness, i.e. it can't assemble lines, only files. – Christian Jul 09 '15 at 07:27
0

I'm not familiar enough with your apps here to be sure, but I'm thinking that you may be better served using host or group variables to pass your configuration in to your roles. The roles can hold your defaults et al and expect to retrieve host/group variables values that you set on an individual basis. This may mean treating each app instance as a host rather than psychical host. How you model it depends on many finer points in your workflow, configuration and app.

This recent thread touches on some of this sort of thing: https://groups.google.com/forum/#!topic/ansible-project/yrnsx2Mw6rc

tima
  • 413
  • 1
  • 5
  • 11
  • Maybe I get it wrong, but this won't solve my problem, as the roles themselves provide configuration to the underlying roles. In my example, I don't want to configure the transport, as this is a "implementation detail". – Christian Jul 09 '14 at 11:08