As per ansible documentation here I am using the below syntax to trigger a role when the variable "mdb_user" starts with prod.
- hosts: category_workstation
gather_facts: False
name: common workstation applications
roles:
- apps_workstation
- { role: apps_workstation_production, when: mdb_user.startswith('prod') }
This works nicely but what i want to know is if i can do something similar to adjust the variables fed to the role in different conditions. For instance the below:
- hosts : category_workstation
name: common workstation applications
roles:
- apps_workstation
- { role: apps_workstation_production, vars={'user':'prod'}, when: mdb_user.startswith('prod')}
Currently I am having to use when and set_fact to get the right variables setup before caling a roles and this approach above (if possible) seems more concise.
You can try something like:
- hosts : category_workstation
name: common workstation applications
roles:
- apps_workstation
- { role: apps_workstation_production, user: prod, when: mdb_user.startswith('prod')}
Related
I would like to skip some of the plays based on a conditional value.
I could have a task at the beginning that would skip some of the other tasks when a condition is met.
I know I could always use set_fact and use this as a condition to run the other plays (roles and tasks) or evaluate the said condition directly in each play I want to skip.
However, since the plays already have a tagging system in place, is there something like set_tags in Ansible that I could leverage on to avoid having to add conditions all over my plays and bloat my already heavy playbook.
Something such as:
- name: skip terraform tasks if no file is provided
hosts: localhost
tasks:
set_tags:
- name: terraform
state: skip
when: terraform_files == ""
The two plays I'd like to skip:
- name: bootstrap a testing infrastructure
hosts: localhost
roles:
- role: terraform
state: present
tags:
- create_servers
- terraform
[...]
- name: flush the testing infrastructure
hosts: localhost
roles:
- role: terraform
state: absent
tags:
- destroy_servers
- terraform
If I understood correctly, the following should do the job:
- name: bootstrap a testing infrastructure
hosts: localhost
roles:
- role: terraform
state: present
when: terraform_files != ""
tags:
- create_servers
- terraform
[...]
- name: flush the testing infrastructure
hosts: localhost
roles:
- role: terraform
state: absent
when: terraform_files != ""
tags:
- destroy_servers
- terraform
This is basically the same as setting the when clause on every single tasks in the role. So each task will be inspected but skipped if the condition is false.
I'm using Ansible to do the automation of my systems.
I have an Ansible playbook that depends on two roles.
The first role creates a user ("specific_user") on a remote server.
The second role uses this user to do a bunch of stuff.
My first solution was the following (my playbook) :
---
- hosts: all
roles:
- { role: ansible-role1, remote_user: root }
- { role: ansible-role2, remote_user: specific_user }
...
However, I'm getting the following warning from Ansible when running it:
Using 'remote_user' as a role param has been deprecated.
In the future, these values should be entered in the `vars:` section for
roles, but for now we'll store it as both a param and an attribute..
What is the alternative ?
Currently this is only a warning message (until version 2.7 of Ansible).
As the message suggests, you need to change syntax to (using YAML in the example below, because it's more readable):
roles:
- role: ansible-role1
vars:
remote_user: root
- role: ansible-role2
vars:
remote_user: specific_user
...
In my system provisioning with Ansible, I don't want to specify become=yes in every task, so I created the following ansible.cfg in the project main directory, and Ansible automatically runs everything as root:
[privilege_escalation]
become = True
But as the project kept growing, some new roles should not be run as root. I would like to know if it is possible to have some instruction inside the role that all tasks whithin that role should be run as root (eg. something in vars/), instead of the global ansible.cfg solution above!
I have found a solution, although I think a better solution should be implemented by the Ansible team. Rename main.yml to tasks.yml, and then write the following to main.yml:
---
- { include: tasks.yml, become: yes }
Another solution is to pass the parameter directly in site.yml, but the main idea of the question was reusing the role in other projects without forgetting it needs root:
---
- hosts: localhost
roles:
- { role: name, become: yes }
You can also wrap your tasks in a block and put become: yes on the block. So, inside your roles/role_name/tasks/main.yml, you'd do this:
- block:
- name: Tasks go here as normal
...
become: yes
This will run all the tasks inside the block as root. More details of Ansible's blocks here (latest docs).
Not really a fundamentally different answer, rather a cosmetic reformatting of what's already been said. Looks the shortest, cleanest and YAML-ishest to me:
- name: My play
hosts: myhosts
roles:
- role: role1
become: yes
- role: role2
Role1 will be run as root while role2 won't.
In Ansible documentation for 2.4, you can find a way to define connection variables, such as ansible_become and ansible_user. They are defined as usual variables. Below is a snippet.
The first role prepare_user connects to hosts using user root without elevation rights. The second role register connects to hosts using the remote_user set via ansible.cfg (looked for in a defined order; search for "in the following order").
---
- hosts: all
name: Prepare VMs for cluster
roles:
- role: prepare_user
vars:
- ansible_become: false
- ansible_user: root
- role: register
...
There is a way to do what you are asking, but you need to be careful with how you use it, because Ansible evaluates most vars before running any tasks. If you use this trick, you must be sure to use it consistently or you could unintentionally use become where you don't want to.
Under the hood, Ansible uses the variable ansible_become to determine whether to use become for that task. Within your role, you can create a defaults/main.yml and set ansible_become: [true/false] This will cause that entire role to accept that value, unless overwritten by a higher-precedence definition (important to understand variable precedence)
The critical "gotcha" here is that if you use a role where this is defined, it will affect all other roles called below it in the play, unless they also have it defined.
Examples:
role_default_become_true has ansible_become: true defined as true in defaults
role_default_become_false has ansible_become: false defined as true in defaults
role_no_default has no default ansible_become value
---
- name: test1
hosts: localhost
connection: local
roles:
- role_default_become_true
- role_default_become_false
- role_no_default
- name: test2
hosts: localhost
connection: local
roles:
- role_default_become_false
- role_default_become_true
- role_no_default
- name: test3
hosts: localhost
connection: local
roles:
- role_default_become_false
- role_default_become_true
- { role: role_no_default, become: false }
In test1, role_no_default will run without become, because the previous role defined it as false, and it does not have its own definition.
In test2, role_no_default will run with become, because the previous role defined it as true, and it does not have its own definition.
In test3, role_no_default will run without become, because it has its own definition.
This is also possible using the include_task module
Create a main.yaml which includes the yaml with the tasks
---
- name: main
include_tasks:
file: "my_tasks_that_needs_become_true.yaml"
apply:
become: true
I want to use the module mongodb_replication defined in greendayonfire.mongodb role.
I know I can use the module in my tasks after applying the role in the same play. But I don't want to apply the role (and execute all it's tasks). Is there any way to get to "include" the role without executing the tasks?
I want to have it like this
---
- hosts: mongodb-nodes
become: true
roles:
- base
- greendayonfire.mongodb
vars:
mongodb_package: mongodb-org
mongodb_version: "3.2"
mongodb_force_wait_for_port: true
mongodb_net_bindip: 0.0.0.0
mongodb_net_http_enabled: true
mongodb_replication_replset: "rs1"
mongodb_storage_prealloc: false
- hosts: mongodb-0
tasks:
- mongodb_replication: replica_set=rs1 host_name=item state=present
with_items:
- mongodb-0
- mongodb-1
- mongodb-2
where the second play is the one that runs the mongodb_replication module (only in the node mongodb-0). Right now it can't find the module.
I guess can I copy the module out of the role into my playbook but I will be cleaner if I could just import the module from the role (which I don't want to edit)
I found that it's possible to load the role without executing the task by using the when: false clause when referring to the role. This loads the vars, defaults, modules, etc.
- hosts: mongodb-0
roles:
- role: greendayonfire.mongodb
when: false
tasks:
- mongodb_replication: replica_set=rs1 host_name=item state=present
with_items:
- mongodb-0
- mongodb-1
- mongodb-2
Here is my play book:
- name: Install MySQL with replication
hosts: mysql-master:mysql-slave
user: root
sudo: false
roles:
- common
- admin-users
- generic-directories
- { role: iptables, tags: [ 'mysql-iptables'] }
- mysql
I have ip tables tasks for different ports, I want to run the task depending on the group of servers.
I have tagged the iptables task based on the group.
When i ran the play book instead of playing the tagged task, its run through all the tasks defined in iptables role.
Please let me know if am doing anything wrong here.
In practices roles should not contains code/configuration used only by you. Try to develop roles like if you're going to publish them, doing this you will create more generic/usefull roles
With an iptable role, what you want in the end is to open port/change firewall configuration.
The role should contains tasks that allow configuration in the playbook:
---
- name: iptables | Open ports
command: 'open port {{item.protocol}} {{item.port}}
with_items: 'iptable_conf'
tags:
- iptables
then you playbook
- name: Install MySQL with replication
hosts: mysql-master:mysql-slave
user: root
sudo: false
vars:
- iptables_conf:
- {protocol: tcp, port: 3307}
- {protocol: tcp, port: 3306}
roles:
- common
- admin-users
- generic-directories
- iptables
- mysql
Hope you like opinionated software all the way: https://github.com/ansible/ansible/issues/3283 .
If I'm reading that correctly, you're experiencing a feature, with everything in that role being tagged for you and your CLI tag specification subsequently matching all those tasks. I hate this feature. It's stupid. "Application" vs. "selection" w/r/t to tags is an obvious first question when you're initially exposed to Ansible tags. It should have a more flexible answer, or at least a nod in the docs.
I would suggest a different way of organizing the versatile iptables role. First, consider not having the role if it's wrapping a very sparse amount of tasks. I would recommend for roles to have meaning to you, and not be module-adapters. So maybe the sql role can handle sql-specific rules in a separate tasks file.
Otherwise, a role parameter which can then be used to load variables dynamically (e.g. the list of firewall rules). Here's what that would look like, stubbed out:
Playbook:
---
- hosts: loc
roles:
- { role: does-too-much, focus_on: 'specific-kind' }
Role tasks/main.yml:
---
- include_vars: "{{ focus_on }}.yml"
- debug:
msg: "ok - {{ item }}"
with_items: stuff
Variables vars/specific-kind.yml:
---
stuff:
- b
- c