Remove first line in 'stdout_lines' - automation

I'm just a beginner and write some small playbook.
For now I get some little error.
- name: Facts
ios_command:
commands: show interface status
register: ios_comm_result
In this playbook, for beginner I get the list of interfaces and then in next task I get list with first position including column name.
- name: get a list of ports to modify
set_fact:
newlist: "{{ (newlist | default([])) + [item.split()[0]] }}"
with_items: "{{ ios_comm_result.stdout_lines }}"
Output:
'Port'
'fa0/1'
'gi0/2'
....
etc
How can I delete first line? Or where can I read about this?

Based on your requirement and the given comments about Accessing list elements with Slice notation ([1:]) and Jinja Filters (| reject()) I've setup an short test
---
- hosts: localhost
become: false
gather_facts: false
vars:
STDOUT_LINES: ['Port', 'fa0/1', 'gi0/2', 'etc/3']
tasks:
# Slice notation
- name: Show 'stdout_lines' from the 2nd line to the end
debug:
msg: "{{ item }}"
loop: "{{ STDOUT_LINES[1:] }}"
# Jinja2 filter
- name: Show 'stdout_lines' and drop any lines which match
debug:
msg: "{{ item }}"
loop: "{{ STDOUT_LINES | reject('match', '^Port') | list }}"
# Conditionals
- name: Show 'stdout_lines' but not the first one
debug:
msg: "{{ item }}"
when: ansible_loop.index != 1
loop: "{{ STDOUT_LINES }}"
loop_control:
extended: true
label: "{{ ansible_loop.index0 }}"
with some value added about Extended loop variables and using conditionals in loops.
All three options show the expected result.

Related

Retrieve variable values from var file in ansible playbook

Need some help to retrieve child values from var file.
Below is my var file
api_user: root
api_password: !vault |
$ANSIBLE_VAULT;1.2;AES256;isi33835326238346338613761366531376662613865376263656262
6138
Huston:
onefs_host: 10.88.55.00
Phoenix:
onefs_host: 10.76.52.01
Below is my playbook
---
- name: isi_increase
hosts: localhost
connection: local
vars_files:
- isilonvars.yml
tasks:
- name: Print
debug:
msg:
- "{{ Huston.onefs_host }}"
- "{{ api_user }}"
- "{{ api_password }}"
This code works perfectly
TASK [Print] ********************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"10.88.55.00",
"root",
"Sh00tm3!"
]
}
But as per my requirement i have to retrieve onefs_host IP as per location in my playbook. I am using extra vars here -e "location=Huston"
- name: Print
debug:
msg:
# - "{{ wcc.onefs_host }}"
- "{{ {{location}}.onefs_host }}"
- "{{ api_user }}"
- "{{ api_password }}"
I am getting the below error.
fatal: [localhost]: FAILED! => {"msg": "template error while templating string: expected token ':', got '}'. String: {{ {{isilon_location}}.onefs_host }}"}
Can you try this way
- name: Print
debug:
msg:
- "{{ vars[location]['onefs_host'] }}"
- "{{ api_user }}"
- "{{ api_password }}"

add variables from Ansible inventory file to a dynamic inventory

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(',') }}"

Syntax error for nested variable in Ansible

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]]}}"

Iterating over variables in Ansible

