Ansible playbook execution (NOT a ROLE) from SmartProxy or Single Role execution

Problem:
Hello

Is it possible to execute an ansible playbook which exists on a smart proxy or foreman server?
I know that I can import a playbook/role to foreman, then assign that playbook to a host. Then execute them by using a Schedule a job button from which I select “Run Ansible Roles”
But this will execute ALL ansible roles which are associated with that host. I don’t want that.

Let’s suppose that I have some healthcheck playbook which checks if services are up, if not starts them, additionally it checks the configuration etc. Plus I have host reboot playbook.
I want to execute only one or another. It doesn’t make sense to execute them all if e.g. I want to only check the health of my vm by executing healthcheck playbook.

Plus, I don’t want to keep my playbook code in Foreman, without direct integration with source control, it’s error prone. I would like to execute imported playbook OR a playbook which exists on a smart proxy or foreman server. Is it possible ?
If not, can I create an input which will use imported playbook name as an argument, like following:


If yes, how can I use the playbook code in the template? By default Run playbook job has following code:
<%= input('playbook') %>
When I select my imported ansible playbook, it tries to execute Imported Ansible Job ID (an integer) rather than Ansible code.
Is there a field or method which I could use which would allow me to retrieve ansible playbook code, rather than id? By something like:
<%= input('playbook').code %>
<%= input('playbook').playbook %>
Is there anything like that?

Moreover, I know that in the job template I can select “Script” provider type and in the job template code just execute ansible-playbook binary. But selecting “Script” provider type forces me to select a smart proxy as a target host, not a host on which I would like to execute a playbook. Not all my hosts have ansible and its playbooks installed, and they shouldn’t. It doesn’t make sense of doing that.

Expected outcome:
Is it possible to select a host from the host line, click on schedule a job, and execute one playbook which exists on a smart proxy or foreman server.

Foreman and Proxy versions:
3.13

Technically yes. You should be able to run a playbook from foreman that just imports another playbook from the filesystem. However bear in mind it was never intended to be used this way so while it may work now, noone can’t really guarantee that it will stay this way.

There’s the foreman-templates plugin which allows you to sync templates from and to git. Is that too indirect?

As far as I know, you can import roles as a first class object. You can “import” playbooks by turning them into job templates, but as far as I know you can’t import playbooks automatically and you definitely can’t assign them to hosts. You seem to be using playbooks and roles interchangeably, but they’re not the same thing.

No, not really. The thing you get from input('playbook') will be an object representing what foreman knows about the imported role. Foreman only knows metadata about the role, it doesn’t know the role’s implementation. Additionally, role can be composed from many files, it would be sort of difficult to turn all that into a single string.

1 Like

Hey, thanks for replying.

Technically yes. You should be able to run a playbook from foreman that just imports another playbook from the filesystem. However bear in mind it was never intended to be used this way so while it may work now, noone can’t really guarantee that it will stay this way.

How can I do this? What should be the code template?
How to read a local playbook? Something like this?
<%= File.read("/etc/ansible/playbooks/#{input('playbook')}") %>
where playbook, e.g. setup.yaml

You can “import” playbooks by turning them into job templates, but as far as I know you can’t import playbooks automatically and you definitely can’t assign them to hosts. You seem to be using playbooks and roles interchangeably, but they’re not the same thing.

As a matter of fact, my company doesn’t use roles at all. Mostly they’re only playbooks.
I think there was some kind of misunderstanding. I am refferring to the Ansible roles import:


Like above, I imported setup.yaml and assigned it to 1 host.
It doesn’t matter if it’s single playbook like setup.yaml or real role. Let’s assume that I assigned 10 real roles (not playbooks) to a host.
Now, after clicking the “Schedule a job” button I have an option to “Run Ansible roles”. All of them, I don’t want that. I want to be picky and select only roles X,Y,Z. Is it possible with Foreman? I don’t know if it’s gonna help me because I am not using roles at all, but playbooks.

Something like this could work

---
- ansible.builtin.import_playbook: /etc/ansible/playbooks/<%= input_resource('playbook').name %>

As long as the playbook input is a user input of value type resource and resource type ansible role just as you have in the original post.

That sounds like a bug to me. I can confirm that you can indeed import playbooks the same way as roles, but Foreman doesn’t internally treat them as playbooks and when you try to run them, it will try to apply them the same way as roles, which doesn’t really fly. Or at least that’s what I’m observing on my machine. CC @nofaralfasi

No, I don’t think so. With the snippet above, you should be able to pick one to be executed, but not multiple at once. Also if the thing you select is an actual role, it will fail, but that shouldn’t be a problem in your case.

1 Like

Hey

It doesn’t work because when resource type is provided foreman retrieves an ID of that resource, and you cannot access that resource details because safe mode is enabled (that’s by default).

  1. Playbook setup.yaml is imported:

  2. Job template defined as following:



  3. Playbook execution, I can select playbook from the list

After executing it I got following error:

Failed to initialize: RuntimeError - Failed rendering template: error during rendering: Safemode doesn’t allow to access ‘role_name’ on #Safemode::ScopeObject

I think this problem might be related to another one which I described in another post: Task Execution - Using another hostname as an input parameter?

I don’t get it what can be the use case of getting only IDs of the resources?
How it can be benefical? Only Foreman is aware of these IDs so we can’t really use selected resource in any job that requires some extra host-related information. We can’t get even the hostname of selected resource.

If you have everything configured as shown on the screenshots, you shouldn’t get an error about calling role_name as nothing should be calling role_name on anything. Now that the other thread is more or less settled, could you double check on your end? This seems to work on my machine

1 Like

Thanks, Adam, for tagging me. I want to ensure I understand correctly - are you saying the bug is that playbooks can be imported the same way as roles?

You can import playbooks the same way as roles, you can assign them to hosts same way as roles, but you can’t apply them the same way as roles. If you try to do so, Ansible will silently fail with

TASK [Apply roles] *************************************************************
[WARNING]: Ignoring invalid path provided to plugin path:
'/etc/ansible/roles/foo.yml' is not a directory

PLAY RECAP *********************************************************************
host.something.somewhere : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
Exit status: 0

Either it should work, or you shouldn’t be able to import them and assign them. Either would work for me, but this middle-ground isn’t good.

1 Like

Thank you for the clarification!

I created the following issue: Bug #38254: Inconsistent Behavior When Applying Playbooks Like Roles - Foreman to report this bug.