'dict object' has no attribute 'stdout_lines' - ansible

I am trying to extract the status (http) (Enabled/ Disabled) for each server and display it in the logs. It is able to check for http status but when I try to store it, it is giving following error.
- name: Check http status(yes or no)
shell: |
sshpass -p "{{ imc_prod_password }}" ssh -T -o StrictHostKeyChecking=no {{ imc_username }}#"{{ item.cimcNames }}" << EOL
scope http
show detail | grep Enabled
EOL
register: http_status
loop: "{{ user_list.list }}"
- debug:
msg: '{{ http_status.stdout_lines | select("Enabled") | list }}'
The command show detail gives following output
Enabled: no
Output - Line 59 points to - debug:
TASK [cimc_reip : Check http status(yes or no)] ********************************
changed: [hostname] => (item={'PreferredDNS': 'x.x.x.x', 'IPdetails': 'x.x.x.x', 'Alternate': 'x.x.x.x', 'id': '1', 'GWDetails': 'x.x.x.x', 'Subnetdetails': 'x.x.x.x', 'cimcNames': 'test-server-01-r'})
changed: [hostname] => (item={'PreferredDNS': 'x.x.x.x', 'IPdetails': 'x.x.x.x', 'Alternate': 'x.x.x.x', 'id': '2', 'GWDetails': 'x.x.x.x', 'Subnetdetails': 'x.x.x.x', 'cimcNames': 'test-server-02-r'})
TASK [cimc_reip : debug] *******************************************************
fatal: [hostname]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout_lines'\n\nThe error appears to be in '/builds/xxxxx/xxxx/playbooks/roles/cimc_reip/tasks/main.yml': line 59, 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 - debug:\n ^ here\n"}

As already mentioned in the comments you are registering the result set in a loop in one variable. You will get therefore an dictionary and in your example an error
The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout_lines'
The following test shows it
---
- hosts: localhost
become: false
gather_facts: false
vars:
USERNAME: ['test'] # list
PASSWORD: 'password'
target_host: "test.example.com"
tasks:
- name: Check http status
shell: |
sshpass -p '{{ PASSWORD }}' ssh -T -o StrictHostKeyChecking=no {{ item }}#"{{ target_host }}" << EOF
sudo lsof -Pi TCP
EOF
register: http_status
loop: "{{ USERNAME }}" # list
- debug:
msg: "{{ http_status | type_debug }}"
resulting into an output of
TASK [debug] ************
ok: [test.example.com] =>
msg: dict
You can loop over the http_status.results list in the dictionary as follow
- name: Show result
debug:
msg: "{{ item.stdout_lines }}"
loop: "{{ http_status.results }}" # list
loop_control:
label: "{{ item.item }}" # with USERNAME looped over to limit the displayed output
resulting into an output of
TASK [Show result] *****************************************************************************
ok: [test.example.com] => (item=test) =>
msg:
- COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
- httpd 384 root 19u IPv4 12345678 0t0 TCP test.example.com:443 (LISTEN)

Related

Loop over list and evaluate element property in Ansible

I have a list with shell lines that I want to execute on inventory hosts so I can determine if the database is working. For the test purposes I have 1 server with PostgreSQL and 1 with MySQL.
This is my playbook so far:
- name: Check db statuses
shell: "{{ item }}"
loop:
- ps -fp $(pgrep -u postgres) | grep /usr/lib/postgresql
- ps -fp $(pgrep -u mysql) | grep mysqld
register: http
ignore_errors: yes
changed_when: item.failed == false
this is failing with:
{
"http": {
"failed": true,
"msg": "The conditional check 'item.failed == false' failed. The error was: error while evaluating conditional (item.failed == false): 'ansible.parsing.yaml.objects.AnsibleUnicode object' has no attribute 'failed'"
}
}
I want to assign only the item.failed==false result in the register variable (http) but ignore the failed ones.
You can't select what will be registered in a loop. Instead, you'll have to evaluate the registered results in the next task(s), e.g.
- hosts: localhost
tasks:
- command: "{{ item }}"
loop:
- /bin/true
- /bin/false
register: http
ignore_errors: true
- debug:
msg: "{{ item.item }} failed: {{ item.failed }}"
loop: "{{ http.results }}"
loop_control:
label: "{{ item.cmd }}"
gives
ok: [localhost] => (item=['/bin/true']) =>
msg: '/bin/true failed: False'
ok: [localhost] => (item=['/bin/false']) =>
msg: '/bin/false failed: True'

