How can I access templated variables for another host in Ansible? - scope

Background
I am deploying to a system containing multiple hosts along with a monitoring host. The monitoring host needs to use information about the other hosts to configure its monitoring checks. However, variables defined as Jinja templates in host_vars/group_vars do not work when accessed through hostvars on the monitoring host.
Example
inventory.ini
my_host ansible_connection=local
monitoring_host ansible_connection=local
host_vars/my_host
---
my_var: "{{ inventory_hostname }}"
playbook.yml
---
- hosts: my_host
tasks:
- debug: var=my_var
- hosts: monitoring_host
tasks:
- debug: var="hostvars['my_host']['my_var']"
The expectation is that the two debug task will output the same value, "my_host". In Ansible 1.7, the second debug task outputs "{{ inventory_hostname }}" (i.e. the template is not expanded). In Ansible 1.8, the second debug task outputs "monitoring_host" (i.e. the template is expanded in the wrong context).
Is this a known bug? Is there a good workaround?

I'm pretty sure this is buggy behaviour. Possible workaround:
---
- hosts: my_host
tasks:
- debug: var=my_var
- set_fact: my_var="{{ my_var }}" # Expanded in my_host context
- hosts: monitoring_host
tasks:
- debug: var="hostvars['my_host']['my_var']"

Related

How to set distinct variables for different hosts in an external variables yaml to be used in Ansible? variables

I have for example this playbook:
- name: System Configuration
hosts: host1, host2
become: yes
tasks:
- name: Set current app version
shell: export APP_VERSION={{ app_version|quote }}
I wish to set this variables for multiple hosts, for example host and host2. I read somewhere that I can create a yml file with the name of each host and store the variables fort each host there but I cane find how to load this file for each host.
I thought it may be loaded automatically if the name matches the host name but I dont think this happens I get an error FAILED! => {"msg": "The task includes an option with an undefined variable
so how can I define a set for variables for each host separately?
There are many options.
For example, create a dictionary in 'group_vars/all'
shell> cat group_vars/all
app_versions:
host1: '1.1'
host2: '1.2'
default: '1.0'
app_version: "{{ app_versions[inventory_hostname]|
default(app_versions.default) }}"
The playbook
- hosts: host1,host2,host3
tasks:
- debug:
var: app_version
gives
TASK [debug] **********************************************************
ok: [host3] =>
app_version: '1.0'
ok: [host1] =>
app_version: '1.1'
ok: [host2] =>
app_version: '1.2'
The next option is 'vars_files'. Create a YAML file and use it in the playbook. For example, the file and the playbook give the same result
shell> cat app_versions.yml
app_versions:
host1: '1.1'
host2: '1.2'
default: '1.0'
app_version: "{{ app_versions[inventory_hostname]|
default(app_versions.default) }}"
- hosts: host1,host2,host3
vars_files:
- app_versions.yml
tasks:
- debug:
var: app_version
The next option is to create files in host_vars. For example, the 'host_vars' and the playbook give also the same result
shell> cat host_vars/host1.yml
app_version: '1.1'
shell> cat host_vars/host2.yml
app_version: '1.2'
shell> cat host_vars/host3.yml
app_version: '1.0'
- hosts: host1,host2,host3
tasks:
- debug:
var: app_version
The options override each other. See Understanding variable precedence. In the above options, the lowest precedence (4,5) are group_vars/all followed by host_vars precedence (9,10). The highest precedence (14) has the play vars_file.
Putting it all together, you might want to put the defaults to the group_vars/all
shell> cat group_vars/all
app_versions:
default: '1.0'
and override the defaults in host_vars
shell> tree host_vars
host_vars
├── host1.yml
└── host2.yml
shell> cat host_vars/host1.yml
app_version: '1.1'
shell> cat host_vars/host2.yml
app_version: '1.2'
Then, the playbook below gives again the same result
- hosts: host1,host2,host3
tasks:
- set_fact:
app_version: "{{ app_version|
default(app_versions[inventory_hostname])|
default(app_versions.default) }}"
- debug:
var: app_version
Ok there are probably many solutions to this but the one I liked an used is to create a vars sub-directory in my project folder. Ansible look there by default when trying to find variable files for a host with the include_vars module.
So in my tasks I added this task:
tasks:
- name: Load variables for host
include_vars:
file: "{{ inventory_hostname }}.yml"
and in my project in the vars directory I added a host_name_as_in_inventory.yml file with the host-name for each host I want to specify variables for.
Edit: as it is suggested int he other coment if the yml files with the hostnames are added in a directory calles host_vars they are loaded automatically so the include_vars taks is redundant.

