Stevel
Stevel

Reputation: 699

Ansible role dependencies - install but don't run (yet) - how?

I want my roles to be reusable and self-contained. To be reusable, each role does a focused piece of work following the "single level of abstraction" paradigm. This leads to many small "atomic" roles, with layers of coordination roles building on them to provide more complex abstractions.

To be self-contained, each role should declare its dependencies on other roles. I don't want such dependencies to be tightly bound to the top-level playbook (e.g. by way of an omnibus playbook/roles/requirements.yml). A role should be fully responsible for managing (declaring) roles it depends upon. This is easily done by way of abc_role/meta/main.yml with suitable entires in the "dependencies" array.

All well and good - except that Ansible Tower not only pulls external dependent roles, e.g. from public or private (custom) repository, IT ALSO RUNS THE ROLE. The "pulling of external roles" happens by Tower in a pre-job that follows all the dependencies recursively and gathers them into the playbook's "roles" directory. This is 100% prior to launching the job template itself. This same declaration of dependencies is also used, by Ansible proper, as a sequence of "pre-tasks" for the role - but without the benefit of any coordination by the using role. This is an unfortunate conflation of the "make available for later use" functionality and the "execute certain tasks first" functionality.

One simple reason for wanting to separate these two functionalities is so that I can have a role available (i.e. it's been installed from wherever) but only execute it conditionally based on dynamic host values. (Even where it's possible to put a role's task flow into "dependencies[]" those items don't seem to honor the "when:" conditional stanza. Thus, conditionals for dependencies are off the table.)

As per https://github.com/ansible/ansible/issues/35905 "Allow role dependencies to not be executed" - this desire of mine has some recognized value. Unfortunately, #35905's commentary / conversation offers no direct solution or mitigation (that I could find).

But I realllly want a solution with the properties that I want. Yes, I want what I want.

So I banged my head bloody, cursed my protoplasmic ancestry, and finally derived log(deps^tags) as a power set of {42} - et voila! (See my selfie answer, below.)

Upvotes: 6

Views: 1897

Answers (2)

cbusque
cbusque

Reputation: 1

As nyet said:

when: false

seem to work on ansible 2.9.5

Example :

 role_X/meta/main.yml

dependencies:

  - src: 'https://git_url.git'
    scm: 'git'
    version: 'commit_id'
    name: 'role_y'
    when: false

Upvotes: 0

Stevel
Stevel

Reputation: 699

Simply enhance each element of abc_role/meta/main.yml ~ "dependencies:" with "tags: [never]"

This gives me exactly what I want:

  • roles can declare what sub-roles they depend upon and have them made available (i.e. pulled down from wherever they come from and installed)
  • yet NOT compel the execution of said sub-roles in declaration sequence as "pre-tasks" of the depending role.

For the "I want to see an actual example" crowd -

===== abc_role/meta/main.yml =====

galaxy_info:
  # boring stuff elided...

dependencies: 
  - src: ssh://[email protected]/projectum/subrollio.git
    scm: git
    tags: [never]   # <<<=== This is the key bit

I have tested this and it works well.

 _______________ 
<  AWX 6.1.0.0  >
 --------------- 
        \   ^__^
         \  (oo)\_______
            (__)      A )\/\
                ||----w |
                ||     ||

                            Ansible 2.8.2

EDIT: Actually, this doesn't quite work in practice.

It does work as described, but when a parent-role is selected by explicit tag (e.g. from a playbook), then the child-roles listed in the parent's dependencies array are executed, despite having a "tags: [never]" element.

I'm still trying to revive my method, by fiddling with the tags or manipsmating them somehow and will update this posting when I have a definitive answer. In the meantime, I wanted to clarify the (very) serious limits of the solution I found and described - and (hope springs eternal) maybe get a better answer from our community...

RE-EDIT

After re-blooding my head through various bangings on the role dependencies array with a multitude of tag combinations plus reading through some of the Ansible source, I have given up my quest.

Over a year ago, @bcoca (one of the Ansible contributors, I think) said an "install but don't execute" meta keyword would be a good option, but there's been no traction on the feature request since then. Smells like dead fish (meaning: this isn't likely to get done).

So, it's back to the (very annoying) "bloat the playbook's requirements.yml with all its transitively-required roles" approach and then just deal with the code-maintenance craziness that entails. It's a fugly way to do things, but at least it can be made to work.

Upvotes: 2

Related Questions