ansible playlets/included plays?

What I want in ansible:

Essentially, it is a simple way to let me port a bunch of puppet
modules directly to ansible.

right now I can include tasks - which is great
and I can include handlers - which is great

Ideally, though, I want to just include a single line and 'boom' that
playbook now does that new stuff. I want to deal with a set of tasks
and handlers and files/templates and variables, potentially, as a blob
that is 'finished'. So I can work on the blob, get it right, and not
have to modify all my other playbooks to fit it in.

In a lot of cases the porting of these modules is easy enough with
just included tasks - but the moment I need to do any special
variables or handlers that doesn't work w/o touching ALL of my
playbooks to include specific vars_files or to include handlers.

So what I think I want is an included 'thing' that inherits from the
current play. For the moment I've been calling it a playlet. It has
tasks, variables, handlers all of its own which are local to that
playlet in scope. It inherits the variables, handlers, and host-list
from the play it is included in and the variables/vars_files that it
includes are overridden exactly like ones in a playbook - meaning
group_vars, host_vars and extra_vars override them. (by treating vars
like that it would mean I could have sensible defaults in vars in a
task list w/o having to do any weird checks elsehwhere)

basic structure of where a playlet fits:
playbook
  - play1
        - playlet1
        - playlet2
  - play2
        - playlet3
        - playlet1

Perhaps a playlet would have a directory structure something like
playlet_name/
     vars/vars.yml
     files/myfile.conf
     myfile2.conf.j2
     handlers/handlers.yml
     playlet.yml

so an example play inclusion would be like:

- name: my play with playlets
  hosts: myhosts
  playlets:
  - path/to/playlet_name
  - path/to/playet_name_2

  tasks:
  - name: my task
    action: stuff which I do

Questions:

1. do playlets run before or after tasks in any given play?
2. should there be some other way ordering them?
3. is a playlet just a short hand for:
    - run this playbook - but override hosts with whatever this play
has and force these vars/handlers into it? Is it bad to have this kind
of short hand? Should we just allow a way to include playbooks like
this and stuff a bunch of vars into them?
4. can playlets include other playlets? (I'm inclined to say NO
but....)
5. what does running a playlet do to cwd for looking up files,
etc?
6. what does a playlet do with --tags?
7. what does a playlet do with --step?

I hope this helps flesh out what I was looking for here and explain how
I would like to use it. I've been looking at the playbook parsing code
to see how to fit this in w/the smallest amount of pain and it seems
like creating a new play and preloading the values from the existing
play would work - but I'm not sure if this is a good way of going about
it or if I should be looking at some sort of plugin that this would
work as.

Thanks,
-sv

I am currently favoring something like this:

hosts: webservers

tasks:

optional and as usual

handers:

optional and as usual

roles:

  • common
  • wordpress user=alice
  • wordpress user=bob

When a role is found (in this case ‘common’), it would do 3 things:

look for …/roles/common or roles/common relative to playbook

if roles/common/vars/main.yml exists, add it to vars_files

if roles/common/tasks/main.yml exists, add it to tasks as an include

if roles/common/handlers/main.yml exists, add it to tasks as an include

In the case of the wordpress example, the variables ‘user=alice’ would also be set automatically in vars, and passed to the task and handler.

This would be compatible with our ansible-examples repo idea of organizing based on roles and also allow us to improve them.

–Michael

This seems pretty easy to do in the main playbook.py code, I think, without too many modifications elsewhere in the stack.

If tasks and handlers were also specified loose, they would come into play after the roles got applied (just have to pick before or after, so I’m picking after, but maybe before is better?)

–Michael

Structurally this sounds fine - I want to think for a sec what this
means for folks looking to exchange these roles.

1. it'd be nice if it let me specify a path so my roles subdir doesn't
need to be adjacent to my playbooks.

2. the dir structure if I am distributing a role as an example:

rolename/
├── handlers
│ └── main.yml
├── tasks
│ └── main.yml
└── vars
    └── main.yml

Since in many cases these roles will need their own templates or config
files would it make since to toss a files/ dir in there too - for
relative files that can then be referred to relative to that dir? I
know that makes the files specification tricky- but I'm thinking of
the case where I want to take someone else's relatively-complicated
role and port it into my own repo. If I have to modify every file
specification to point to wherever my files are that's going to be
pretty onerous and error-prone.

that's why when I originally brought up the idea of the playlets I
wanted the files dir to be able to be relative to the rest of the
playlet.

Do you see what I mean?

For more of an example:

let's say I'm deploying a web app in a role. (like wordpress)
I need to deploy a wordpress-apache.conf file into /etc/httpd/conf.d/

so I have:

- name: put wordpress config into apache
  action: copy src=where?/wordpress/wordpress-apache.conf
          dest=/etc/httpd/conf.d/wordpress-apache.conf

Finally - how do we deal with duplicate handler definitions here? How
does ansible do that generally - if I two things named 'restart apache'?

thx

-sv

Structurally this sounds fine - I want to think for a sec what this
means for folks looking to exchange these roles.

1. it'd be nice if it let me specify a path so my roles subdir doesn't
need to be adjacent to my playbooks.

2. the dir structure if I am distributing a role as an example:

rolename/
├── handlers
│ └── main.yml
├── tasks
│ └── main.yml
└── vars
    └── main.yml

(And also templates & files, but yes, oh I see you say that later too!)

Since in many cases these roles will need their own templates or config
files would it make since to toss a files/ dir in there too - for
relative files that can then be referred to relative to that dir? I
know that makes the files specification tricky- but I'm thinking of
the case where I want to take someone else's relatively-complicated
role and port it into my own repo. If I have to modify every file
specification to point to wherever my files are that's going to be
pretty onerous and error-prone.

I think it should indeed allow this. We have some "path_dwim" functions
in Ansible that should be made smart about this.

Finally - how do we deal with duplicate handler definitions here? How
does ansible do that generally - if I two things named 'restart apache'?

Handlers are stored in hashes based on the name IIRC, so I believe they
overwrite. I can check.

Which actually seems reasonable I think.

Those path functions would need to be pretty stunning to know how to
find the files local to that task when the task is just included in the
normal set of tasks.

If you think about the tree in the bestpractices doc we have it pretty
similar but we have everything down one level for organization

ansible-repo
    playbooks
    files
    tasks
    roles/ <--- then the role names under here

so if my playbook is:
   playbooks/hosts/somehost.yml
   and it is including the 'common' role

I have no idea how it will find those files/templates specific to
'common'

However, if this is part of the bigger plan then that seems like a way
forward for me.

-sv

I can possibly see roles taking a path versus knowing to look in roles/$name.

I’ll fiddle with it some.