I have a test playbook where I have 5 nodes and I need to create a dynamic host group if the Manufacturer of that nodes is XYZ company
So far, I have tried these and able to loop through nodes and get a Manufacturer using
- name: Filter the Manufacturer of Nodes
hosts: Test
tasks:
- name: Get facts from hosts
redfish_info:
category: Chassis
command: GetChassisInventory
baseuri: "{{ hostvars[item]['nodes_list'] }}"
username: "{{ }}"
password: "{{ }}"
register: chassis_facts
with_items:
- "{{ groups.webservers }}"
- "{{ groups.dbservers }}"
- debug:
var: chassis_facts.results
What should now happen is I need to create a dynamic host group using add_host module
- name: Add the hosts dynamically as per Manufacturer
add_host:
groups: xyz_hosts
hostname: "{{ item }}"
when: chassis_facts.results[*].redfish_facts | json_query(some_regex_filter)
with_items:
- "{{ groups.webservers }}"
- "{{ groups.dbservers }}"
based on the Manufacturer from above node list using json_query filter. Any help is highly appreciated.
So, after much digging I found an answer to this, Im using below module which did the trick.
- name: create a new host group based on Manufacturer
add_host:
groups: webservers
hostname: "{{ item }}"
inventory_dir: "{{inventory_dir}}"
when: '"xyz Company" in
result.results[0].redfish_facts.chassis.entries[0].Manufacturer'
with_items:
- "{{ groups.webservers }}"
Related
I have a functioning ansible script that connects to AWS and prints out tags from instances in a specified state.
The problem I'm having is the print out is two separate lists e.g.
What I get is:
name1
name2
name3
description1
description2
description3
What I would like is:
name1 - description1
name2 - description2
name3 - description3
I've tried pushing this all into a dictionary, but got lost in the attempt. There must be an easier way.
Here's my code:
- name: print stopped systems
hosts: all
become: false
tasks:
- name: Gather ec2_metadata_facts (use -vv to show all)
action: ec2_metadata_facts
- name: pull instance info with ec2_instance_info
ec2_instance_info:
region: "{{ lookup('env','AWS_DEFAULT_REGION') }}"
aws_access_key: "{{ lookup('env','AWS_ACCESS_KEY_ID') }}"
aws_secret_key: "{{ lookup('env','AWS_SECRET_ACCESS_KEY') }}"
filters:
instance-state-name: [ "shutting-down", "stopping", "stopped" ]
register: ec2_info
- name: print Instance Info
debug:
msg:
- "{{ ec2_info | json_query(name_tag) }}"
- "{{ ec2_info | json_query(description_tag) }}"
vars:
name_tag: "instances[*].tags.Name"
description_tag: "instances[*].tags.Description"
The output of the debug statement looks like this:
TASK [print Instance Info] **********************************************************************************************************************
ok: [tools-server-01] =>
msg:
- - server-01
- server-02
- - Description for server one
- Description for server two
Thanks #Rickkwa
I've got this mostly working.
here's my current code
- name: Print stopped systems
hosts: all
become: false
tasks:
- name: Gather ec2_metadata_facts (use -vv to show all)
action: ec2_metadata_facts
- name: pull instance info with ec2_instance_info
ec2_instance_info:
region: "{{ lookup('env','AWS_DEFAULT_REGION') }}"
aws_access_key: "{{ lookup('env','AWS_ACCESS_KEY_ID') }}"
aws_secret_key: "{{ lookup('env','AWS_SECRET_ACCESS_KEY') }}"
filters:
instance-state-name: [ "shutting-down", "stopping", "stopped" ]
register: ec2_info
- name: Create Name list
no_log: true
set_fact:
name_l: "{{ec2_info | json_query(name_tag)}}"
vars:
name_tag: "instances[*].tags.Name"
- name: Create Description list
no_log: true
set_fact:
desc_l: "{{ ec2_info | json_query(description_tag) }}"
vars:
description_tag: "instances[*].tags.Description"
- name: print together
debug:
msg: "{{item.0}} --- {{item.1}}"
loop: "{{ name_l|zip(desc_l)|list}}"
Unfortunately, the last debug statement includes some 'garbage" I'd like to remove...anyone have a suggestion to get rid of the stuff following the "u"s?
here's the output :'
TASK [print together] ***************************************************************************************************************************
ok: [dev-bsd-01] => (item=[u'server-01', u'server one description']) =>
msg: server-01 --- server one description
ok: [dev-bsd-01] => (item=[u'server-02', u'server two description']) =>
msg: server-02 --- server two description
I'm trying to learn how to iterate through data from csv and put it into a dict rather than a list. I can make it work with a list, but doing so isn't as helpful for a CSV that needs to run multiple tasks that each use only some of the same data because then I'd have to make a new CSV for every task and call a different csv in every task. Since most of the data is the same in each task I'd rather pull all from the same csv and use a dict to specify which particular cell's data i want to use at that moment.
Is there a way to put the data pulled from the csv into a dict?
My Playbook:
tasks:
- name: Read CSV
read_csv:
path: ./constructs.csv
dialect: excel
register: csv_data
- name: Add a new BD
cisco.mso.mso_schema_template_bd:
<<: *login
state: present
schema: "{{ item.schema }}"
template: "{{ item.template }}"
bd: "{{ item.bd }}"
loop: "{{ csv_data.dict|dict2items }}"
- name: Add a new EPG
cisco.mso.mso_schema_template_anp_epg:
<<: *aci_login
state: present
schema: "{{ item.schema }}"
template: "{{ item.template }}"
anp: "{{ item.app_profile }}"
epg: "{{ item.epg }}"
bd:
name: "{{ item.bd }}"
loop: "{{ csv_data.dict|dict2items }}"
If i run the above (with appropriate headers/etc above task: it will simply skip all my tasks. The skip reason is 'no items in the list'.
I'm struggling to find a solution for LAB project I'm working on right now. I'd like to use csv file to populate variables in my playbook when configuring Cisco ACI. I'm using read_csv module and the latest Ansible 2.9
Sample CSV:
tenant1;tenant1-vrf;tenant1-app
tenant1;tenant1-vrf2;tenant1-app2
tenant2;;tenant2-vrf2;tenant2-app2
UPDATE - based on Sai's code I'm not far from reaching the objective. This is the full tasks code.
UPDATE2 - eventually I went back to the read_csv module. It works nice even for complex things. Hope it helps someone as an example.
tasks:
- name: Read tenant from CSV file and return a list
read_csv:
path: "{{ filename }}"
delimiter: ;
register: tenantconfig
- name: TASK 1 - BUILD tenant
aci_tenant:
<<: *aci_login
validate_certs: no
use_ssl: yes
tenant: "{{ item.tenant }}"
description: "{{ item.tenant }} creation as per {{ filename }} source file"
state: present
with_items: "{{ tenantconfig.list }}"
- name: TASK 2 - BUILD Routing {{ vrf }} for {{ tenant }} on {{ apic_host }}
aci_vrf:
<<: *aci_login
state: present
validate_certs: no
use_ssl: yes
tenant: "{{ item.tenant }}"
vrf: "{{ item.vrf }}"
description: "{{ item.vrf }}"
with_items: "{{ tenantconfig.list }}"
i have changed answer to dynamically process your input file and assign tenant,vrf fields where ever you want to call.
tasks:
- name: split fields
command: /usr/bin/awk -F';' '!/^#/ && !/^$/ { print $1 }' tenant1.csv
register: tenants_out
#- debug:
# msg: "{{ lookup('csvfile', item + ' file=tenant1.csv delimiter=; col=0') }}"
# with_items: "{{ tenants_out.stdout_lines }}"
- name: TASK 1 - BUILD tenant
aci_tenant:
state: present
tenant: "{{ lookup('csvfile', item + ' file=tenant1.csv delimiter=; col=0') }}"
vrf: "{{ lookup('csvfile', item + ' file=tenant1.csv delimiter=; col=1') }}"
with_items: "{{ tenants_out.stdout_lines }}"
input file lines are spitted using initial task, and you can direct specify required tenent, vrf values using "with_items" looping. this is useful if your input file has multiple lines as well.
I have a question, i got the sid list & the DB open_mode, i am trying to run a sql script on the DB when below two conditions satisfy:
DB name should end with '1'.
DB Open_Mode should be 'READ WRITE'.
i am using ansible dynamic inventory to get the sid's from the host & loop through that list, but i am unable to use the two conditions to work through the conditions i am adding.
- hosts: all
gather_facts: false
strategy: free
tasks:
- include_vars: roles/oracle/vars/install_vars.yaml
vars:
var_list:
- script_name
- set_fact:
ORACLE_HOMES_DIR: "/u01/app/oracle/product"
DB_HOME: "{{ ORACLE_HOMES_DIR }}/{{ ORACLE_VERSION }}/dbinst_1"
- name: Copy script to host
copy:
src: "{{ playbook_dir }}/{{ script_name }}"
dest: "/tmp/"
owner: "{{ USER_ORACLE }}"
group: "{{ GROUP_ORACLE }}"
mode: 0755
- name: Verify if the DB is open READ WRITE (or) not
become_user: "{{ USER_ORACLE }}"
environment:
ORACLE_SID: "{{ sid }}"
ORACLE_HOME: "{{ ORACLE_HOME }}"
shell: "echo \"set pagesize 0\n select trim(open_mode) from v\\$database;\" | {{ORACLE_HOME}}/bin/sqlplus -S / as sysdba"
with_items: "{{ hostvars[inventory_hostname]['sid_list'] }}"
loop_control:
loop_var: sid
register: om
- name: Get list of sid that are open in READ WRITE mode
set_fact:
sid_list: "{{ om.results | selectattr('sid','search','1$') | map (attribute='sid') | list }}"
- name: Get the OPEN MODE output of the sid's from the list
set_fact:
om_out: "{{ om.results | selectattr('stdout') | map (attribute='stdout') | list }}"
- name: execute sql script
become_user: "{{ USER_ORACLE }}"
environment:
ORACLE_SID: "{{ item.0 }}"
ORACLE_HOME: "{{ ORACLE_HOME }}"
shell: "{{ ORACLE_HOME }}/bin/sqlplus / as sysdba #/tmp/{{ script_name }}"
when: item.1 == 'READ WRITE'
with_together:
- "{{ sid_list }}"
- "{{ om_out }}"
I am expected the playbook to execute the SQL script on the DB, but i am getting error saying "conditional result was False"
TASK [Get list of sid that are open in READ WRITE mode] ****************************************************************************************************************************************************
task path: /uhome/abhi/ansible/sql_script_execute.yaml:44
ok: [dwracdb1] => {
"ansible_facts": {
"sid_list": [
"abhitest1",
"dw1"
]
},
"changed": false
}
TASK [Get the SQL output from all the sid's] ***************************************************************************************************************************************************************
task path: /uhome/abhi/ansible/sql_script_execute.yaml:48
ok: [dwracdb1] => {
"ansible_facts": {
"om_out": [
"READ WRITE",
"READ WRITE"
]
},
"changed": false
}
TASK [Print om out] ****************************************************************************************************************************************************************************************
task path: /uhome/abhi/ansible/sql_script_execute.yaml:52
ok: [dwracdb1] => (item=[u'abhitest1', u'READ WRITE']) => {
"msg": "sid output is abhitest1 om output is READ WRITE"
}
ok: [dwracdb1] => (item=[u'dw1', u'READ WRITE']) => {
"msg": "sid output is dw1 om output is READ WRITE"
}
TASK [execute sql script] **********************************************************************************************************************************************************************************
task path: /uhome/abhi/ansible/sql_script_execute.yaml:61
fatal: [dwracdb1]: FAILED! => {
"msg": "The conditional check 'item.1 == 'READ WRITE'' failed. The error was: error while evaluating conditional (item.1 == 'READ WRITE'): 'item' is undefined\n\nThe error appears to have been in '/uhome/abhi/ansible/sql_script_execute.yaml': line 61, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: execute sql script\n ^ here\n"
}
First, a formatting hint: move the when condition on your block up to the top so that it's obvious what it controls. When you put it at the bottom it's not obvious:
- block:
when:
- hostvars[inventory_hostname]['sid_list'] is defined
In this task, you're collecting multiple results (one for each entry in sid_list):
- name: Verify if the DB is open READ WRITE (or) not
become_user: "{{ USER_ORACLE }}"
environment:
ORACLE_SID: "{{ sid }}"
ORACLE_HOME: "{{ ORACLE_HOME }}"
shell: "echo \"set pagesize 0\n select trim(open_mode) from v\\$database;\" | {{ORACLE_HOME}}/bin/sqlplus -S / as sysdba"
with_items: "{{ hostvars[inventory_hostname]['sid_list'] }}"
loop_control:
loop_var: sid
register: om
- name: Get list of sid that are open in READ WRITE mode
set_fact:
sid_list: "{{ om.results | selectattr('sid','search','1$') | map (attribute='sid') | list }}"
That's why, when you run this task, you end up with a list of results:
- name: Get the SQL output from all the sid's
set_fact:
om_out: "{{ om.results | selectattr(\"stdout\",'equalto','READ WRITE') | map (attribute='stdout') | list }}"
You're doing the correct thing here in your debug task using with_together: you need that in order to associate a result in om_out with one of the entries in sid_list:
- name: Print om out
debug:
msg: sid output is {{ item.0 }} om output is {{ item.1 }}
with_together:
- "{{ sid_list }}"
- "{{ om_out }}"
You should do the same thing when trying to execute your sql script. Get rid of the block, because you only have a single task and you can't loop a block:
- name: execute sql script
become_user: "{{ USER_ORACLE }}"
environment:
ORACLE_SID: "{{ sid.0 }}"
ORACLE_HOME: "{{ ORACLE_HOME }}"
shell: "{{ ORACLE_HOME }}/bin/sqlplus / as sysdba #/tmp/{{ script_name }}"
when:
- sid.1 == 'READ WRITE'
with_together:
- "{{ sid_list }}"
- "{{ om_out }}"
loop_control:
loop_var: sid
In this loop, sid.0 will be the value from sid_list, and sid.1 will be the corresponding value from om_out.
I've been following this example playbook to create rackspace servers using Ansible
http://nicholaskuechler.com/2015/01/09/build-rackspace-cloud-servers-ansible-virtualenv/
Which works great, but only works on one server at a time, so I am trying to make it more dynamic, using with_items to loop through the number of servers I want to build
tasks:
- name: Rackspace cloud server build request
local_action:
module: rax
credentials: "{{ credentials }}"
name: "{{ item }}"
flavor: "{{ flavor }}"
image: "{{ image }}"
region: "{{ region }}"
files: "{{ files }}"
wait: yes
state: present
networks:
- private
- public
with_items:
- server-app-01
- server-app-02
register: rax
This creates the servers fine, but when I try and add this to the deploy group using the method in the link, I get an error, as expected as now there is a 'results' key I"ve tried all kinds of ways to try and target this in the way that I perceive the documentation to allude to:
- name: Add new cloud server to host group
local_action:
module: add_host
hostname: "{{ item.success.name }}"
ansible_ssh_host: "{{ item.success.rax_accessipv4 }}"
ansible_ssh_user: root
groupname: deploy
with_items: rax.results
(I’ve also tried many other kinds of ways to target this)
But I get ‘One or more undefined variables: ‘list object’ has no attribute ‘rax_accessipv4”
This is a stripped down version of the object I get back from rax, through debug. These servers don't exist anymore.
http://pastebin.com/NRvM7anS
Can anyone tell me where I'm going wrong I'm starting to go a bit mad
If you notice the type of rax.results.success is list.
So this: hostname: "{{ item.success.name }}"
should be
hostname: "{{ item.success[0].name }}" or
hostname: "{{ item['success'][0]['name'] }}"
.
{
"changed": true,
"msg": "All items completed",
"results": [
{
"instances": [
{
"name": "server-app-01",
"rax_accessipv4": "134.213.51.171",
"rax_accessipv6": "2a00:1a48:7808:101:be76:4eff:fe08:5251",
}
],
"item": "server-app-01",
"success": [
{
"name": "server-app-01",
"rax_accessipv4": "134.213.51.171",
"rax_accessipv6": "2a00:1a48:7808:101:be76:4eff:fe08:5251",
}
],
"timeout": []
},
......
}
I was just wrestling with this Friday. Here is my solution:
---
- name: Provision rackspace webheads
hosts: localhost
gather_facts: false
max_fail_percentage: 10
tasks:
- name: Provision a set of instances
local_action:
group: servers
count: 5
exact_count: yes
credentials: cred.ini
flavor: <FLAVOR ID>
group: raxhosts
image: <IMAGE ID>
key_name: <SSH KEYNAME>
module: rax
name: webheads
state: present
wait: yes
register: rax
- name: Add new instances to the group 'raxhosts'
local_action:
module: add_host
hostname: "{{ item.name }}"
ansible_ssh_host: "{{ item.rax_accessipv4 }}"
ansible_ssh_pass: "{{ item.rax_adminpass }}"
groupname: raxhosts
with_items: rax.success
when: rax.action == 'create'
- name: Wait for hosts
local_action: wait_for host={{ item.rax_accessipv4 }} port=22 delay=60 timeout=600 state=started
with_items: rax.success
Here is what my cred.ini looks like:
[rackspace_cloud]
username =
api_key =
Run it like so:
RAX_CREDS_FILE=cred.ini RAX_REGION=DFW ansible-playbook <playbook>.yml