Specifying variables in master Ansible playbook - ansible

I am writing a master Ansible playbook which is including playbooks. Now, I want to set variables that all the playbooks specified within it use. How do I specify variables in this playbook?
I know that one of the options is to include vars_files and use it with each of the playbook. Example: - include: abc.yml
vars_files: vars.yml
I am using Ansible 1.9.3.

First I would really recommend you to update your Ansible to latest version. It is very easy to do so, no reason to stay behind.
Having said that, there are many ways on how to specify variables in your master playbook. All these are more or less the same with any other playbook. Briefly mentioning:
a. Define them in your playbook itself
- hosts: webservers
vars:
http_port: 80
b. Separating into a variable file, as you already said:
- hosts: all
remote_user: root
vars:
favcolor: blue
vars_files:
- /vars/external_vars.yml
vars/external_vars.yml
somevar: somevalue
password: magic
Other possibilities include:
c. Using facts
d. Registering output into variables
Additionally, which may be important for your case:
d. You can pass variables into includes:
tasks:
- include: wordpress.yml wp_user=timmy
- include: wordpress.yml wp_user=alice
- include: wordpress.yml wp_user=bob
e. Passing variables in command line:
ansible-playbook release.yml -k "version=1.23.45 other_variable=foo"
-k is shorthand for --exra-vars.
There might be other ways too that I may be missing at the moment.

Related

Playbook to modify another playbook then run the modified playbook

I'm trying to create a playbook that will first modify another playbook, then run that modified version of the playbook. But import_playbook pre-processes, so the original playbook, not the modified, is run. Is there any way to tell Ansible to re-read this playbook? Note I am changing more that the hosts, but using this simple example.
- name: Change the playbook
hosts: localhost
connection: local
gather_facts: False
tasks:
- name: Change the playbook
lineinfile:
path: "my_playbook.yml"
regexp: "- hosts: some_group_name"
line: "- hosts: some_other_group_name"
- name: Include the playbook that was modified
import_playbook: my_playbook.yml
With proper organized inventory, group_vars, variables, templating and add_host or dynamic inventory, there is no need for self-modifying code (SMC).
Regarding
But import_playbook pre-processes, so the original playbook ...
you may have a look into What's the difference between include_tasks and import_tasks?.
Furthermore, there is no dynamic include_playbook.

Use a variable for remote_user in ansible

I want to parameterize (use a variable) for remote_user in ansible.
This is the first part from the playbook:
- hosts: xxx
remote_user: "centos"
become: true
I will replace it with
- hosts: wazuh
remote_user: "{{ new_user }}"
become: true
But what is a good place to store the value of this variable? It seems group_vars/all mostly contain variables which are more app/env specific than ansible specific. Or should I put it in inventories/hosts as a var? What is the recommended location to store it?
You should actually store it in your inventory as ansible_user either for the all group (for all host), a specific group or a specific host. You can keep a remote_user in your play which will be used in case the ansible_user is not defined for some hosts in your inventory. If you remove it, you local user on the controller will be the default, unless you use the -u flag on the command line.
You can find a good explanation of the difference between ansible_user and remote_user and how the overide works in the documentation on variable precedence
Using a var as you wrote it in your above example can actually work. But since it must be expanded before the play actually starts and any action is taken on any host, the only place you can "store" it is in an extra_var on the command line.
To be a little more practical, here is what I suggest from your above example:
inventories/dev/hosts.yml
---
wazuh:
hosts:
host_a.wazuh.tld:
host.b.wazuh.tld:
inventories/dev/group_vars/wazuh.yml
---
# Vars for the wazuh group
ansible_user: centos
plabook.yml
---
- hosts: wazuh
tasks:
- name: Proove we connected with the given user
cmd: whoami
register: whoami_result
- name: Show actual result
debug:
var: whoami_result.stdout
Launching the playbook:
ansible-playbook -i inventories/dev playbook.yml

Ansible playbook-wide settings and tasks