Ansible show correct result with conditionnal in when from list in dict

How i can select the correct "IP" from ping in with_items
Ansible main.yml code:
IP_server:
- north:
192.168.1.1
192.168.1.2
- name: Ping command
shell:
cmd: "ping -c -w 2 {{ item }}"
register: "server_ok"
ignore_errors: yes
with_items:
- "{{ IP_server.north }}"
loop_control:
loop_var: "correct_server"
- name: "Selected IP"
debug:
msg: "{{ IP_server.north.msg }}"
when: IP_server.north.msg.0.rc == 0
Result: Always show first IP: 192.168.1.1
Desired result: The correct IP selected by the conditional "....rc==0" in the "when".
Thanks a lot!
For example
- hosts: localhost
vars:
IP_server:
- 10.1.0.61
- 10.1.0.62
- 10.1.0.99
tasks:
- command: "ping -c 1 {{ item }}"
register: server_ok
ignore_errors: yes
loop: "{{ IP_server }}"
- debug:
msg: "{{ server_ok.results|
selectattr('rc', 'eq', 0)|
map(attribute='item')|
list }}"
gives
PLAY [localhost] ****************************************************************
TASK [command] ******************************************************************
changed: [localhost] => (item=10.1.0.61)
changed: [localhost] => (item=10.1.0.62)
failed: [localhost] (item=10.1.0.99) => changed=true
ansible_loop_var: item
cmd:
- ping
- -c
- '1'
- 10.1.0.99
delta: '0:00:03.078826'
end: '2021-02-25 10:50:17.192211'
item: 10.1.0.99
msg: non-zero return code
rc: 1
start: '2021-02-25 10:50:14.113385'
stderr: ''
stderr_lines: <omitted>
stdout: |-
PING 10.1.0.99 (10.1.0.99) 56(84) bytes of data.
From 10.1.0.27 icmp_seq=1 Destination Host Unreachable
--- 10.1.0.99 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms
stdout_lines: <omitted>
...ignoring
TASK [debug] ********************************************************************
ok: [localhost] =>
msg:
- 10.1.0.61
- 10.1.0.62

Ansible v2.2 error when using with_subelements which worked fine in 1.7

