Automatically include environment variables in an Ansible playbook - ansible

I have an Ansible playbook that performs various tasks based on environment variables that have been set on the system running Ansible. For example:
- hosts: all
tasks:
- name: Download allowlist
command: "some_command {{ lookup('env', 'ALLOWLIST_URL') }}"
when: "lookup('env', 'ALLOWLIST_URL') is defined"
Currently, I provide all the environment variables from outside the playbook, through a wrapper script:
export ALLOWLIST_URL="..."
export SOME_OTHER_VAR="..."
ansible-playbook -i hosts playbook.yaml
However, I'd like to be able to include these environment variables automatically into Ansible, either through a command line switch, an additional task in the playbook, or another means, so that I can get rid of the wrapper entirely.
To clarify, I'd prefer a way of doing something like this (this is not a real command and only intended to demonstrate what I'm looking for):
ansible-playbook --include-env-vars ENVFILE -i hosts playbook.yml
Or, if it's within the playbook, something like this (again, include_env_vars is not a real module and only intended as a demonstration):
tasks:
- name: Include env vars
include_env_vars:
from: ENVFILE
Is such a thing possible?

Related

Executing playbooks in groupings created in hosts.yaml file

Ansible Version: 2.8.3
I have the following hosts.yaml file for use in Ansible
I have applications that I want to deploy on potentially both rp_1 and rp_2
---
all:
vars:
docker_network_name: devopsNet
http_protocol: http
http_host: ansiblenode01_new.example.com
http_url: "{{ http_protocol }}://{{ http_host }}:{{ http_port }}/{{ http_context }}"
hosts:
ansiblenode01_new.example.com:
ansiblenode02_new.example.com:
children:
##################################################################
rp_1:
children:
httpd:
hosts:
ansiblenode01_new.example.com:
vars:
number_of_tools: 6
outside_port: 443
jenkins:
hosts:
ansiblenode01_new.example.com:
vars:
http_port: 4444
http_context: jenkins
artifactory:
hosts:
ansiblenode01_new.example.com:
vars:
http_port: 8000
http_context: artifactory
rp_2:
children:
httpd:
hosts:
ansiblenode02_new.example.com:
vars:
number_of_tools: 4
outside_port: 7090
jenkins:
hosts:
ansiblenode02_new.example.com:
vars:
http_port: 7990
http_context: jenkins
artifactory:
hosts:
ansiblenode02_new.example.com:
vars:
http_port: 8000
http_context: artifactory
The following python wrapper script is calling ansible-playbook in a loop to deploy the applications
#!/usr/bin/python
import yaml
import os
import getpass
with open('hosts.yaml') as f:
var = yaml.load(f)
sudo_pass = getpass.getpass(prompt="Please enter sudo password: ")
# Running individual ansible-playbook deployment for each application listed and uncommented under 'applications' object.
for network in var['all']['children']:
for app in var['all']['children'][network]['children']:
os.system('ansible-playbook deploy.yml --extra-vars "application='+app+' ansible_sudo_password='+sudo_pass+'"')
The problem I recognize is that both Ansible and Python will use the hosts.yaml file, but not use it the way I thought it would as I'm not too familiar with Ansible.
The hosts.yaml was written in a format that is required by Ansible.
The Python script will open the yaml file, make a dictionary out of it, and step through the dictionary and look for the application names to pass to the command line call. The problem is then that Python only passes the name of the app as a string to the invocation of ansible-playbook, the dictionary structure obviously doesn't get passed, so Ansible will then open the hosts.yaml file as well, but all it does is step through the yaml and look for the first occurrence of the app name that was passed as an argument when ansible-playbook was invoked, completely disregarding the structure I've created in the yaml file.
So basically only the rp_1 group in the yaml file will be executed since Ansible, I think reads through the yaml from top down and stops at the first occurrence, therefore all or parts of the rp_2 group will never be processed by Ansible if the group contains all or some of the same apps as rp_1, therefore running the same deployment twice.
Is there a way to invoke Ansible or some ways to set the playbooks up so that Ansible will recognize that in my hosts file, I have networks (rp_1, rp_2) that I want to setup and executes the playbooks in the grouping that I've created in the yaml file?
Ansible already has this built-in. You do not need a wrapper script.
To run the deploy.yml playbook on all hosts in your hosts.yaml (this is called "inventory" btw.) do this:
ansible-playbook -i hosts.yaml deploy.yml -bK
To only run it on rp_1, do this:
ansible-playbook -i hosts.yaml deploy.yml --limit rp_1 -bK
-b makes ansible become root
-K will make ansible ask for the password to become root
-i <file> specifies the inventory file
--limit <host/group> limits the execution to certain hosts or groups, you can also add more than one, as a comma-separated list (e.g., pr_1,rp_2)
You can also specify a list of hosts/groups in your playbook like this:
- name: do whatever you like
hosts:
- rp_1
- rp_2
become: yes
tasks:
- debug:
msg: "I'm running on {{ inventory_hostname }}!"
Further reading:
Discovering variables: facts and magic variables
How to build your inventory
Special variables
Using variables
Ansible examples
Accessing variables of "other" hosts: on serverfault and stackoverflow

Is there a way to reference group variables when importing in Ansible?

