Ansible PLaybook: Escape '$' in Linux path - ansible

I have a path which looks like this -
base_dir/123/path/to/G\$/subdirectory/html/
When I try to set this path in Ansible playbook, it throws error. If add \$ to escape '\', it throws unexpected failure error.
Playbkook -
- hosts: localhost
vars:
account_id: 123
tasks:
- name: Add \ to path
debug:
var: "base_dir/{{ account_id }}/path/to/G\\$/subdirectory/html/"
Result -
TASK [Gathering Facts] *************************************************************************************************************************************************
task path: /playbooks/example_path.yml:2
ok: [localhost]
META: ran handlers
TASK [Add \ to path] ***************************************************************************************************************************************************
task path: /playbooks/exmaple_path.yml:6
fatal: [localhost]: FAILED! => {
"msg": "Unexpected failure during module execution."
}
PLAY RECAP *************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=1

As explained in the debug module documentation, the var option is expecting a variable name, not a scalar for output. You are getting an error because \ is not expected in a variable name. Running the playbook with -vvv will give you a little more explanations.
In this case you need to use the msg option.
- hosts: localhost
gather_facts: false
vars:
account_id: 123
tasks:
- name: Add \ to path
debug:
msg: "base_dir/{{ account_id }}/path/to/G\\$/subdirectory/html/"
Result
PLAY [localhost] ***************************************************************
TASK [Add \ to path] ***********************************************************
ok: [localhost] => {
"msg": "base_dir/123/path/to/G\\$/subdirectory/html/"
}
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

The next option is to use the Single-Quoted Style. See the example below
- hosts: localhost
vars:
my_dir1: "/scratch/tmp/G1\\$"
my_dir2: '/scratch/tmp/G2\$'
tasks:
- file:
state: directory
path: "{{ item }}"
loop:
- "{{ my_dir1 }}"
- "{{ my_dir2 }}"
# ls -1 /scratch/tmp/
'G1\$'
'G2\$'

Related

Ansible - Compare dictionaries works but will not accept an addition

I am trying to compare two dictionaries and create a 3rd dictionary if an item has changed or is not present. I have this playbook
---
- hosts: localhost
connection: local
gather_facts: no
vars:
host_list1:
host1: 1.1.1.1
host2: 2.2.2.2
host3: 3.3.3.3
host_list2:
host1: 1.1.1.1
host2: 2.2.2.2
host3: 3.3.3.3
tasks:
- name: Define Dict
set_fact:
diff_list: {}
- name: Compare lists
set_fact:
diff_list: "{{ diff_list|combine({item: host_list1[item]}) }}"
loop: "{{ host_list1.keys()|list }}"
when: host_list1[item] != host_list2[item]
- name: Display Results
debug:
msg: "{{ diff_list }}"
If I change the IP in host_list1 it has the desired result and will update the diff_list.
PLAY [localhost] **************************************************************************************************************************************************************
TASK [Define Dict] ************************************************************************************************************************************************************
ok: [localhost]
TASK [Compare lists] **********************************************************************************************************************************************************
ok: [localhost] => (item=host3)
ok: [localhost] => (item=host2)
skipping: [localhost] => (item=host1)
TASK [Display Results] ********************************************************************************************************************************************************
ok: [localhost] => {
"msg": {
"host2": "2.2.2.5",
"host3": "3.3.3.4"
}
}
PLAY RECAP ********************************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
However if I try and add another host into the host_list1 dictionary I get the following error
PLAY [localhost] **************************************************************************************************************************************************************
TASK [Define Dict] ************************************************************************************************************************************************************
ok: [localhost]
TASK [Compare lists] **********************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'host_list1[item] != host_list2[item]' failed. The error was: error while evaluating conditional (host_list1[item] != host_list2[item]): 'dict object' has no attribute u'host4'\n\nThe error appears to be in '/home/playbooks/test.yml': line 20, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Compare lists\n ^ here\n"}
PLAY RECAP ********************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
I have tried updating the when statement
when: host_list1[item] != host_list2[item] or not defined
However this does not work and I am unable to get the new host appended to the diff_list dictionary
The problem is your conditional statement:
when: host_list1[item] != host_list2[item]
If item is key that is present in only host_list1, then host_list2[item] is an error. There are (at least!) two ways of fixing this.
Use a default value
You can use the default filter to provide a default value when the result of an item lookup is undefined:
when: host_list1[item] != host_list2[item]|default(none)
Explicitly check for membership
You can check that the key exists in host_list2 before attempting to get its value:
when: item not in host_list2 or host_list1[item] != host_list2[item]
You can get your result using a single jinja2 expression without using any tasks.
The following playbook:
---
- hosts: localhost
connection: local
gather_facts: no
vars:
hosts_current:
host1: 1.1.1.1
host2: 2.2.2.3
host3: 3.3.3.4
host4: 5.5.5.5
hosts_origin:
host1: 1.1.1.1
host2: 2.2.2.2
host3: 3.3.3.3
diff_dict: >-
{{
hosts_origin | dict2items
| symmetric_difference(hosts_current | dict2items)
| items2dict
}}
tasks:
- name: Show the calculated var
debug:
var: diff_dict
gives:
PLAY [localhost] **************************************************************************************************************************************************************************************************************
TASK [Show the calculated var] ************************************************************************************************************************************************************************************************
ok: [localhost] => {
"diff_dict": {
"host2": "2.2.2.3",
"host3": "3.3.3.4",
"host4": "5.5.5.5"
}
}
PLAY RECAP ********************************************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Fetch hosts without domain from inventory file