I am getting the following error while running my ansible playbook.
TASK [base : Rsyslog yapilandiriliyor.]
**************************************** fatal: [gkts.ahtapot]: FAILED! => {"failed": true, "msg": "The conditional check
'ansible_fqdn == {{item.1}}' failed. The error was: error while
evaluating conditional (ansible_fqdn == {{item.1}}): 'item' is
undefined\n\nThe error appears to have been in
'/etc/ansible/roles/base/tasks/rsyslog.yml': line 2, column 3, but
may\nbe elsewhere in the file depending on the exact syntax
problem.\n\nThe offending line appears to be:\n\n---\n- name: Rsyslog
yapilandiriliyor.\n ^ here\n"}
This worked fine in ansible 1.7 but doesn't work in ansible 2.2.1
- name: Rsyslog yapilandiriliyor.
template:
src: "{{ rsyslog['conf']['source'] }}"
dest: "{{ rsyslog['conf']['destination'] }}"
owner: "{{ rsyslog['conf']['owner'] }}"
group: "{{ rsyslog['conf']['group'] }}"
mode: "{{ rsyslog['conf']['mode'] }}"
# when: "ansible_fqdn == item.1"
when: "ansible_fqdn == {{item.1}}"
with_subelements:
- "{{ossimciks}}"
- "{{clients}}"
notify:
- rsyslog servisini yeniden baslat
sudo: yes
tags: rsyslog
ossimciks and clients are defined in my vars file:
ossimciks:
server01:
fqdn: "OSSIMCIK_FQDN"
port: "20514"
clients:
- "LOG_KAYNAGI_FQDN"
- "LOG_KAYNAGI_FQDN"
What am I missing?
with_subelements:
- "{{ossimciks}}"
- "{{clients}}"
Syntax
I don't know how where/how/when this might have changed in Ansible, but I think that
the first element in with_subelements is a variable, and
the second element in with_subelements is a key.
This works in playbooks I've written, and matches the relevant docs (since 2.5, there are no with_* loops [1] in the docs since they were always lookups anyhow [2]):
with_subelements:
- "{{ ossimciks }}"
- clients
Data
It's not clear to me which item you're attempting to target with {{ item.1 }} in your playbook, but if making a minor change to your data is permissible, you can structure it so that any of the information shown is accessible within a with_subelements loop (I've also expanded and restructured the data a bit to clarify what the loop is doing):
---
- hosts: localhost
gather_facts: false
vars:
fqdn_var: "OSSIMCIK_FQDN_2"
ossimciks:
- server: "server01"
fqdn: "OSSIMCIK_FQDN_1"
port: "20514"
clients:
- "LOG_KAYNAGI_FQDN_1"
- "LOG_KAYNAGI_FQDN_2"
- server: "server02"
fqdn: "OSSIMCIK_FQDN_2"
port: "20514"
clients:
- "LOG_KAYNAGI_FQDN_1"
- "LOG_KAYNAGI_FQDN_2"
tasks:
- name: Output ossimciks contents.
debug:
msg: "{{ item.0.server }} client: {{ item.1 }}"
with_subelements:
- "{{ ossimciks }}"
- clients
when: item.0.fqdn == fqdn_var
This outputs:
skipping: [localhost] => (item=None) => {"skip_reason": "Conditional result was False"}
skipping: [localhost] => (item=None) => {"skip_reason": "Conditional result was False"}
ok: [localhost] => (item=None) => {
"msg": "server02 client: LOG_KAYNAGI_FQDN_1"
}
ok: [localhost] => (item=None) => {
"msg": "server02 client: LOG_KAYNAGI_FQDN_2"
}
[1] http://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html
[2] Loops are actually a combination of things with_ + lookup(), so any lookup plugin can be used as a source for a loop, ‘items’ is lookup.
Edited to add: the playbooks where I've used the syntax above were definitely in the 2.x release series--I think ~2.1.

Ansible slurp module fails with a variable

When I use an Ansible variable with the src option of the slurp module, the slurp module fails.
I'm trying to build an Ansible playbook to copy the SSH public key from each node in the group to every other node in the group. I cannot use the Ansible lookup() function because that can lookup files only on the Ansible server. Instead, I build the path to the id_rsa.pub with the intent of slurp'ing into memory for the authorized_key function.
My problem is that when I specify an Ansible variable for the src for the slurp module, the playbook fails, even though it lists the correct path to the id_rsa.pub file. If I specify the path instead of using the variable, the slurp module works.
Here is my playbook:
# Usage: ansible-playbook copyPublicKey.yaml --limit <GRP> --extra-vars "userid=<userid>"
---
- hosts: all
remote_user: root
vars:
user_id: "{{ userid }}"
tasks:
- name: Determine the path to the public key file
shell: grep "{{ user_id }}" /etc/passwd | cut -d":" -f6
changed_when: false
register: user_home
- set_fact:
rsa_file: "{{ user_home.stdout_lines | to_nice_yaml | replace('\n', '') }}/.ssh/id_rsa.pub"
- debug:
msg: "Public key file - {{ rsa_file }}"
- slurp:
src: "{{ rsa_file }}"
register: public_key
- debug:
msg: "Public key: {{ public_key }}"
The invocation:
ansible-playbook copyPublicKey.yaml --limit DEV --extra-vars "userid=deleteme2"
The output of the slurp module:
TASK: [slurp ] ****************************************************************
failed: [hana-np-11.cisco.com] => {"failed": true}
msg: file not found: - /usr/sap/DEV/home/deleteme2/.ssh/id_rsa.pub
failed: [hana-np-13.cisco.com] => {"failed": true}
msg: file not found: - /usr/sap/DEV/home/deleteme2/.ssh/id_rsa.pub
failed: [hana-np-14.cisco.com] => {"failed": true}
msg: file not found: - /usr/sap/DEV/home/deleteme2/.ssh/id_rsa.pub
failed: [hana-np-15.cisco.com] => {"failed": true}
msg: file not found: - /usr/sap/DEV/home/deleteme2/.ssh/id_rsa.pub
failed: [hana-np-12.cisco.com] => {"failed": true}
msg: file not found: - /usr/sap/DEV/home/deleteme2/.ssh/id_rsa.pub
FATAL: all hosts have already failed -- aborting
Yet if I specify the actual path in the slurp module:
- slurp:
src: /usr/sap/DEV/home/deleteme2/.ssh/id_rsa.pub
I get the output I expect:
TASK: [slurp ] ****************************************************************
ok: [hana-np-11.cisco.com]
ok: [hana-np-12.cisco.com]
ok: [hana-np-15.cisco.com]
ok: [hana-np-14.cisco.com]
ok: [hana-np-13.cisco.com]
TASK: [debug ] ****************************************************************
ok: [hana-np-11.cisco.com] => {
"msg": "Public key: c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBQkl3QUFBUUVBbHgzM0FUdGlLcWlrblQxMWorNjZKSXVFQW1OWWxZcDdCbHIwZXBzaWRuZ3NNYW9pMjNYL1Bjb0EvdnVxYmpxbmZ0Q1YzQmhUdURYQ3BYY0FwNDF5TEF5dlIvOW8xYi9mR2VtZWtlS296ZDh5Smh5VXFMR3IvMmJ6N0N2NFdaOWVqU0dyMFlzWGNjSFNDRmYzNmJreVBPNUg5NUdZdXpGMUV2RzVVcGM3YVNXWEVpM3JWVGJETEhBVC9YTk0veXhRUEMxRjB5Vi8yRkY1WDg4SXU5U0w2TGxrVnhsMUU3VkozTm40UEQrY3RUbGxFeno3enNETWxDbXpzMW5MaHROWnFuSXRZUkhMd21WUk5VcHJvYlpyUm1YMFJVYmIwNFNVbzdBbXpBNnZNcHR1OE1aUURzUGRMckMwYWxPWnZHMHpEUi9ReDlGalh6MVRXMld5WWhZNllRPT0gYW5zaWJsZS1nZW5lcmF0ZWQgb24gaGFuYS1ucC0xMQo=..."
}
ok: [hana-np-12.cisco.com] => {
"msg": "Public key: c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBQkl3QUFBUUVBd2hPa0FqcEhwbUU4ZEkvemR6d0I1U0htZnlpdXljd2ZmK2lDNW9KaEN4aU5ST0ZKbnVyOFArWno2K2c4Qy8waUdkNGs1ZHIwcE9IY1liWHlMeDNObHhTTWN6RnowZWNSUnMzL1FOOEQzSnBtWlR6T0JaMm1SaG1FY0hGbS9uTkh5eUZyWXlPOHlQNWpqNmxiSUlwU0lMb1BZZGJvM1dxenBGZjhiaDFlVkhRTEo2citVZzNwcUhUeWRzRDZhY3Rtc1ZvWWUvdVV6WExiYkpKbUxxdi9ZeGU4ZW9aUmtONkVqNGtaVDBibDFYUktkM0xTQlZKMHRwa3A1bVgzekxMNGVvWVEzMzMzam1qd2MzU1dWSHVObVl1b1ZsRFEvSzdoR2lFVHd5YUM3VU9hQ29pcEVnUGl5b2o3U1JpNzZCenpxV2hXc2dIbHI0REM3U0p2WFpObk9RPT0gYW5zaWJsZS1nZW5lcmF0ZWQgb24gaGFuYS1ucC0xMgo=..."
}
ok: [hana-np-13.cisco.com] => {
"msg": "Public key: c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBQkl3QUFBUUVBemFzeitlSW9OSnc2Q3psaVVSR2NQbnMyRkVWbDRtd1RqbDJrWkYxcC9uL0d1b3RPS01vMnR2RmQrN3JmY3YrN2VSZXNtM1lldXJzOXRCQXdSVDdvbXdjckpqUkJiM2Q3UHd3MnM1OTJjb0RjdFo3aE9vL3p4S1FCeWtjaXcvejJ3U1pKWUZKdnE4eFloWkxQNmxnK01uVW1Rd0JROURhREc3MVY2VFc5cFdSM0poYk5BZ2s4bWpBYlEyQk1kK2lWOGxoOUorcWIxbGE3RVVRRGZNaUM3R0ZKVmxJUVlpdm02Q045dGZOdnJGRlNaamZ6MEZKeXhQQWd1VW05d2NUMG9lUDdEQTJTVFNZQ0trQklvRmVuTUp3eFFzNDZSclJSenlBNlErN3I3Q3g5WnpPSlQ0OGgzQnpHQkNwYnhNd0R2L1RMNjRNTDN3UGxXVng5NGZvU2NRPT0gYW5zaWJsZS1nZW5lcmF0ZWQgb24gaGFuYS1ucC0xMwo=..."
}
ok: [hana-np-14.cisco.com] => {
"msg": "Public key: c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBQkl3QUFBUUVBd3U5V3FaZHBmSjdUZkFhNkc2V05pTkpraWVjWllObjZ4Mno2WWo3eUhsdDBrVWhoYmVXZWR4and0Ukl5d0h2UUZCU2xoVVo2V1Vhc2w0RlZsdzcrOHRGVkVIMkkwTUQ1YjN5UGFrclFhVXdxZHZ6TDEvVXpQWkJjTGU0SENmTGdLNjAxaXdncXBvdUVoRjFEdjEvVHorcTFvU0dmTTFOVjFPOFBGc1pQVjRZbVpoTC9qTVZBNE5MUzFKdXRoS1VmZlo3TmJOSk42SmdWaE14UW8vQXZIZmZvYktDUGJ1VWxDTFE0cTV6VlVTWkxyV1p3VmdncU44MkVnd0xYS00xU0IvOVQ2YmFMVXZhaDVVN0s1QjEzR0pFVXJWek1NNWZ0clpwdEo4T1N3OXUvMHJLVXlzZ0hRcUZVM0ViN0JkVkUxQVdCRXFtaW1XRFdMV3hUclJmZ053PT0gYW5zaWJsZS1nZW5lcmF0ZWQgb24gaGFuYS1ucC0xNAo=..."
}
ok: [hana-np-15.cisco.com] => {
"msg": "Public key: c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBQkl3QUFBUUVBdWwxTjlWQkNSU3QrOG5jdTRMVUlBb2hxUEkrWmRlcEtINHlhU1BBZWtETXdkaXpLVHZRSElXdC9iVkpXUzNma3BOYjVuTXFtMkR1eFZnKzBtZmRPTTk1Q2ZsUk00ZUNON05Jb25HQTQrUGVyOXRYdlNrdFU4U0huWERsZVNNa3dybUxnQ1dQN2lwbDRTdGt1SUNGaFh1NzBkOHBEN29IeW9BZVVWWVFuYzRkZldHQStVNU1SdWNSaC9mNWhhS25pN1hpRHZ0alVTaDJHN1RpMTlIdHBvYnlQdmdNSjVnRUt2OXRlWGJ3Qk14YXZicEFiRjJVOTRRTmorKzZOYTZIaWUweS9JQzVtWDRvSmgyb2Z6bGwybjA0MHdtQWRkQS9mY1d1L0IvR3FyOWNDZlhXK0hIUU95MEJoUXNBMk54K3A1RU4rbG1iREg1TUNHTW41Y0RLVEpRPT0gYW5zaWJsZS1nZW5lcmF0ZWQgb24gaGFuYS1ucC0xNQo=..."
}
What am I doing wrong? What don't I know about using Ansible variables?
slurp module fails because you provide it incorrect data -- the error message is:
msg: file not found: - /usr/sap/DEV/home/deleteme2/.ssh/id_rsa.pub
Rephrasing:
The file named "- /usr/sap/DEV/home/deleteme2/.ssh/id_rsa.pub" cannot be found.
Quite obviously such a file with a hyphen and a space at the beginning does not exist and the error is valid.
The reason for malformed data is unnecessary to_nice_yaml filter on a user_home.stdout_lines list (hyphen is an element marker in YAML).
You can safely remove it and use the following:
---
- hosts: all
remote_user: root
vars:
user_id: "{{ userid }}"
tasks:
- name: Determine the path to the public key file
shell: grep "{{ user_id }}" /etc/passwd | cut -d":" -f6
changed_when: false
register: user_home
- slurp:
src: "{{ user_home.stdout_lines[0] }}/.ssh/id_rsa.pub"
register: public_key
- debug:
msg: "Public key: {{ public_key }}"
Elements of stdout_lines don't have trailing newlines, so replace('\n', '') is unnecessary, but as it is a list, even though south a single element, you need to address only the first element with [0].
Otherwise you could also get the value with user_home.stdout | replace('\n', '') }}/.ssh/id_rsa.pub.
In this case, the issue is related to incorrect file name (as mentioned by techraf).
But just a note about what I have experienced is that slurp also shows the same error "File not found" when the file resides in a directory whose permissions are not allowing ansible user to read content from it. Though, it should print permission related error but it shows instead "File not found" error.