I'm trying to use the same set of variables for the various modules in my play (with some slight variations as you will see).
It seemed logical to include them as 'vars' at the top of my play, but i then have trouble referring to them later on. So far i've done this :
- name: destruction instance sur GCP
hosts: localhost
gather_facts: no
vars:
gcp_project: ansible-test-248409
gcp_cred_kind: serviceaccount
gcp_cred_file: /google/service-accounts/ansible-test-248409-fbadc808948d.json
zone: europe-west1-b
region: europe-west1
machine_type: n1-standard-1
machines:
- webserver-1
- webserver-2
- webserver-3
- devops-1
- devops-2
tasks:
- name: destruction des machines
gcp_compute_instance:
name: "{{ machines }}"
state: absent
zone: "{{ zone }}"
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/compute
- name: destruction des disques
gcp_compute_disk:
name: "{{ machines }}-disk"
state: absent
zone: "{{ zone }}"
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/compute
Which gives me this error message
[WARNING]: The value ['webserver-1', 'webserver-2', 'webserver-3', 'devops-1', 'devops-2'] (type list) in a string field was
converted to u"['webserver-1', 'webserver-2', 'webserver-3', 'devops-1', 'devops-2']" (type string). If this does not look like what
you expect, quote the entire value to ensure it does not change.
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Invalid JSON response with error: <HTML>\n<HEAD>\n<TITLE>Bad Request</TITLE
>\n</HEAD>\n<BODY BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\">\n<H1>Bad Request</H1>\n<H2>Error 400</H2>\n</BODY>\n</HTML>\n"}
Using 'lookup' or 'query' doesn't work either. Can anyone see what i'm missing ?
you use with_items: option.
tasks:
- name: destruction des machines
gcp_compute_instance:
name: "{{ item }}"
state: absent
zone: "{{ zone }}"
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/compute
with_items: "{{ machines }}"

In an Ansible playbook, what is a better way to iterate over a list of objects and call a different role depending on that object's data?

I am using Ansible to read in a YAML file containing a list of dictionaries. I then need to iterate through this list and call a different role depending on data within each list object. I have a solution that is working, but it seems so kludgy to me, that I wanted to find out if there was a better way.
I have defined a YAML file structure to provide the input to my playbook and I read that file into a variable with the include_vars module. I then use with_items to loop through the array one time for each role that I need to support (currently 6, but it may increase) and use a when clause to only include_role when the data in the object is correct for that role.
Code
Sample Input file:
---
objects:
- type: type1
name: obj_type1
- type: type2
name: obj_type2
- type: type3
name: obj_type3
Sample Playbook:
---
- hosts: cf-host
gather_facts: False
vars:
objects_file: ''
tasks:
- name: Read objects_file
include_vars:
file: "{{ objects_file }}"
- name: Handle type1
include_role:
name: type1_role
vars:
- type1_role_name: "{{ item.name }}"
with_items: "{{ objects }}"
when: item.type == "type1"
- name: Handle type2
include_role:
name: type2_role
vars:
- type2_role_name: "{{ item.name }}"
with_items: "{{ objects }}"
when: item.type == "type2"
- name: Handle type3
include_role:
name: type3_role
vars:
- type3_role_name: "{{ item.name }}"
with_items: "{{ objects }}"
when: item.type == "type3"
Sample Role:
---
- name: Print name
debug:
msg: "Type 1 - Name is {{ type1_role_name }}"
The other roles are the same, but have msg set to "Type X - Name is {{ typeX_role_name }}" instead.
This leads to a skipped task for every item in the list when it does not match the type corresponding to the role. It also means that I have to loop through the same list multiple times (as many as types that I need to support). As mentioned, I already need to support 6 different types and that number may grow.
This solution seems like it would scale very poorly and would have terrible performance as the list and supported types become larger and larger. Is there a better way to do what I need to do?
Better Solution
Using this answer: https://stackoverflow.com/a/53859851/9744341 as a base, I was able to come up with this as a better solution that I am happy with. Here it is in case anyone else has the same needs:
Sample Playbook:
---
- hosts: cf-host
gather_facts: False
vars:
objects_file: ''
role_name_lookup:
type1:
role_name: type1_role
tasks_from: type1_tasks
type2:
role_name: type2_role
tasks_from: type2_tasks
type3:
role_name: type3_role
tasks_from: main
tasks:
- name: Read objects_file
include_vars:
file: "{{ objects_file }}"
- name: Call roles to create infra
include_role:
name: "{{ role_name_lookup[item.type].role_name }}"
tasks_from: "{{ role_name_lookup[item.type].tasks_from }}"
vars:
inputs: "{{ item }}"
with_items: "{{ objects }}"
Sample Role:
---
- name: Print name
debug:
msg: "Type 1 - Name is {{ inputs.name }}"
The other roles are the same, but have msg set to Type X - Name is {{ inputs.name }} instead.
Would this code fit your purpose?
- name: Include roles
include_role:
name: "{{ item.type }}_role"
with_items: "{{ objects }}"
- name: Print name
debug:
msg: "{{ item.type }} - Name is {{ role_name }}"