I have following inventory file
$ cat hosts
[web]
server1.example.com
server2.example.com
I would like to fetch the hostname, without the part of domain (.example.com).
I tried with the following playbook, however, it is still fetching with the entire hostname..
$ playbook.yaml
- hosts: localhost
tasks:
- debug:
msg: "{{ groups['web'] }}"
Output
PLAY [localhost] *************************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************************
ok: [localhost]
TASK [debug] *****************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"server1.example.com"
"server2.example.com"
]
}
PLAY RECAP *******************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Expected output
PLAY [localhost] *************************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************************
ok: [localhost]
TASK [debug] *****************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"server1"
"server2"
]
}
PLAY RECAP *******************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You can get what you want from a magic variable called inventory_hostname_short which basically returns anything before the first . found in the inventory_hostname.
To get this in a normal play host loop, it's as easy as:
- hosts: all
tasks:
- name: show target short name
debug:
var: inventory_hostname_short
If you need to get that for hosts not in the host loop, you will have to go through hostvars. Here is an example to get all those names in a list for a given group running from localhost:
- hosts: localhost
gather_facts: false
tasks:
- name: show list of shortnames for group 'toto'
debug:
msg: "{{ groups['toto'] | map('extract', hostvars, 'inventory_hostname_short') }}"
An other example to get that name only for the first server in group 'toto'
- hosts: localhost
gather_facts: false
tasks:
- name: show shortnames for first server in group 'toto'
vars:
server_name: "{{ groups['toto'][0] }}"
debug:
msg: "{{ hostvars[server_name].inventory_hostname_short }}"

Ansible hosts to be set to a substring of a passed variable