In my Ansible scripts, is there a way to reference a path variable when importing a playbook?
I have set up some variables with the path to different files in my Ansible file hierarchy that I would like to reference when importing and including playbook and variable files. The path variables are defined in a file in the group_vars/all/ directory so they are loaded automatically.
When I try to import a playbook and reference one of my path variables, I get an error that the variable is not defined.
Here's an example. I created a simple playbook file that I call include.yml:
---
- name: Include playbook
import_playbook: "{{ base_dir }}/foo.yml"
The playbook imports another playbook called foo.yml in a directory defined in the variable, base_dir.
Here is foo.yml:
---
- name:
hosts: localhost
gather_facts: no
tasks:
- name: Check that group_vars/all variable loaded
debug:
var: test_dir
In the group_vars/all/ directory, I define base_dir and test_dir in a file called dirs.yml:
base_dir: "{{ playbook_dir }}"
test_dir: "{{ base_dir }}/foo"
When I run:
ansible-playbook include.yml
I expect that Ansible will import and run foo.yml, which prints the value of the test_dir variable which references base_dir.
Instead, I get the error:
ERROR! 'base_dir' is undefined
If I run:
ansible-playbook include.yml --extra-vars base_dir="."
then it runs as expected.
It appears that the import occurs before the group_vars variables are loaded.
If true, this is inconvenient because I would like to define my file paths in global variables that can be referenced by multiple playbooks, instead of hardcoding them in all of my playbooks. Is there a way around this issue?
Q: "I would like to define my file paths in global variables that can be referenced by multiple playbooks, instead of hardcoding them in all of my playbooks. Is there a way around this issue?
A: It's a rational expectation that group_vars/all might have been loaded before a playbook is imported. But neither playbook nor inventory related group_vars/all works this way. There are closed issues on this topic (locked and limited conversation to collaborators on Apr 27) for example playbook_vars_root doesn't work for playbook imports #34239.
There is no workaround. The scope of such variables is the play. goup_vars can't be loaded before the hosts is known from the play.
FWIW. An option of running playbooks in a systemic and flexible way is ansible-runner. See Runner Input Directory Hierarchy and Running Playbooks.

dynamic include var files at playbook level [duplicate]

I have created my own custom library, I added my custom library in the common folder of my repository. In that I need to pass variables dynamically. It's a confidential password, so I am using "vault" in ansible.
In that my requirement is how to pass include_vars in the tasks\main.yml before hosts.
e.g: mytasks.yml
- include_vars: sample_vault.yml
- include: sample_tasks.yml
- hosts: localhost
tasks:
name: "free task"
command: ls -a
my directory structure like this:
myfolder
- common
-library
-my file.py
- sample_tasks.yml
- mytasks
-mytasks.yml(my main master playbook file)
-sample_vault.yml (note:i create this using vault for confidential purpose)
- roles
-myrole
Here I need to run sample_tasks file using a variables passed in sample_vault.yml file before I execute the hosts tasks using ansible. If I use extra variable means password is visible so I don't need that.
When I use include_vars in my tasks/main.yml file, it shows the following error:
ERROR! 'include_vars' is not a valid attribute for a Play
You can't use include_vars this way, it's only available for use under tasks.
If sample_tasks.yml is a list of tasks, you also can't use it on playbook level. See my other answer for explanation.
You can use vars_files like this:
- hosts: localhost
vars_files:
- sample_vault.yml
tasks:
name: "free task"
command: ls -a
Or pass a file as extra variables:
ansible-playbook --ask-vault-pass -e #sample_vault.yml myplaybook.yml

ansible playbook on multiple servers with different vars

I'm running an ansible playbook on a list of hosts with a host file:
[consul]
${HOST1} ansible_ssh_host=${HOST1} ansible_ssh_user=devops ansible_ssh_pass=blabla
${HOST2} ansible_ssh_host=${HOST2} ansible_ssh_user=devops ansible_ssh_pass=blabla
.......so on...
The thing is that I need to pass a different variable for each host.
I know of the flag -e that allows me to send a variable with the ansible-playbook command but it's not for each of the hosts.
I'm running the playbook with this:
ansible-playbook -vvvv site.yml
How can I pass a different var for each host?
Thanks!
Note: I'm using ansible 1.7.1
Two ways you should be able to do this:
1) Include the variable in your host file:
[consul]
${HOST1} ansible_ssh_host=${HOST1} .... myvar=x
${HOST2} ansible_ssh_host=${HOST2} .... myvar=y
2) Or use the include_vars task to load a file based on the host name
include_vars: "{{ ansible_ssh_host }}.yml"
The second method is good if you have a lot of variables to load for a host.
For more complex cases the lookups module might help:
http://docs.ansible.com/ansible/playbooks_lookups.html

Ansible: Use variable for defining playbook hosts

I have the following version installed: ansible 2.3.0 (devel 2131eaba0c)
I want to specify my host variable as external variable and then use it in the playbook similar to this:
hosts: "{{integration}}"
In my group_vars/all file I have the following defined variable:
integration: "int60"
The host file looks like this:
[int60]
hostA
[int61]
hostB
Unfortunately this does not work. I also tried to define the host var in the following way:
[integration]
127.0.0.1 ansible_host="{{ integration_env }}"
and have the integration_env specified in my group_vars/all file. In this case it seemed like it ran the tasks locally and not in the desired environment.
Is it possible to do something like this? I'd be open to whole new ways of doing this. The main goal is simply to define the host variable in a var file.
This will work if you pass integration variable as extra variable:
ansible-playbook -e integration=int60 myplaybook.yml
Any variables used in play "header", should be defined before Ansible parses playbook.
In your example you define integration as host facts. Facts are only defined on task level, not play level.
Update: and you can use other ways of passing variables, not only extra vars.
For example:
- hosts: "{{ lookup('env','DYN_HOSTS') }}"
will also work.

Resources