1

I'm writing Ansible roles, one role per 'service' / part of infrastructure that I'm managing. Let's say that' I'm managing some webserver, which is a part of a larger system. The whole system is managed by several playbooks, one each for deploying it, restarting it, getting status, backing it up, destroying it, etc.

Logically, each part of this larger system (webserver, database, runner, message queue, ...) would be encapsulated in a single role, and that role should expose all the relevant functionalities: deploy, restart, status, destroy, etc. I'd then just call the appropriate functionality for each role from the appropriate playbook, and all would be well.

However, I simply can't figure out what's the preferred / idiomatic way of handling this?

I encountered these candidate solutions, but none of them seem to cover all requests.

potential solution 1: a role with multiple entrypoints

The documentation for role argument validation, as well as import_role and include_role (tasks_from:) hints at using different task files in role/tasks/ as the entrypoint. This approach even allows for specifying different arguments for validation for each entrypoint.

However, this approach forces you to use the include_role and import_role tasks, preventing you from using the role as a regular role (in roles:).

potential solution 2: deciding based on args

This solution has you defining a special variable (say action) which chooses the action, and then you run tasks selectively in the role by checking if it's the correct action (when: action == 'destroy').

The vars / args for the role are then a weird union of all of the possible args any of the actions uses. This may work for the webserver example, but doesn't look great if you have more complicated actions, where args' types may clash.

potential solution 3: tags

You write all the actions in a contiguous role/tasks/main.yml. Yes, you can include them from other files in the tasks folder for better organization, each include tagged with the appropriate tag, but logically they still all run as a whole when you disregard the tags. You tag the steps with different tags (deploy, restart, ...), and then you can use it with include_role.

This seems fine, but you again must specify all the args / vars for the whole module, and it interferes with your tag use for other purposes.

potential solution 4: a combo of 1 and 2

You use args to decide the action in role/tasks/main.yml, then import the appropriate other action from role/tasks.

potential solution 5: something else?

There may be a solution I'm missing.


So, what's the idiomatic way of doing this? Are there any other benefits of these individual solutions that I'm missing? Is there some literature from developers codifying this that I haven't seen?

andrejr
  • 133
  • 6
  • There is no code. You can do what you want. *tasks_from* can't be used if you always have to run some common tasks. I prefer to use *tasks_from* with a kind of 'library' role, e.g. [ansible-lib](https://github.com/vbotka/ansible-lib/). I prefer the combination of tags and args to select functionality, e.g. [ansible-linux-postinstall](https://github.com/vbotka/ansible-linux-postinstall/tree/master). Especially practical I find 'namespacing' of tags, e.g. `lp_gpg, lp_gpg_conf, lp_gpg_debug, ...`. You can easily list tags by `--list-tags`. Proper naming of the tags can be self-explained. – Vladimir Botka Jul 02 '23 at 22:09
  • 1
    See [example](https://github.com/vbotka/ansible-certificate/blob/master/tasks/main.yml) of args and logical groups of tags. In this case, a [help](https://github.com/vbotka/ansible-certificate/blob/master/defaults/main.yml) is needed to explain the usage. – Vladimir Botka Jul 02 '23 at 22:19
  • You can always keep a `role/tasks/common.yml` and include it at the beginning of every entrypoint, that works. – andrejr Jul 02 '23 at 23:08
  • I need to have a certain granularity of actions performed on the system at large. Limiting hosts allows me to limit by location and test/prod criteria, and tags allow me to pick which part of the system I'm operating on (allowing me, say, restart just the db and message queue). I use different roles for the operations (restart, status, etc.). If I use tags for that same thing, inside the playbooks, that's kind of confusing. I also despise magical solutions where one thing is this when here and another thing there, and so does my team. – andrejr Jul 02 '23 at 23:15
  • 1
    This question will be closed as 'opinion-based', I'm afraid. You can [edit] the question and provide [mre] of your problem if you want to. – Vladimir Botka Jul 03 '23 at 00:35
  • I agree with Vladimir Botka. Every option you've described is correct. A final solution will depend on capabilities, environment and what "tastes" or work for one. Therefore, every answer will probably just an opinion. – U880D Jul 03 '23 at 06:36

0 Answers0