Ansible: How to pass the condition when variable is undefined - ansible

I tried to combine the below dictionaries to one but struggling to pass the condition when one of the variable is not defined.
ok: [vm1.nodekite.com]] => {
"containeruplist": {
"service": "service-test-app",
"platform-service": "service-dev-app"
}
}
ok: [vm1.nodekite.com] => {
"containerexitedlist": {
"nginx": "www-service"
}
}
Here is my code.
- set_fact:
final_list: "{{ final_list|default({}) | combine( {item.key:item.value} ) }}"
with_dict:
- "{{ containeruplist }}"
- "{{ containerexitedlist }}"
when: (containeruplist is defined) or (containerexitedlist is defined)
Here is the output
ok: [vm1.nodekite.com] => {
"final_list": {
"service": "service-test-app",
"platform-service": "service-dev-app"
"nginx": "www-service"
}
}
but how to pass all the 3 conditionals when one of the variable is not defined.
containeruplist is populated or containerexitedlist is undefined
containeruplist is undefined or containerexitedlist is populated
containeruplist is populated or containerexitedlist is populated
I tried with when: (containeruplist is defined) or (containerexitedlist is defined) which still throws {"msg": "'containerexitedlist' is undefined"}

Related

Define which users belong to which host

I have an inventory:
[dbs]
server1.intranet
[webservices]
server2.intranet
[apps]
server3.intranet
And a file with variables:
users:
- { name: user1, ssh_key: <SSH_KEY> }
- { name: user2, ssh_key: <SSH_KEY> }
(1) My first question is: How can I tell in the inventory which user is part of each server? (without having to copy and duplicate the user information at every host) Note that users can change and can belong to multiple servers.
(2) The final objective is to do some tasks at each host. For example, to create the users at each host, and add the corresponding user SSH key at each server, something like:
- name: SSH
ansible.posix.authorized_key:
user: "item.name"
state: present
key: "item.ssh_key"
with_items: "{{ users[??] }}"
Of course the users variable should only have the users for the specific host iterating.
How can I do this?
I didn't understand your second point, but this solution could be helpful.
Define destination hosts as an array:
users:
- { name: user1, ssh_key: <SSH_KEY>,hosts: ['test-001','test-002'] }
- { name: user2, ssh_key: <SSH_KEY>,hosts: ['test-002'] }
Use selectattr filter for your loop to search the running hostname in the hosts list defined in the vars:
- name: SSH
ansible.posix.authorized_key:
user: "{{ item.name }}"
state: present
key: "{{ item.ssh_key }}"
loop: "{{ users | selectattr('hosts', 'search', inventory_hostname) }}"
ok: [test-001] => (item={'name': 'user1', 'ssh_key': '<SSH_KEY1>', 'hosts': ['test-001', 'test-002']}) => {
"msg": "user1"
}
ok: [test-002] => (item={'name': 'user1', 'ssh_key': '<SSH_KEY1>', 'hosts': ['test-001', 'test-002']}) => {
"msg": "user1"
}
ok: [test-002] => (item={'name': 'user2', 'ssh_key': '<SSH_KEY2>', 'hosts': ['test-002']}) => {
"msg": "user2"
}

I can't get Selectaddr to display attributes from my dict

We're running ansible 2.9.27 on Red Hat Linux 7.9. In my playbook, I have the following code:
- name: DEBUG THIS THING1
debug:
msg: "FOUND HOME: {{ found_service_accounts['svclinux']['home'] }}"
- name: DEBUG THIS THING2
debug:
msg: "FOUND: {{ found_service_accounts['svclinux']['home'] | selectattr('path', 'defined') | list }}"
The output looks like this:
TASK [service_accounts : DEBUG THIS THING1] ***************************************************************************
ok: [myhost.example.com] => {
"msg": "FOUND HOME: {u'owner': u'svclinux', u'path': u'/home/svclinux', u'group': u'svc-linux', u'permissions': u'755'}"
}
TASK [service_accounts : DEBUG THIS THING2] ***************************************************************************
ok: [myhost.example.com] => {
"msg": "FOUND: []"
}
I can't figure out why Ansible isn't printing the path attribute of my home. It just prints the empty list. Can you see my obvious mistake?
Thanks.
Note: found_service_accounts is a dict that was set as follows. The homes.results...stdout_lines[n] are simple strings gleaned from a shell command:
- name: set found_service_accounts
set_fact:
found_service_accounts: |
{% set j2fsa = { } %}
{%- for user in service_account_names -%}
{% set _ = j2fsa.update(
{ user : { 'home' : { 'path' : homes.results[loop.index0].stdout_lines[0],
'owner' : homes.results[loop.index0].stdout_lines[1],
'group' : homes.results[loop.index0].stdout_lines[2],
'permissions' : homes.results[loop.index0].stdout_lines[3]
},
'ssh_subdirectory' : {
'owner' : ssh_subdir.results[loop.index0].stdout_lines[0],
'permissions' : ssh_subdir.results[loop.index0].stdout_lines[1]
}
}
})
%}
{%- endfor %}
{{ j2fsa }}
and service_account_names is just a list like: [ 'svclinux' ]
found_service_accounts['svclinux']['home'] is a dictionary, not a list. You should directly access the value of path:
- name: DEBUG THIS THING2
debug:
msg: "FOUND: {{ found_service_accounts['svclinux']['home']['path'] }}"
What happens in your original attempt is that iterating over a dictionary returns just the dictionary keys (["owner", "path", "group", "permissions"]), and strings do not have an attribute named path.