When hostvars data is populated and how it is accessible?

Here is my play:
- name: Tag ec2 instances
hosts: localhost
tasks:
- name: Print Hosts
debug: var=hostvars[item]['ec2_id']
with_inventory_hostnames: all
- name: Print Hosts 2
debug: msg={{hostvars[item]['ec2_id']}}
with_inventory_hostnames: all
- name: Tag Hosts
ec2_tag:
resource: "{{ hostvars[item]['ec2_id'] }}"
region: ap-southeast-2
args:
tags: {mytag: 'myvalue'}
with_inventory_hostnames: all
Can anyone explain why the second task fails with the following error while the first one is successful?
...
ok: [localhost] => (item=172.31.11.37) => {
"hostvars[item]['ec2_id']": "i-xxxxxx",
"item": "172.31.11.37"
}
TASK [Print Hosts 2] ***********************************************************
fatal: [localhost]: FAILED! => {"failed": true, "msg": "'dict object' has no attribute 'ec2_id'"}
debug module with var=hostvars[item]['ec2_id'] will not fail if anything to the right of equal sign is undefined.
While msg={{hostvars[item]['ec2_id']}} will fail if the part in braces can't be templated.
In your example this may fail for localhost because I'm almost sure that ec2_id is not defined for localhost.
To avoid this, you can apply when statement to your loop, as follows:
- name: Print Hosts 2
debug: msg={{hostvars[item]['ec2_id']}}
when: hostvars[item]['ec2_id'] is defined
with_inventory_hostnames: all

Resources