I have a playbook with this structure:
---
- hosts: foo-servers
roles:
- foo_setup
become: yes
tags: tweaks
- hosts: bar-servers
roles:
- bar_setup
become: yes
tags: tweaks
[a few more server groups with a similar pattern]
I have a somewhat similar feature to deploy in all servers but each server group has it's own small differences, so I need to keep separate roles for each group.
I also want to run just a select group of tasks from each role, the ones tagged 'tweaks', in all hosts.
And all hosts should be run with raised privileges, but that is not true for all playbooks, so I want that setting to apply just to this playbook (no global vars).
I would like to move all the repeated parameters - become: yes and tags: tweaks outside of host: plays where they will be indicated to apply to all roles bellow. Something to the effect of
--
- all_hosts_this_playbook:
become: yes
tags: tweaks
- hosts: foo-servers
roles:
- foo_setup
- hosts: bar-servers
roles:
- bar_setup
I suppose this is possible in the command line. Like ansible-playbook setup_tweaks.yml --tags "tweak" --become? But is there a playbook equivalent? I'd rather have these in the file than in the command line, where I often forget to add stuff.
And looping doesn't work...
ERROR! 'loop' is not a valid attribute for a Play
- name: Make tweaks in many servers
become: yes
tags: tweaks
hosts: "{{ item.host }}"
roles:
- "{{ item.role }}"
loop:
- { host: 'foo-servers', role: 'foo_setup' }
- { host: 'bar-servers', role: 'bar_setup' }
I also want to add post_tasks: to be run in all servers (maybe they also need to be tagged?):
post_tasks_all_hosts:
- name: Upgrade system
apt:
autoremove: yes
autoclean: yes
update_cache: yes
upgrade: dist
tags: tweaks
- name: Reboot
shell: sleep 2 && reboot
async: 3
poll: 0
tags: tweaks
Is it possible to define playbook-wide pre_tasks or post_tasks?
Here Ansible: How to declare global variable within playbook? it is indicated that one 'cannot define a variable accessible on a playbook level', but in my case it's not variables - it's task parameters and post_tasks:.
Maybe the parameters and the 'pre/post tasks' are different problems with different solutions, but I decided to ask in the same place because they both fall on the same category of parameters that I'd like to set for the whole playbook, outside of host: plays.
Q: "I suppose this is possible in the command line. Like ansible-playbook setup_tweaks.yml --tags "tweak" --become? But is there a playbook equivalent?"
A: No. There is no such playbook equivalent.
Isn't this is a misunderstanding of the command-line option --tags
only run plays and tasks tagged with these values
versus
tag inheritance ?
Adding tags: to a play, or to statically imported tasks and roles, adds those tags to all of the contained tasks...When you apply tags: attributes to structures other than tasks, Ansible processes the tag attribute to apply ONLY to the tasks they contain. Applying tags anywhere other than tasks is just a convenience so you don’t have to tag tasks individually.
Details
In the play below tag "tweaks" is added to all of the contained tasks
- hosts: foo-servers
roles:
- foo_setup
tags: tweaks
The command below selects only tasks tagged "tweaks"
ansible-playbook setup_tweaks.yml --tags "tweak"
Q: "Is it possible to define playbook-wide pre_tasks or post_tasks?"
A: No. It's not possible. The scope of pre/post_tasks is the play.

Ansible: How to declare global variable within playbook?

