Reuse set of tasks

I am the maintainer of a collection. Users of my collection use my roles to extend their own roles on and use them in their playbooks to deploy their system. I also provide a bunch of playbooks in the collection that my users can use directly as part of their deployments.

I found that my users do certain things (in lack of a better term) over and over again, like registering a Windows service in a specific way (how our internal software needs the service to be registered). These things typically consist of a small number of tasks, let’s say there are 5 tasks involved that are always the same, despite the name of the service and a few other vars being different. Some of these things register variables that are used in the following tasks.

Note: Keep in mind the registering of the windows-service is just an example I figured would be easy to show my issue. There are other examples like adding a specific value to a database or calling a specific API of an internal REST service.

Example Playbook of one of my users:

- hosts: localhost
  tasks:
# Users typically do some specific stuff to their deployment first
  - debug: msg="Do some unrelated stuff"

# The following tasks are the same for a lot of users:
  - debug: msg="Create a directory DIR1 for config"
  - debug: msg="Set environment var VAR1"
  - debug: msg="Download application from URL1"
  - debug: msg="Register Windows service APP_A"
  - debug: msg="Check some internal state, register variable STATE1"

# Users continue with other specific stuff, sometimes using vars
# like the internal state they queried after registering the service
  - debug: msg="Hello {{ STATE1 }}"

Now I’d like to help those users by taking the 5 middle tasks and putting them into something “reusable”. Normally I’d put them into a reusable_tasks.yml and include them like so:

- hosts: localhost
  tasks:
# Users typically do some specific stuff to their deployment first
  - debug: msg="Do some unrelated stuff"

# Users can now simply register their service by including my tasks.yml
# and providing some variables:
  - include_tasks: reusable_tasks.yml
    vars:
      - DIR1: foo_dir
      - VAR1: foo_var
      - URL1: foo_url
      - APP1: foo_app

# Users continue with other specific stuff, sometimes using vars
# like the internal state they queried after registering the service
  - debug: msg="Hello {{ STATE1 }}"

But as far as I’ve seen it isn’t possible to provide a list of tasks with a collection. The search pathes are documented to resolve from the local tasks and play directory.

A collection can provide Modules, Playbooks and Roles to be shared. But those will not help me replace the small number of tasks in an easy way:

  • Custom Module: These need to be Python scripts, right? I’d rather like to reuse the 5 tasks my users have been using instead of rewriting the registering of a Windows service in Python. However from a users perspective this looks like the best fit.
  • Playbook: Using import_playbook cannot be done within the task-list of a playbook as far as I understood. Users would need to restructure their playbooks in a larger way which will not be trivial.
  • Roles: This seems to be overengineering. I’d like to replace a few tasks, roles are much more complex. Users have their playbooks executing the tasks, it’d probably not be easy to integrate a whole role for 5 tasks within it.

The whole issue feels like there’s an easy solution that I’m looking over. Please let me know what detail I’m missing before I build something much too complex for something this simple.

While rereading this I found what I actually want to have is similar to a custom module:

- hosts: localhost
  tasks:
# Users typically do some specific stuff to their deployment first
  - debug: msg="Do some unrelated stuff"

# Users can now simply register their service with this task
  - register_internal_windows_service:
      dir: foo_dir
      env_var: foo_var
      url: foo_url
      app: foo_app
    register: register_output

# Users continue with other specific stuff, sometimes using vars
# like the internal state they queried after registering the service
  - debug: msg="Hello {{ register_output.state }}"

But as far as I found modules are Python scripts and cannot simply be a list of tasks. That’s why in my original post I tried exploring the usage of include_tasks with variables instead. But this is already a workaround solution to what I actually want to achieve.

Perhaps there are other, better ways to reach what I’d like to do.

After some research I think I’ll go with include_role and setting public=true. This should look like the following:

- hosts: localhost
  tasks:
# Users typically do some specific stuff to their deployment first
  - debug: msg="Do some unrelated stuff"

# Users can now simply register their service with this task
# This role sets its "return variables" within
# the `register_internal_windows_service` dict
  - include_role: namespace.collection.register_internal_windows_service
      public: true
    vars:
      dir: foo_dir
      env_var: foo_var
      url: foo_url
      app: foo_app

# Users continue with other specific stuff, sometimes using vars
# like the internal state they queried after registering the service
  - debug: msg="Hello {{ register_internal_windows_service.state }}"

We have one role called shared_tasks that contains almost nothing but various tasks files dedicated to specific purposes like this. It doesn’t even have a tasks/main.yml. To use it, we invoke include_role with the tasks_from parameter indicating which tasks file to use, and we add any variables as needed in a vars section.

That sounds to me like exactly the problem w/ solution you described.

4 Likes

Awesome, thanks for confirming what I hoped was a good idea :slight_smile:

“A set of thing that I want to reuse over and over” is a role. Put it in a role.

(You can also put things other than tasks in roles, but that doesn’t mean that you can’t put tasks in roles.)

3 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.