How to pass a files/ folder in ansible include_role option - ansible

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

Related

Ansible - How to manage Large list of small tasks

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

How to run a task only once during entire Ansible Playbook?

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

Change ansible inventory based on variables

Can a playbook load inventory list from variables? So I can easily customize the run based on chosen environment?
tasks:
- name: include environment config variables
include_vars:
file: "{{ item }}"
with_items:
- "../../environments/default.yml"
- "../../environments/{{ env_name }}.yml"
- name: set inventory
set_fact:
inventory.docker_host = " {{ env_docker_host }}"
Yes. Use the add_host module: https://docs.ansible.com/ansible/latest/modules/add_host_module.html
As I'm in ansible 2.3 I can't use the add_host module (see Jack's answer and add_host docs) and that would be a superior solution. Therefore, I'll use a different trick to augment an existing ansible inventory file, reload and use it.
hosts.inv
[remotehosts]
main.yml
- hosts: localhost
pre_tasks:
- name: include environment config variables
include_vars:
file: "{{ item }}"
with_items:
- "../environments/default.yml"
- "../environments/{{ env_name }}.yml"
- name: inventory facts
run_once: true
set_fact:
my_host: "{{ env_host_name }}"
- name: update inventory for env
local_action: lineinfile
path=hosts.inv
regexp={{ my_host }}
insertafter="[remotehosts]" line={{ my_host }}
- meta: refresh_inventory
- hosts: remotehosts
...
The pretasks process the environments yml with all the variable replacement etc and use that to populate hosts.inv prior to reloading via refresh_inventory
Any tasks defined beneath - hosts: remotehosts would execute on the remote host or hosts.

ansible with_items pass variables from outside file

I just want to pass list of rpm packages in a yml file and call it in with_items inside my tasks.
Which format the yml file should be. Please help me. I googled a lot, still being confused. I need to achieve so that I could change only the package names in outside file, without changing the main file.
Ex: files.yaml
---
- vars:
modules:
- firmware-system-p89-2.56_2018_01_22-1.1.i386.rpm
- firmware-smartarray-ea3138d8e8-6.30-1.1.x86_64.rpm
=> passing to with_items in another file
---
- name: List required packages
include_vars:
-files.yml
set_fact: pkglist="{{ item}}"
with_items:
- "{{ modules }}"
register: pkglist_result
Comment:
Thanks a lot. that helps.
I did just this to finally accomplish. I wasn't trying right. But I mentioned just the name of the packages in files.yml and placed the real packages in files directory where tasks directory resides.
- name: List required packages
include_vars: files.yml
register: pkglist_result
- name: make a list
set_fact: pkg_list="{{ pkglist_result.ansible_facts.modules}}"
- debug: var=pkg_list
files.yml:
---
modules:
- firmware-system-p89-2.56_2018_01_22-1.1.i386.rpm
- firmware-smartarray-ea3138d8e8-6.30-1.1.x86_64.rpm
example playbook:
---
- hosts: my_hosts
vars_files:
- files.yml
tasks:
- name: print module name one by one
debug:
msg: "{{ item }}"
with_items: "{{ modules }}"

Read a file locally and use the vars remote in Ansible

I read a YAML file locally with the following playbook:
- name: Ensure the deploy_manifest var is defined and read deploy manifest
hosts: localhost
connection: local
gather_facts: False
tasks:
- assert:
that: deploy_manifest is defined
msg: |
Error: Must provide providers config path. Fix: Add '-e deploy_manifest=/path/to/manifest' to the ansible-playbook command
- name: Read deploy manifest
include_vars:
file: "{{ deploy_manifest }}"
name: manifest
register: manifest
- debug:
msg: "[{{ manifest.key }}]: {{ manifest.value }}"
with_dict: "{{ manifest.ansible_facts }}"
and then in the same playbook YAML file I run:
- name: Deploy Backend services
hosts: backend
remote_user: ubuntu
gather_facts: False
vars:
env: "{{ env }}"
services: "{{ manifest.ansible_facts }}"
tasks:
- include_role:
name: services_backend
when: backend | default(true) | bool
However it doesn't work because debug fails. It says that manifest is empty.
Which is the best way to read a YAML file or generally a configuration in a playbook and then have the variables passed in another playbook?
Your debug module doesn't say "that manifest is empty", it says the key manifest.key does not exist because it does not.
You registered a fact named manifest with:
register: manifest
You try to refer to a key of the above manifest named key and another key (!) named value:
msg: "[{{ manifest.key }}]: {{ manifest.value }}"
Please read Looping over Hashes chapter and acknowledge that (without using loop control) you refer to the iterated variable using item.
Please note that with name: manifest and register: manifest you read your vars file into manifest.ansible_facts.manifest.

Resources