I have a play like this:
- name: Perform an action on a Runtime
hosts: all
roles:
- role: mule_action_on_Runtime
A variable at invocation (--extra-vars 'mule_runtime=MuleS01-3.7.3-Testing') has a prefix of the host needed (MuleS01). I want to set hosts: MuleS01. How do I do this?
Given that your pattern is always PartIWant-PartIDonCareAbout-AnotherPartAfterOtherDash you could use the split method of Python, then get the first item of the list via the Jinja filter first.
Here is full working playbook as example:
- hosts: local
gather_facts: no
tasks:
- debug:
msg: "{{ mule_runtime.split('-') | first }}"
This yield the recap:
play.yml --extra-vars 'mule_runtime=MuleS01-3.7.3-Testing'
PLAY [local] *******************************************************************
TASK [debug] *******************************************************************
ok: [local] => {
"msg": "MuleS01"
}
PLAY RECAP *********************************************************************
local : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
With the inventory
shell> cat hosts
MuleS01
MuleS02
MuleS03
this playbook
shell> cat pb.yml
- hosts: all
tasks:
- debug:
msg: Set {{ mule_runtime }}
when: mule_runtime.split('-').0 == inventory_hostname
gives
skipping: [MuleS02]
ok: [MuleS01] => {
"msg": "Set MuleS01-3.7.3-Testing"
}
skipping: [MuleS03]

Ansbile get the substring from task output

I have this URL string server https://test.example.com:6443. I need to extract only hostname test from it using Ansible task.
came up with this playbook, Is there a better way of doing this with-out using sed?
- hosts: localhost
connection: local
gather_facts: no
tasks:
- name: get the URL
shell: echo 'server https://test.example.com:6443' |sed -e 's/^.*https...//' -e 's/\..*$//'
register: result
- name: Print the var
debug:
msg: "{{ result.stdout }}"
Output
PLAY [localhost] *********************************************************************************************************************
TASK [get the URL] *******************************************************************************************************************
changed: [localhost]
TASK [Print the var] *****************************************************************************************************************
ok: [localhost] => {
"msg": "test"
}
PLAY RECAP ***************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You can use split on the URL name and get the desired value, Ideally hostname should be test.example.com in your case. However, you can customize the split function based on your need also as below.
- hosts: localhost
connection: local
gather_facts: no
vars:
url: "https://test.example.com:6443"
tasks:
- name: Print the hostname var
debug:
msg: "{{ url.split(':')[1].split('//')[1] }}"
- name: Print the subdomain prefix
debug:
msg: "{{ url.split(':')[1].split('//')[1].split('.')[0] }}"

Need to use host variables in Ansible (ansible engine 2.8 & ansible tower 3.5)

Need your help in achieving below:
- use variables provided inline with hostIP (i.e. host variables) in Ansible inventory
my inventory:
[ora_patch]
10.24.29.14 SID=orcl,orcl2
my playbook:
---
- hosts: [ora_patch]
tasks:
- debug:
var: "{{ hostvars[ansible_host]['SID'] }}"
Output ** I GET **:
PLAY [ora_patch] ************************************************************
TASK [patch_ora_si_122 : debug] *****************************************
ok: [10.24.29.14] => {
"orcl,orcl2": "(Undefined, Undefined)"
}
PLAY RECAP ******************************************************************
10.24.29.14 : ok=1 changed=0 unreachable=0 failed=0
Output ** I want ** :
PLAY [ora_patch] ***********************************************************
TASK [patch_ora_si_122 : debug] ****************************************
ok: [10.24.29.14] => {
"SID": "orcl,orcl2"
}
PLAY RECAP *****************************************************************
10.24.29.14 : ok=1 changed=0 unreachable=0 failed=0
Command I execute:
ansible-playbook -i inventory patch_ora_si_122.yml
Your playbook is slightly wrong. You are trying to use the content of the hostvar "{{ hostvars[ansible_host]['SID'] }}" as a variable name to display with debug: var=....
Simply change your playbook to
---
- hosts: ora_patch
tasks:
- debug:
msg: "SID: {{ hostvars[ansible_host]['SID'] }}"
or you could also use the variable name directly:
---
- hosts: ora_patch
tasks:
- debug:
var: SID
Ansible inventory.ini follows beloe format.
[hosts]
[hosts:vars]
The below should work:
[ora_patch]
10.24.29.14 SID=orcl,orcl2
[ora_patch:vars]
SID=orcl,orcl2

Resources