I have written lots of small yaml task files for an ansible project.
Only few of these tasks files are being reused (say 30%).
I wonder how to manage this big list of tasks, should I convert all of them to roles, and call the playbook with roles:
Playbook as below (pls ignore the syntaxe), will be clear, But I do not like to have a role for each simple task.
- name: playbook with roles for each task
hosts: all
roles:
- small_task_1
- small_task_2
- small_task_3
- small_task_4
....
....
- small_task_20
I liked the idea of putting them 2-3 roles, and call the task with include_task (or import_task), but the problem is, to each call of a task, I have to add "import_role: , name: , tasks_from" EVEN THOUGH It's from the same role!
$ ansible-galaxy role list
$ /home/user1/.ansible/roles
roles_a, (unknown version)
roles_b, (unknown version)
in roles_a and roles_b, I may have around 10 yaml tasks for each
,,,
name: playbook with 2 roles
hosts: all
- name: small task 1
include_role:
name: role_a
tasks_from: small_task_1
- name: small task 2
include_role:
name: role_a
tasks_from: small_task_2
......
......
- name: small task 9
include_role:
name: role_a
tasks_from: small_task_9
- name: small task 10
include_role:
name: role_a
tasks_from: small_task_10
,,,
Above thing is not very handy...
I would like to group the tasks in a "role" (or any other ansible thing), and call the tasks from that group... something like :
,,,
name: playbook with 2 roles
hosts: all
- name: small tasks
include_role:
name: role_a
tasks_from: small_task_1
tasks_from: small_task_2
......
......
tasks_from: small_task_9
tasks_from: small_task_10
,,,
I've tried with block , but it does not shorten the playbook.
Can anyone guide me, please?
For your final example, you can just use a loop directive on your include_role task, like this:
- hosts: localhost
gather_facts: false
tasks:
- include_role:
name: role_a
tasks_from: "{{ item }}"
loop:
- small_task_1
- small_task_2
- small_task_3
- small_task_4
Related
I am trying to reuse an existing role by using the include_role feature in ansible but I can not seem to find a way to pass the files inside the files/testrole1.yaml folder from the calling role and it always uses the files from the common role.
Here is the structure and code I came up with so far:
---
- name: importing tasks from role1
include_role:
name: service-deploy-role1
tasks_from: "{{item}}"
loop:
- install
- setup
The above code always uses the testrole1.yaml file. Is is possible to pass the testrole2.yml when I call the install task from the service-deploy-role1?
I could figure out the solution:
---
- name: workaround
set_fact:
role_location: "{{ role_path }}"
- name: debug role path
debug:
msg: "{{ role_location }}"
- name: importing tasks from role1
include_role:
name: service-deploy-role1
tasks_from: "{{item}}"
vars:
role_dir: "{{ role_location }}"
loop:
- install
- setup
I've an inventory as follow:
[central]
central_1
central_2
[peripheral]
peripheral_1
peripheral_2
...
central_1 and central_2 share the same database and each peripheral_* has its own local database.
Connection parameters are all stored in group_vars/central.yml and multiple host_vars/peripheral_* files.
Then I have a bunch of roles that access the database and perform specific operation based on values in peripheral_conf hostvars.
My goal here is to run a subset of the roles on one central host using the right DB access parameter.
First attempt
First attempt was to have two different play in the playbook targeting different hosts
- hosts: peripheral
pre_tasks:
- name: Load Configuration
set_fact:
peripheral_conf: "{{ hostvars[inventory_hostname] }}"
roles:
- role1
- role2
- role3
- hosts: central
roles:
- role1
- role2
but, since I normally run the playbook limiting the inventory to a specific peripheral host, I'm not able to run it against the central hosts.
Second attempt
I then tried to include role using delegate_to and delegate_fact:
- hosts: peripheral
gather_facts: False
pre_tasks:
- name: Load Configuration
set_fact:
peripheral_conf: "{{ hostvars[inventory_hostname] }}"
tasks:
- name: Insert values into central DB based on peripheral configuration
include_role:
name: '{{ item }}'
apply:
delegate_to: central
delegate_facts: yes
run_once: yes
loop:
- role1
- role2
roles:
# insert values into peripheral DB
- role1
- role2
- role3
but it keeps using peripheral's DB connection parameters.
Working attempt
I finally was able to make it works adding an explicit overriding of the connection parameters:
- hosts: peripheral
gather_facts: False
pre_tasks:
- name: Load Configuration
set_fact:
peripheral_conf: "{{ hostvars[inventory_hostname] }}"
tasks:
- name: Insert values into central DB based on peripheral configuration
include_role:
name: '{{ item }}'
apply:
delegate_to: central
run_once: yes
vars:
db_host : "{{ hostvars['central_app1']['db_host'] }}"
db_database: "{{ hostvars['central_app1']['db_database'] }}"
db_username: "{{ hostvars['central_app1']['db_username'] }}"
db_password: "{{ hostvars['central_app1']['db_password'] }}"
loop:
- role1
- role2
roles:
# insert values into peripheral DB
- role1
- role2
- role3
And finally, the question
The playbook does the job but I'd like to know if this is the only way of do this or there is any better and/or more efficient way to do this.
I have a playbook defined as below:
- name: install percona rpms
hosts: imdp
roles:
- role1
- role2
- role3
- role4
I just want the tasks defined in role 3 to be executed serially. If I define serial: 1 in the role3 tasks, it doesn't work. All tasks are executed in parallel. But if I defined serial: 1 in the main yaml (the above yaml) then all the roles are executed serially, which is also not needed.
How can I get just role3 to be executed serially?
"serial" is available in a play only. See Playbook Keywords. The solution is to split the roles among more plays. For example
- name: Play 1. install percona rpms
hosts: imdp
roles:
- role1
- role2
- name: Play 2. install percona rpms
hosts: imdp
serial: 1
roles:
- role3
- name: Play 3. install percona rpms
hosts: imdp
roles:
- role4
As example (emulation)
my-tasks.yml:
---
- include_tasks: custom-tasks.yml
when: inventory_hostname == item
with_items: "{{ ansible_play_hosts }}"
custom-tasks.yml:
---
- debug:
var: inventory_hostname
I have a Ansible playbook which does multiple things as below -
Download artifacts fron nexus into local server (Ansible Master).
Copy those artifacts onto multiple remote machines let's say server1/2/3 etc..
And I have used roles in my playbook and the role (repodownload) which downloads the artifacts I want to run it only once because why would i want to download the same thing again. I have tried to use run_once: true but i guess that won't work because that only works for one playbook run but my playbook is running multiple times for multiple hosts.
---
- name: Deploy my Application to tomcat nodes
hosts: '{{ target_env }}'
serial: 1
roles:
- role: repodownload
tags:
- repodownload
- role: copyrepo
tags:
- copyrepo
- role: stoptomcat
tags:
- stoptomcat
- role: deploy
tags:
- deploy
Here target_env is being passed from the command line and it's the remote host group.
Any help is appreciated.
Below is the code from main.yml from repodownload role -
- connection: local
name: Downloading files from Nexus to local server
get_url: url="{{ nexus_url }}/{{item}}/{{ myvm_release_version }}/{{item}}-{{ release_ver }}.war" dest={{ local_server_location }}
with_items:
- "{{ temps }}"
This is a really simple one that I battled with too.
Try this:
- connection: local
name: Downloading files from Nexus to local server
get_url:
url: "{{ nexus_url }}/{{item}}/{{ myvm_release_version }}/{{item}}-{{ release_ver }}.war"
dest: "{{ local_server_location }}"
with_items:
- "{{ temps }}"
run_once: true
Just something else, unrelated to your main question;
When you run a module that has really long args, like in your example above, rather break the params into their own lines nested under the module. It makes for easier reading, and it makes it easier to spot any potential typos or syntax errors early.
Okay extending from your converstation with Zeitounator. The following workaround will work without changing your vars files. Just remember that this is a workaround, might not be the most efficient way to do the job.
---
- name: Download my repo to localhost
# Executes only for first host in target_env and has visibility to group vars of target_env
hosts: '{{ target_env }}[0]'
serial: 1
roles:
- role: repodownload
tags:
- repodownload
- name: Deploy my Application to tomcat nodes
# Executes for all hosts in target_env
hosts: '{{ target_env }}'
serial: 1
roles:
- role: copyrepo
tags:
- copyrepo
- role: stoptomcat
tags:
- stoptomcat
- role: deploy
tags:
- deploy
I have a large playbook that uses multiple roles to setup new servers. I'd like to re-use the playbook but for the decommission stage instead of calling into role_name/tasks/main.yml and having a lot of when: statements, I'd like to tell Ansible to call the role but start in role_name/tasks/decommission.yml.
As a first test I setup my main.yml file like this:
- name: "Provisioning new server"
block:
- name: "Include the provisioning steps."
include_tasks: provision.yml
when:
- not decom
- name: "DECOM - Unregister from Satellite server"
block:
- name: "DECOM - Include the deprovision steps."
include_tasks: decommission.yml
when:
- decom
But that's getting really ugly to maintain. Is this possible or am I overlooking an alternative way to setup the playbook?
Q: "Tell Ansible to call the role but start in role_name/tasks/decommission.yml"
A: Use include_role
- include_role:
name: role_name
tasks_from: decommission.yml
,or import_role
- import_role:
name: role_name
tasks_from: decommission.yml
See Re-using files and roles on what is the difference between including and importing a role.