I'm trying to write a ansible task to incorporate the output of below command into /etc/lvm/lvm.conf file:
[root#ansible]# vgs --noheadings -o vg_name
my_vg
rhel_home
rhel_root
The above mentioned values need to be added as below:
volume_list = [ "rhel_root", "rhel_home", "my_vg" ]
In the managed nodes, the above paramater will be as below:
# volume_list = [ "vg1", "vg2/lvol1", "#tag1", "#*" ]
Kindly help me to proceed further as I'm stuck here:
- name: Fetch the Volume group
shell: "vgs --noheadings -o vg_name"
register: vgs
- debug:
msg: "{{ vgs.stdout }}"
- name: Line in file
lineinfile:
path: /tmp/lvm.conf
regex: "volume_list = .*"
line: "volume_list = [ vgs.stdout_lines ]"
It is adding a line as below, without double quotes in the vg name:
volume_list = [ vgs.stdout_lines ]
at the bottom and not replacing the below line:
volume_list = [ "vg1", "vg2/lvol1", "#tag1", "#*" ]
Need assistance to get output as
volume_list = [ "rhel_root", "rhel_home", "my_vg" ]
For your purpose, you need to use the {{ vgs.stdout_lines }} list (not \"vgs.stdout_lines\" string) variable in your lineinfile task.
Like:
line: "volume_list = {{ vgs.stdout_lines | to_json }}"
Though, I noticed that the VG Names returned by command have preceding whitespace like " rhel_root". So it might be a good idea to set_fact another variable which has the unnecessary whitespace trimmed.
- command: vgs --noheadings -o vg_name
register: vgs
- set_fact:
volume_list: "{{ volume_list | default([]) + [ item | trim ] }}"
loop: "{{ vgs.stdout_lines }}"
- lineinfile:
path: /tmp/lvm.conf
regexp: '# volume_list ='
line: 'volume_list = {{ volume_list | to_json }}'
Related
i have an inventory file containing 200 servers and thier respective variables as shown in a sample below:
[myhost1.mrsh.com]
myhost1.mrsh.com ORACLE_HOME=/u/orahome12/middleware/12c_db1 ansible_user=wladmin
[myhost2.mrsh.com]
myhost2.mrsh.com ORACLE_HOME=/u/orahome12/middleware/12c_db1 ansible_user=wladmin
..........
........
i ask the user to enter any hostname which is passed to hostnames variable as below:
ansible-playbook /web/playbooks/automation/applycpupatch/applycpupatch.yml -i /web/playbooks/automation/applycpupatch/applycpupatch.hosts -f 5 -e action=status -e hostnames='myhost1
myhost2' -e patch_file='p33286132_122130_Generic.zip'
if myhost1 is present in the applycpupatch.hosts file i then wish to create a dynamic inventory using add_host having only myhost1 and its variables like ORACLE_HOME
Below is my code:
- name: "Play 1 - Set Destination details"
hosts: all
tasks:
- add_host:
name: "{{ item | upper }}"
groups: dest_nodes
ansible_user: "{{ hostvars[item + '*'].ansible_user }}"
ORACLE_HOME: "{{ hostvars[item + '*'].ORACLE_HOME }}"
when: inventory_hostname | regex_search(item)"
with_items: "{{ hostnames.split() }}"
Unfortunately, i get the error as below:
TASK [add_host] ****************************************************************
Saturday 20 November 2021 19:05:38 -0600 (0:00:00.059) 0:00:23.532 *****
[0;31mfatal: [myhost222.mrsh.com]: FAILED! => {"msg": "The conditional check 'inventory_hostname | regex_search(item)\"' failed. The error was: template error while templating string: unexpected char '\"' at 45. String: {% if inventory_hostname | regex_search(item)\" %} True {% else %} False {% endif %}\n\nThe error appears to be in '/web/playbooks/automation/applycpupatch/applycpupatch.yml': line 36, 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 - add_host:\n ^ here\n"}[0m
I also tried the below but it fails with the error.
ORACLE_HOME: "{{ hostvars['all'][item + '*'].ORACLE_HOME }}"
Thus my dynamic inventory constructed runtime dest_nodes in this example should have ONLY the below.
myhost1.mrsh.com ORACLE_HOME=/u/orahome12/middleware/12c_db1 ansible_user=wladmin
myhost2.mrsh.com ORACLE_HOME=/u/orahome12/middleware/12c_db1 ansible_user=wladmin
i dont understand very well what do you want, but you have lot of errors to fix in your playbook:
1- launch your playbook with -e hostnames='myhost1,myhost2'
2- fix your playbook: you have to test the result of your regex_search, use the variable inventory_hostname and use split(','):
a sample
- name: "Play 1 - Set Destination details"
hosts: all
tasks:
- debug:
msg: "{{ item }} - {{ hostvars[inventory_hostname].ORACLE_HOME }}"
when: (inventory_hostname | regex_search(item)) != ''
with_items: "{{ hostnames.split(',') }}"
I want to lanch a application :
command=/usr/bin/toto --config /var/toto/conf1.json /var/toto/conf2.json /var/toto/conf3.json
the config file are on /var/toto directory
task.yml
- name: Ansible find file
find:
paths: "/var/toto"
register: found_files
- name: print files
debug:
msg: "{{ found_files['files'] | map(attribute='path') | map('regex_replace','^.*/(.*)$','\\1') | list }}"
register: file_name
- name: Create the Jinja2 based template
template:
src: "etc/control/config.conf.j2"
dest: "/etc/control/config.conf"
with_dict: "{{ file_name }}"
config.conf.j2
command=/usr/bin/toto --config {% for item in file_name %} /var/toto/{{ item }} {% endfor %}
but, I have get this on my file
/etc/control/config.conf
command=/usr/bin/toto --config /var/opt/msg /var/opt/failed /var/opt/changed
varfile_name :
"msg": [ "conf1.json", "conf2.json", "conf3.json"
]
You're iterating over the dictionary in file_name, which is a task result. If you were to print that out, you would find that it contains something like:
TASK [debug] *********************************************************************************************************************************************************************************
ok: [localhost] => {
"file_name": {
"changed": false,
"failed": false,
"msg": [
"file1",
"file2",
"file3"
]
}
}
So when you iterate over it using for item in file_name, you're iterating over the top level keys (changed, failed, msg).
But this is all the wrong way to do it. You never use the debug module to create variables; that's what set_fact is for. You want something like:
- name: build list of files
set_fact:
file_name: "{{ found_files['files'] | map(attribute='path') | map('regex_replace','^.*/(.*)$','\\1') | list }}"
- name: Create the Jinja2 based template
template:
src: "config.conf.j2"
dest: "config.conf"
After the set_fact task, the variable file_name will contain a
list of file names.
It looks like you're using that regular expression to get the basename
of the files found in your find task. There's a basename filter
that can do that with less complexity:
- name: print files
set_fact:
file_name: "{{ found_files['files'] | map(attribute='path') | map('basename') | list }}"
- name: Create the Jinja2 based template
template:
src: "config.conf.j2"
dest: "config.conf"
Here's the playbook I'm using to test this locally:
- hosts: localhost
gather_facts: true
tasks:
- name: find files
find:
paths: /tmp/example
register: found_files
- name: print files
set_fact:
file_name: "{{ found_files['files'] | map(attribute='path') | map('basename') | list }}"
- name: Create the Jinja2 based template
template:
src: "config.conf.j2"
dest: "config.conf"
Before running this, I run:
mkdir /tmp/example
touch /tmp/exampe/file{1,2,3}
This produces a config.conf file that looks like:
command=/usr/bin/toto --config /var/toto/file3 /var/toto/file2 /var/toto/file1
I have a two main variable with subvariables. The main variable VELABx and VELABy match the ansible_hostnames. Following an example of the variables mentioned:
VELABx
location: "text1.1"
initialism: "text1.2"
VELABy
location: "text2.1"
initialism: "text2.2"
Now I'd like to run a task which replaces a regexp with the location variable based on the current ansible_hostname. So, I tried this code, but it leads into an error.
- name: Replace location for VELABx
replace:
dest: "/path/to/file"
regexp: 'location'
replace: "{{ {{ansible_hostname}}.location }}"
remote_user: rssuser
become: no
when: ansible_hostname == "VELABx"
What am I doing wrong? How can I solve this? Can anyone bring up a solution?
Things are always easier when you manage to create a proper structure of data. For example, given the dictionaries in a file
shell> cat velab.yml
VELABx:
location: "text1.1"
initialism: "text1.2"
VELABy:
location: "text2.1"
initialism: "text2.2"
you can include the data from the file into a dictionary, e.g.
- hosts: VELABx,VELABy,VELABz
tasks:
- include_vars:
file: velab.yml
name: velab
run_once: true
- debug:
var: velab
run_once: true
gives
velab:
VELABx:
initialism: text1.2
location: text1.1
VELABy:
initialism: text2.2
location: text2.1
The data you provided in the question are not YAML dictionaries. The colon is missing behind the keys. Either fix it, if you can or parse the file. Anyway, create the dictionary whatever is the source.
Then, given the files
shell> ssh admin#10.1.0.61 cat /tmp/velab.txt
location
shell> ssh admin#10.1.0.62 cat /tmp/velab.txt
location
shell> ssh admin#10.1.0.63 cat /tmp/velab.txt
location
the task to replace the location is simple
- name: Replace location for VELAB*
replace:
dest: /tmp/velab.txt
regexp: location
replace: "{{ velab[inventory_hostname]['location'] }}"
when: velab[inventory_hostname] is defined
gives
shell> ansible-playbook playbook.yml -CD
PLAY [VELABx,VELABy,VELABz] ******************************************
...
TASK [Replace location for VELAB*] ***********************************
skipping: [VELABz]
--- before: /tmp/velab.txt
+++ after: /tmp/velab.txt
## -1 +1 ##
-location
+text1.1
changed: [VELABx]
--- before: /tmp/velab.txt
+++ after: /tmp/velab.txt
## -1 +1 ##
-location
+text2.1
changed: [VELABy]
The next option is to remove the condition and use the default value, instead of skipping the host, when the host is missing in the dictionary
- name: Replace location for VELAB*
replace:
dest: /tmp/velab.txt
regexp: location
replace: "{{ velab[inventory_hostname]['location']|
default(default_location) }}"
vars:
default_location: "text99.1"
you must use loopkup, {{}} inside other {{}} is incorrect
---
- hosts: localhost
gather_facts: false
vars:
ansible_hostname: VELABx
VELABx:
location: "text1.1"
initialism: "text1.2"
VELABy:
location: "text2.1"
initialism: "text2.2"
tasks:
- name: DEBUG
debug:
msg: "{{ lookup('vars', ansible_hostname ).location }}"
- name: Replace location for VELABx
replace:
dest: "/path/to/file"
regexp: 'location'
replace: "{{ lookup('vars', ansible_hostname ).location }}"
when: ansible_hostname == "VELABx"
Hoping someone can help me figure out what I feel should be a simple nested string problem. I have the following tasks to randomly choose a string, save it to a variable and print it:
tasks:
- name: Debug Section 1
debug:
msg: "{{ item }}"
with_random_choice:
- MY_CHOICE1
- MY_CHOICE2
register: choice
- name: Set result to a fact
set_fact:
THE_CHOICE: "{{ choice.results }}"
- name: Debug Section 3
debug:
msg: "{{ THE_CHOICE }}"
The results return with:
PLAY [Testing variable] **********************************************************************************************************************************************************************************************************************
TASK [Debug Section 1] ***********************************************************************************************************************************************************************************************************************ok: [localhost] => (item=MY_CHOICE1) => {
"msg": "MY_CHOICE1"
}
TASK [Set result to a fact] ******************************************************************************************************************************************************************************************************************ok: [localhost]
TASK [Debug Section 3] ***********************************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": [
{
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"item": "MY_CHOICE1",
"msg": "MY_CHOICE1"
}
]
}
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
I would like the variable THE_CHOICE to just return the item, but I can't seem to get it to work. In the set_fact section I've tried the following:
THE_CHOICE: "{{ choice.results['item'] }}"
THE_CHOICE: "{{ choice.results.item }}"
THE_CHOICE: "{{ choice['results']['item'] }}"
All attempts result in something to the effect of this:
"The task includes an option with an undefined variable. The error was: 'list object' has no attribute 'item'
Could anybody provide some insight into what I'm missing?
It would be simpler to use the random filter (since Ansible 1.6):
vars:
choices:
- MY_CHOICE1
- MY_CHOICE2
tasks:
- name: Set fact random
set_fact:
THE_CHOICE: "{{ choices | random }}"
About your original playbook, choice.results is a list, containing one result for each item of the loop. In your case, it only contains one result, because the with_random_choice loop only iterates once. So, in order to access your item, you must select the first result of the list with [0]:
- name: Set result to a fact
set_fact:
THE_CHOICE: "{{ choice.results[0].item }}"
I have included the below variable file in my playbook:
more vars/was_vars.yaml
::::::::::::::
10.9.12.112: "/was/IBM/WebSphere"
10.8.10.28: "/was/IBM/profiles"
10.7.120.129: "/app/tmp"
Here is my playbook:
- name: Configure nodes
hosts: dest_nodes
user: "{{ USER }}"
tasks:
- name: Construct File Path on "{{ inventory_hostname }}".
command: "touch {{ BASEPATH }}/{{ ( item | splitext)[1] }}/del.tmp"
when: "{{ Layer == 'APP' }}"
file: path="{{ "{{ inventory_hostname }}" }}/{{ App_List }}/{{ Rel_Path }}/del.tmp state=directory mode=u=rwx,g=rw,o=r"
when: "{{ Layer == 'WAS' }}"
"{{ inventory_hostname }}" gets substituted with "10.9.12.112" which should then get further substituted to "/was/IBM/WebSphere" as stated in the included vars("was_vars.yaml") file.
I'm getting the below Syntax error with my current code:
ERROR! conflicting action statements: command, file
The error appears to be in '/app/Ansible/deploy.yml': line 133, column 4, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
tasks:
- name: Construct File Path on "{{ inventory_hostname }}".
^ here
We could be wrong, but this one looks like it might be an issue with
missing quotes. Always quote template expression brackets when they
start a value. For instance:
with_items:
- {{ foo }}
Should be written as:
with_items:
- "{{ foo }}"
I'm on the latest version on ansible.
Can you please suggest?
1) The dash is missing in front of the file module.
2) Nested expansion is not possible (wrong: "{{ "{{ inventory_hostname }}" }}").
3) when: condition is expanded by default.
4) The whole string shall be quoted when the expansion of a variable is included.
5) The index of the expansion {{ ( item | splitext)[1] }} wont work.
6) It's not clear where do the variable item and the filter splitext come from.
The correct syntax might be
tasks:
- name: "Construct File Path on {{ inventory_hostname }}."
command: "touch {{ BASEPATH }}/{{ item|splitext|first }}/del.tmp"
when: Layer == 'APP'
- file:
path: "{{ inventory_hostname }}/{{ App_List }}/{{ Rel_Path }}/del.tmp"
state: directory
mode: "u=rwx,g=rw,o=r"
when: Layer == 'WAS'
(not tested)
Thank you for the inputs but what we are actually looking for is how to get the expansion to work...
I.e the inventory_hostname would be substituted with host ip say 10.9.12.112 ... But how do we code to get "/was/IBM/WebSphere" substituted matching the IP from the included variable file?
Can you try as :
"{{vars[inventory_hostname]}}"
or if you want one more level use as :
"{{vars[vars[inventory_hostname]]}}"