How can I declare global variable within Ansible playbook. I have searched in google and found the below solution, but its not working as expected.
- hosts: all
vars:
prod-servers:
- x.x.x.x
- x.x.x.x
- hosts: "{{prod-servers}}"
tasks:
- name: ping
action: ping
When I'm trying the above code, it says variable prod-servers is undefined.
You cannot define a variable accessible on a playbook level (global variable) from within a play.
Variable Scopes
Ansible has 3 main scopes:
Global: this is set by config, environment variables and the command line
Play: each play and contained structures, vars entries (vars; vars_files; vars_prompt), role defaults and vars.
Host: variables directly associated to a host, like inventory, include_vars, facts or registered task outputs
Anything you declare inside a play can thus only be either a play variable, or a (host) fact.
To define a variable, which you can use in the hosts declaration:
run ansible-playbook with --extra-vars option and pass the value in the argument;
or to achieve the same functionality (decide which hosts to run a play on, from within a preceding play):
define an in-memory inventory and run the subsequent play against that inventory.
what you seem to want is an inventory (http://docs.ansible.com/ansible/latest/intro_inventory.html), it looks like you have an static list of IP's that may be prod servers (or dev, or whatever), therefore you can create an static inventory.
In your second play you want to use the list of IP's as hosts to run the tasks, that's not what Ansible expects. After the "hosts" keyword in a play declaration, Ansible expects a group name from the inventory.
If, on the opossite, your prod servers change from time to time, you may need to create a dynamic inventory. You can have a look at examples in https://github.com/ansible/ansible/tree/devel/contrib/inventory (for instance, there are examples of dynamic inventory based on EC2 from Amazon or vsphere)
regards
well, this can be done using
set_fact.
I don't know the best practice for this but this works for me
Here's my playbook example
- hosts: all
gather_facts: false
tasks:
- set_fact: host='hostname'
- hosts: host-name1
gather_facts: false
tasks:
- name: CheckHostName
shell: "{{ host }}"
register: output
- debug: msg="{{ output }}"
- hosts: host-name2
gather_facts: false
tasks:
- name: CheckHostName
shell: "{{ host }}"
register: output
- debug: msg="{{ output }}"

Ansible: Include playbook according to inventory variable

I am trying to set up Ansible to be able to run a playbook according to what inventory group the host is in. For example, in the inventory, we have:
[group1]
host1.sub.domain.tld ansible_host=10.0.0.2
...
[group1:vars]
whatsmyplaybook=build-server.yml
Then we want to make a simple playbook that will more or less redirect to the playbook that is in the inventory:
---
- name: Load Playbook from inventory
include: "{{hostvars[server].whatsmyplaybook}}"
Where the "server" variable would be the host's FQDN, passed in from the command line:
ansible-playbook whatsmyplaybook.yml -e "server=host1.sub.domain.tld"
Our reasoning for this would be to have a server bootstrap itself from a fresh installation (PXE boot), where it will only really know its FQDN, then have a firstboot script SSH to our Ansible host and kick off the above command. However, when we do this, we get the below error:
ERROR! 'hostvars' is undefined
This suggests that the inventory is not parsed until a host list is provided, which sucks a lot. Is there another way to accomplish this?
A bit strange workflow, honestly.
Your setup doesn't work, because most of variables are not defined during playbook parse time.
You may be more lucky with defining single playbook with different plays for different groups (no need to set group var, just use correct host pattern (group name in my example)) and execute it limiting to specific host:
site.yml:
---
- hosts: group1
tasks:
- include: build-web-server-tasks.yml
- hosts: group2
tasks:
- include: build-db-server-tasks2.yml
command to provision specific server:
ansible-playbook -l host1.sub.domain.tld site.yml
You can develop your own dynamic inventory file so that all machines which needs to be bootstrapped will automatically added into your inventory and group respectively with out an manual entry in to the inventory file.
For developing dynamic inventory you can follow the below link:
http://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html
You can include multiple playbooks targeted to different groups as follows.
---
- hosts: all
tasks:
- include: build-web-server-tasks.yml
where: inventory_hostname in groups['group1']
- include: build-db-server-tasks2.yml
where: inventory_hostname in groups['group2']
inventory_hostname is the name of the hostname as configured in Ansible’s inventory host file. This can be useful for when you don’t want to rely on the discovered hostname ansible_hostname or for other mysterious reasons. If you have a long FQDN, inventory_hostname_short also contains the part up to the first period, without the rest of the domain.

Resources