Ansible-AWX get file from remote Windows to local linux

Hello to all stack overflow community.
I'm seeking you help because I've been trying to accomplish the task of getting a file from remote Windows to local linux using Ansible-AWX and I can't get it to work. Bellow I shared the playbook and most of tests I've done but none of them worked.
I'm getting latest file in a windows directory and trying to transfer that file to local AWX either inside the docker or in the linux server where AWX is running.
Test_1: Said file was copied but when I go inside the docker nothing there. I can't find an answer and couldn't find any on Google.
Test_2: Didn't work. It says can't authenticate to linux server
Test_3: Task became idle and I have to restart the docker to be able to stop it. It gets crazy. No idea why.
Test_4: It says connection unexpectedly closed.
I didn't want to provide output to reduce noise and because I can't share the information. I removed names and ips from playbook as well.
I'm connecting to Windows server using AD.
Please, I don't know what else to do. Thanks for your help in advance.
---
- name: Get file from Windows to Linux
hosts: all # remote windows server ip
gather_facts: true
become: true
vars:
local_dest_path_test1: \var\lib\awx\public\ # Inside AWX docker
local_dest_path_test2: \\<linux_ip>\home\user_name\temp\ # Outside AWX docker in the linux server
local_dest_path_test3: /var/lib/awx/public/ # Inside AWX docker
# Source file in remote windows server
src_file: C:\temp\
tasks:
# Getting file information to be copied
- name: Get files in a folder
win_find:
paths: "{{ src_file }}"
register: found_files
- name: Get latest file
set_fact:
latest_file: "{{ found_files.files | sort(attribute='creationtime',reverse=true) | first }}"
# Test 1
- name: copy files from Windows to Linux
win_copy:
src: "{{ latest_file.path }}"
dest: "{{ local_dest_path_test1 }}"
remote_src: yes
# Test 2
- name: copy files from Windows to Linux
win_copy:
src: "{{ latest_file.path }}"
dest: "{{ local_dest_path_test2 }}"
remote_src: yes
become: yes
become_method: su
become_flags: logon_type=new_credentials logon_flags=netcredentials_only
vars:
ansible_become_user: <linux_user_name>
ansible_become_pass: <linux_user_password>
ansible_remote_tmp: <linux_remote_path>
# Test 3
- name: Fetch latest file to linux
fetch:
src: "{{ latest_file.path }}"
dest: "{{ local_dest_path_test3 }}"
flat: yes
fail_on_missing: yes
delegate_to: 127.0.0.1
# Test 4
- name: Transfer file from Windows to Linux
synchronize:
src: "{{ latest_file.path }}"
dest: "{{ local_dest_path_test3 }}"
mode: pull
delegate_to: 127.0.0.1

Ansible Azure Dynamic Inventory and Sharing variables between hosts in a single playbook