Ansible play is not able to take variable

C:\CYGWIN64\ETC\ANSIBLE\ANSIBLE-ACI-CONFIG
├───environments
│ ├───houston
│ └───munich
├───group_vars
├───plays
├───plugins
│ └───filter
│ └───__pycache__
└───roles
├───aci-fabric-onboarding
│ └───tasks
variable file:
oob_nodes:
- { node_id: "101", obb_address: "10.10.10.10", obb_cidr: "27" , obb_gateway: "10.10.10.1" }
- { node_id: "102", obb_address: "10.10.10.11", obb_cidr: "27" , obb_gateway: "10.10.10.1" }
- { node_id: "201", obb_address: "10.10.10.12", obb_cidr: "27" , obb_gateway: "10.10.10.1" }
play
========
- name: Setup ACI Fabric
hosts: "{{ target }}"
gather_facts: no
any_errors_fatal: true
tasks:
- include_vars:
file: "{{ ACI_SSoT_path }}/fabricsetup.yml"
- include_vars:
file: "{{ ACI_SSoT_path }}/oob.yml"
# Intent Statement
- include_role:
name: aci-fabric-onboarding
roles
==============
# Adding OBB address
- name: Add OBB address
delegate_to: localhost
aci_rest:
host: "{{ aci_ip }}"
username: ansible
private_key: ansible.key
certificate_name: ansible
use_ssl: yes
validate_certs: false
path: /api/node/mo/uni/tn-mgmt/mgmtp-default/oob-default/rsooBStNode-[topology/pod-1/node-"{{item.node_id}}"].json
method: post
content:
{
"mgmtRsOoBStNode":{
"attributes":{
"tDn":"topology/pod-1/node-101",
"addr":"25.96.131.61/27",
"gw":"25.96.131.33",
"status":"created"
},
"children":[
]
}
}
with_items: "{{ oob_nodes }}"
error:
TASK [aci-fabric-onboarding : Add OBB address] *****************************************************************************************************************************************************
task path: /etc/ansible/Ansible-Aci-config/roles/aci-fabric-onboarding/tasks/apply-oob-config.yml:4
fatal: [25.96.131.30]: FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was: 'item' is undefined\n\nThe error appears to be in '/etc/ansible/Ansible-Aci-config/roles/aci-fabric-onboarding/tasks/apply-oob-config.yml': line 4, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n# Adding OBB address\n- name: Add OBB address\n ^ here\n"
}
That looks like an indention error to me. You have with_items with the same indention as aci_rest:
# Adding OBB address
- name: Add OBB address
delegate_to: localhost
aci_rest:
host: "{{ aci_ip }}"
username: ansible
private_key: ansible.key
certificate_name: ansible
use_ssl: yes
validate_certs: false
path: /api/node/mo/uni/tn-mgmt/mgmtp-default/oob-default/rsooBStNode-[topology/pod-1/node-"{{ item.node_id }}"].json
method: post
content:
{
"mgmtRsOoBStNode":{
"attributes":{
"tDn":"topology/pod-1/node-101",
"addr":"25.96.131.61/27",
"gw":"25.96.131.33",
"status":"created"
},
"children":[
]
}
}
with_items: "{{ oob_nodes }}"
Have a look at the documentation as well.

calling a custom variable from inventory

I have a some custom variables in my inventory file. I would like to call them in my playbook, but not sure how to do this.
--------------------------------INV--------------------------------
[testA]
namgw01a
namgw02a
[testB]
namgw01b
namgw02b
[nam:children]
testA
testB
[testA:vars]
file=file_a.conf
[testB:vars]
file=file_b.conf
--------------------------------PLAYBOOK--------------------------------
vars:
- file: "{{ file }}"
- name: "show variable"
debug:
var: file
--------------------------------RESULT--------------------------------
TASK [show variable] **************************************************************************************************************************************
ok: [namgw01b] => {
"file": "VARIABLE IS NOT DEFINED!"
}
ok: [namgw02b] => {
"file": "VARIABLE IS NOT DEFINED!"
}

ansible 2.0.0-0.3.beta1 ec2_vpc_route_table ec2_vpc_subnet

I am creating an ansible playbook using version 2.0.0-0.3.beta1
I'd like to get the subnet id after i create a subnet. I'm refering the official ansible docs : http://docs.ansible.com/ansible/ec2_vpc_route_table_module.html
- name: Create VPC Public Subnet
ec2_vpc_subnet:
state: present
resource_tags: '{"Name":"{{ prefix }}_subnet_public_0"}'
vpc_id: "{{ vpc.vpc_id }}"
az: "{{ az0 }}"
cidr: 172.16.0.0/24
register: public
- name: Create Public Subnet Route Table
ec2_vpc_route_table:
vpc_id: "{{ vpc.vpc_id }}"
region: "{{ region }}"
tags:
Name: Public
subnets:
- "{{ public.subnet_id }}"
routes:
- dest: 0.0.0.0/0
gateway_id: "{{ igw.gateway_id }}"
after running the playbook i received following error:
fatal: [localhost]: FAILED! => {"failed": true, "msg": "ERROR! 'dict object' has no attribute 'subnet_id'"}
Try using: public.subnet.id instead of public.subnet-id
Its useful to debug by running this task:
- debug: msg="{{ public }}"

Resources