77
votes

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

3
as per coderwall.com/p/dlsjya/executable-playbooks, we can put a shebang comment on top of the yml file, but again nothing prevents some colleague to run directly ansible-playbook on the file instead of running it as an executable (on top of portability issues)Louis
maybe the command line can be a helper. I use a perl script to run diffrent playbooks. (not exactly the same). The call from the script looks like: ansible-playbook name_of_playbook --extra-vars "lots of vars" , if it would be possible for you to specify the way your colleagues use it, thats maybe a way.ThoFin
indeed stackoverflow.com/users/4503915/thofin, but if I can find a native solution it would be much nicerLouis

3 Answers

73
votes

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.

47
votes

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.

1
votes

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') }}"