Problem: referencing a fact about a host ( in this case, the private ip ) from another host in a playbook using a wildcard only seems to work in the "Host" part of a playbook, not inside a task. vm_ubuntu* cannot be used in a task.
In a single playbook, I have a couple of hosts, and because the inventory is dynamic, I don't have the hostname ahead of time as Azure appends an identifier after it has been created.
I am using TF to create.
And using the Azure dynamic inventory method.
I am calling my playbook like this, where myazure_rm.yml is a bog standard azure dynamic inventory method, as of the time of this writing.
ansible-playbook -i ./myazure_rm.yml ./bwaf-playbook.yaml --key-file ~/.ssh/id_rsa --u azureuser
My playbook looks like this ( abbreviated ).
- hosts: vm_ubuntu*
tasks:
- name: housekeeping
set_fact:
vm_ubuntu_private_ip="{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"
#"
- debug: var=vm_ubuntu_private_ip
- hosts: vm_bwaf*
connection: local
vars:
vm_bwaf_private_ip: "{{private_ipv4_addresses | join }}"
vm_bwaf_public_ip: "{{ public_ipv4_addresses | join }}"
vm_ubuntu_private_ip: "{{ hostvars['vm_ubuntu*']['ip'] }}"
api_url: "http://{{ vm_bwaf_public_ip }}:8000/restapi/{{ api_version }}"
#"
I am answering my own question to get rep, and to to help others of course.
I also want to thank the person ( https://stackoverflow.com/users/4281353/mon ) who came up with this first, which appears in here: How do I set register a variable to persist between plays in ansible?
- name: "Save private ip to dummy host"
add_host:
name: "dummy_host"
ip: "{{ vm_ubuntu_private_ip }}"
And then this can be referenced in the other host in the playbook like this:
- hosts: vm_bwaf*
connection: local
vars:
vm_bwaf_private_ip: "{{private_ipv4_addresses | join }}"
vm_bwaf_public_ip: "{{ public_ipv4_addresses | join }}"
vm_ubuntu_private_ip: "{{ hostvars['dummy_host']['ip'] }}"

How do we use encoded value in playbook and decode it whenever needed in ansible playbook?

I am trying to use ansible-pull method for running a playbooks with extra vars on run time of playbooks.
Here is how i needed to run my playbook with vars looks like.
ansible-playbook decode.yml --extra-vars "host_name=xxxxxxx bind_password=xxxxxxxxx swap_disk=xxxxx"
The bind_password will have encoded value of admin password.
and i have tried writing below playbook for it.
I am able to debug every value and getting it correctly but after decoding password not getting exact value or not sure whether i am doing it correct or not?
---
- name: Install and configure AD authentication
hosts: test
become: yes
become_user: root
vars:
hostname: "{{ host_name }}"
diskname: "{{ swap_disk }}"
password: "{{ bind_password }}"
tasks:
- name: Ansible prompt example.
debug:
msg: "{{ bind_password }}"
- name: Ansible prompt example.
debug:
msg: "{{ host_name }}"
- name: Ansible prompt example.
debug:
msg: "{{ swap_disk }}"
- name: Setup the hostname
command: hostnamectl set-hostname --static "{{ host_name }}"
- name: decode passwd
command: export passwd=$(echo "{{ bind_password }}" | base64 --decode)
- name: print decoded password
shell: echo "$passwd"
register: mypasswd
- name: debug decode value
debug:
msg: "{{ mypasswd }}"
but while we can decode base64 value with command:
echo "encodedvalue" | base64 --decode
How can i run this playbook with ansible-pull as well.
later i want to convert this playbook into roles (role1) and then needs to run it as below:
How can we run role based playbook using ansible-pull?
The problem is not b64decoding your value. Your command should not cause any problems and probably gives the expected result if you type it manually in your terminal.
But ansible is creating an ssh connection for each task, therefore each shell/command task starts on a new session. So exporting an env var in one command task and using that env var in the next shell task will never work.
Moreover, why do you want to handle all this with so many command/shell tasks when you have all the needed tools directly in ansible ? Here is a possible rewrite of your last 3 tasks that fits into a single one.
- name: debug decoded value of bind_password
debug:
msg: "{{ bind_password | b64decode }}"

How to set environment variables of remote hosts

I am having problems working with the environment variables of a remote host. For example, when I try {{ lookup('env', 'PATH') }} this returns the path of my guest machine not of the remote host.
How to pick up / change environment variables of the remote host?
my playbook :
---
- name : playbook
hosts : webservers
gather_facts: yes
remote_user: user1
vars:
Path: "{{lookup('ansible_env','PATH')}}"
roles :
- task1
- task2
- task3
that's return the path of my machine not the path of remote host named user1
i'm a beginner in ansible need some help .
thank you in advance.
You can set the PATH for a task or a playbook by using the environment keyword.
environment:
PATH: "{{ ansible_env.PATH }}:/thingy/bin"
SOME: value
The Ansible FAQ mentions this near the top http://docs.ansible.com/ansible/faq.html
So in your case try something like the following:
- name: Set Path for java
environment:
PATH: "$JAVA_HOME/bin:{{ ansible_env.PATH }}"
Setting the environment reference: http://docs.ansible.com/ansible/playbooks_environment.html

Resources