include tasks from another role in ansible playbook

I'm designing a kind of playbook lib with individual tasks

so in the usual roles repo, I have something like:

roles
├── common
│   └── tasks
│       ├── A.yml
│       ├── B.yml
│       ├── C.yml
│       ├── D.yml
│       ├── login.yml
│       ├── logout.yml
│       └── save.yml
├── custom_stuff_workflow
│   └── tasks
│       └── main.yml
└── other_stuff_workflow
    └── tasks
        └── main.yml

my main.yml in custom_stuff_workflow then contain something like:

---

- include: login.yml
- include: A.yml
- include: C.yml
- include: save.yml
- include: logout.yml

and this one in the other workflow:

---

- include: login.yml
- include: B.yml
- include: A.yml
- include: D.yml
- include: save.yml
- include: logout.yml

I can't find a way to do it in a natural way: one way that worked was having all tasks in a single role and tagging the relevant tasks while including a custom_stuff_workflow

The problem I have with that is that tags cannot be set in the calling playbook: it's only to be set at command line as I'm distributing this ansible repo with many people in the company, I can't rely on command line invocations (it would be nice to have a #! header in yml to be processed by ansible-playbook command)

I could also copy the relevant tasks (inside common in the above tree) in each workflow, but I don't want to repeat them around

Can someone see a solution to achieve what I'd like without repeating the tasks over different roles?

I guess the corner stone of my problem is that I define tasks as individual and it looks not natural in ansible...

Thanks a lot

PS: note that the tasks in the workflow have to be done in specific order and the only natural steps to abstract would be the login and save/logout

PPS: I've seen this question How do I call a role from within another role in Ansible? but it does not solve my problem as it's invoking a full role and not a subset of the tasks in a role


Solution 1:

Just incase someone else bumps into this, version 2.2 of Ansible now has include_role.You can now do something like this.

---
- name: do something
  include_role:
    name: common
    tasks_from: login

Check out the documentation here.

Solution 2:

Yes, Ansible doesn't really like tasks as individual components. I think it wants you to use roles, but I can see why you wouldn't want to use roles for simple, reusable tasks.

I currently see two possible solutions:

1. Make those task-files into roles and use dependencies

Then you could do something like this in e.g. custom_stuff_workflow

dependencies:
  - { role: login }

See: https://docs.ansible.com/playbooks_roles.html#role-dependencies

2. Use include with "hardcoded" paths to the task files

- include: ../../common/tasks/login.yml

That worked pretty well in a short test playbook I just did. Keep in mind, you can also use parameters etc. in those includes.

See: http://docs.ansible.com/ansible/latest/playbooks_reuse.html

I hope I understood that question correctly and this helps.

Solution 3:

Using include_role: with option tasks_from is a good idea. However this still includes parts of the role. For example it loads role vars and meta dependencies. If apply is used to apply tags to an included file, then same tags are applied to meta dependencies. Also, the ansible output lists as the included role's name in its output, which is confusing.

It is possible to dynamically locate a role and include a file using first_found. One can find the role path searching DEFAULT_ROLES_PATH and load a file from tasks folder. Ansible uses the same variable when sarching a role, so long as the role is in a path that Ansible can find, then the file will be loaded.

This method is as dynamic as using include_role with option tasks_from

Example:

- name: Include my_tasks.yml from my_ansible_role
  include_tasks: "{{lookup('first_found', params)}}"
  vars:
    params:
      files: my_ansible_role/tasks/my_tasks.yml
      paths: "{{ lookup('config', 'DEFAULT_ROLES_PATH') }}"