Using template in complex list variable - ansible

I have a var file like below and the two items don't work the same: the first one is treated as a JSON object and I can access its properties, such as script.name, but it's not the case for the second item which seems to be a plain string.
How can I define the second element of the list in such a way that I can access its properties?
---
file2: script2.j2
scripts_list:
- { name: script1, file: script1.j2 }
- "{ name: script2, file: {{ file2 }} }"
More details - I use the list in a loop like this:
# main.yml
- include_tasks: script.yml
loop: "{{ scripts_list }}"
loop_control:
loop_var: script
# script.yml
- debug:
msg: "loop variable = {{ script }}"
- debug:
msg: "loop variable name = {{ script.name }}"
The first item in the list works fine, but the second returns an error when accessing its name property.
The output seems to show that the first item is treated as a JSON structure whereas the second is just a plain string:
TASK [test : debug] ******************************************************************************************************************************************************************************************************************************
ok: [test] => {
"msg": "loop variable = {u'name': u'script1', u'file': u'script1.j2'}"
}
TASK [test : debug] ******************************************************************************************************************************************************************************************************************************
ok: [test] => {
"msg": "loop variable name = script1"
}
TASK [test : debug] ******************************************************************************************************************************************************************************************************************************
ok: [test] => {
"msg": "loop variable = { name: script2, file: script2.j2 }"
}
TASK [test : debug] ******************************************************************************************************************************************************************************************************************************
fatal: [test]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'unicode object' has no attribute 'name'\n"}

How can I define the second element of the list in such a way that I can access its properties?
Well IMO the best way to address this since you are defining your scripts info inside a yaml file is to use a yaml definition for all of them and to quote elements with jinja2 templating appropriately.
scripts_list:
- name: script1
file: script1.j2
- name: script2
file: "{{ file2 }}"
If for some reason you want to keep the jsonish definition, the following should work as expected:
scripts_list:
- { name: script1, file: script1.j2 }
- { name: script2, file: "{{ file2 }}" }

Related

Ansible - List of dictionaries

Let me introduce my problem. I have some list of dictionary in my Ansible code:
my_example_list = [
{
"key1" : "value_of_first_key"
},
{
"key2": "value_of_second_key"
},
{
"key3": "value_of_third_key"
}
]
I need execute command which will iterate over this list and it should look something like:
- name: 'Example'
shell: 'Here is my {{ item.key }} and here is {{ item.value }}'
What I've do or try to do:
I was trying to do that with with_items but i'm not able to point into value of particular key.
I've also try to filter values using | first and | last but it's not worked in my case.
What I want to achieve:
Creating loop which will iterate via that list and inject separated key and value into command.
I was asked to show how I was trying to resolve my issue:
Here is some code:
# Showing last component failing
- name: "Try to show last component of my list"
debug:
msg: "{{ my_example_list[1] | last }}"
# When i'm trying to show first component of my list i get "key1"
- name: "Try to show first component of my list"
debug:
msg: "{{ my_example_list[1] | first }}"
# This shows me my list of dict
- name: "Trying use with_items"
debug:
msg: "{{ item }}"
with_items: "{{ my_example_list }}"
# But when i'm trying point to key and value for example
- name: "Trying use with_items point to key and value"
debug:
msg: "Here is my {{ item.key }} which keep {{ item.value }}"
with_items: "{{ my_example_list }}"
# It's failing.
Sorry it's not maybe solution with using loop. I'm just stack with that issue over few days... And as first step I want to know how correctly point to pair keys and values.
It also works well:
- name: Correct solution
debug:
msg: "This is my {{ item.key }} and my value {{ item.value }}"
with_dict: "{{ my_example_list }}"
Thanks #U880D for help! I'm not able to add some plus for your solution because I'm new joiner. Appreciate your answer! :)
Your data structure and naming seems to be unfavorable. There is no need to number the key name and therefore it should be avoided. Furthermore counting list elements in Python starts at 0 not 1.
The following minimal example playbook
---
- hosts: localhost
become: false
gather_facts: false
vars:
example_list: |
[
{
"key1" : "value_of_first_key"
},
{
"key2": "value_of_second_key"
},
{
"key3": "value_of_third_key"
}
]
tasks:
- name: Example loop
debug:
msg: "{{ item }} is of type {{ item | type_debug }}"
loop: "{{ example_list }}"
- name: Example loop
debug:
msg: "{{ item.values() }}"
loop: "{{ example_list }}"
will result into an output of
TASK [Example loop] ******************************************
ok: [localhost] => (item={u'key1': u'value_of_first_key'}) =>
msg: '{u''key1'': u''value_of_first_key''} is of type dict'
ok: [localhost] => (item={u'key2': u'value_of_second_key'}) =>
msg: '{u''key2'': u''value_of_second_key''} is of type dict'
ok: [localhost] => (item={u'key3': u'value_of_third_key'}) =>
msg: '{u''key3'': u''value_of_third_key''} is of type dict'
TASK [Example loop] ******************************************
ok: [localhost] => (item={u'key1': u'value_of_first_key'}) =>
msg:
- value_of_first_key
ok: [localhost] => (item={u'key2': u'value_of_second_key'}) =>
msg:
- value_of_second_key
ok: [localhost] => (item={u'key3': u'value_of_third_key'}) =>
msg:
- value_of_third_key
Further Readings
How to work with lists and dictionaries in Ansible
Extended loop variables

Ansible: how to fetch a value from a dictionary if the dictionary MIGHT be undefined

I need to fetch a value from a dictionary, that might be either defined or undefined, but I can't find a proper way.
Let's assume we have a dictionary:
- name: Define the dictionaty
set_fact:
my_dictionary:
my_key: my_value
Then let's assume that we had to drop the dictionary at some point in some case:
- name: Drop the dictionary
set_fact:
my_dictionary:
And then I need to check if the dictionary defined and assign a variable from one of this dictionary's keys:
- name: Fetch the parameter from the dictionary or set the default value
set_fact:
my_var: >-
(my_dictionary != None) | ternary(
{{ my_dictionary.my_key }},
'my_default_value'
)
Wrong move!
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'None' has no attribute 'my_key'\n\nThe error appears to be in '***/test.yml': line 16, 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: Fetch the parameter from the dictionary or set the default value\n ^ here\n"}
As I understood, Ansible tries to compute the values of the parameters of ternary() in any case. Well, I understand that Ansible is not a programming language, so I shouldn't expect that it will act like a programming language. :-) But, anyhow, how to fetch a value from a dictionaty if the dictionary might be set to None?
The only (ugly) way I've found is something like that:
- name: Fetch the parameter from the dictionary
set_fact:
my_var: "{{ my_dictionary.my_key }}"
when:
my_dictionary != None
- name: Set the default value
set_fact:
my_var: 'my_default_value'
when:
my_dictionary == None
Though I'd rather use some shorter form.
Would anyone be so kind as to share a hint, please?
That's what the default() filter is for.
- hosts: localhost
vars:
foo:
baz:
bar: not the default
tasks:
- debug:
msg: "{{ foo.bar | default('my_default_value') }}"
- debug:
msg: "{{ bar.bar | default('my_default_value') }}"
- debug:
msg: "{{ baz.bar | default('my_default_value') }}"
Output:
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "my_default_value"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "my_default_value"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "not the default"
}
Hope I understood all your requirements correctly but the code seems to be way more complicated that it needs to be.
How about define dict:
-set_fact:
my_dictionary:
1: one
If dict is defined grab the value
-set_fact:
my_var: "{{ my_dictionary.1 }}"
when: my_dictionary is defined
Else set it to value of your choice:
-set_fact:
my_var: two
when: my_dictionary is not defined
Slava Ukraini!

Evaluate variable content in Ansible

I load a file with the content Some {{bar}} random text using the file lookup plugin:
- name: Load foo
set_fact:
foo: "{{ lookup('file', 'foo.txt') }}"
- name: Output foo
debug:
msg: "{{foo}}"
If I output {{foo}}, the output is literally Some {{bar}} random text. Ignoring the fact that I could use the template lookup plugin instead: Is it possible to evaluate {{foo}} after the file has been loaded, so that the actual value of bar will be injected into Some {{bar}} random text?
I am looking for something like:
- name: Evaluate foo
set_fact:
evaulated_foo: "{{ lookup('template', foo) }}" #Use the value of foo instead of a file
This is the intended behaviour. Lookups return unsafe text, which will never be templated. Use the template lookup when you want to return the contents of a file after template evaluation.
To avoid ordering issues, use a variable with the lookup instead of set_fact. set_fact sets variables to a static, fully evaluated value while normal variables are evaluated lazily, so they don't require that all of the variables be defined at the same time.
- hosts: localhost
gather_facts: false
vars:
foo: "{{ lookup('template', 'test.j2') }}"
tasks:
# These will work because bar is a current variable
- debug:
msg: "{{ foo }}"
vars:
bar: lemon
- debug:
msg: "{{ foo }}"
vars:
bar: orange
# This will not work, because bar isn't set
- set_fact:
foo: "{{ foo }}"
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "Some lemon random text\n"
}
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "Some orange random text\n"
}
TASK [set_fact] ****************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: {{ lookup('template', 'test.j2') }}: 'bar' is undefined\n\nThe error appears to be in '/home/ec2-user/test.yml': line 18, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n # This will not work, because bar isn't set\n - set_fact:\n ^ here\n"}

Ansible unable to convert string to dictionary from the stdout_lines

I am trying to get the "count" value from the dictionary
"{ \"_id\" : ObjectId(\"5d3a1643c43c898d01a3c740\"), \"count\" : 2 }"
present at the last element of the ansible stdout_lines.
TASK [version_update : debug] ******************************************************************************************************************************************
ok: [192.168.27.125] => {
"count_info.stdout": "MongoDB shell version v4.0.6\nconnecting to: mongodb://127.0.0.1:27017/configure-db?gssapiServiceName=mongodb\nImplicit session: session { \"id\" : UUID(\"4bfad3ba-981f-47de-86f9-a1fadbe28e12\") }\nMongoDB server version: 4.0.6\n{ \"_id\" : ObjectId(\"5d3a1643c43c898d01a3c740\"), \"count\" : 2 }"
}
TASK [version_update : debug] ******************************************************************************************************************************************
ok: [192.168.27.125] => {
"count_info.stdout_lines": [
"MongoDB shell version v4.0.6",
"connecting to: mongodb://127.0.0.1:27017/configure-db?gssapiServiceName=mongodb",
"Implicit session: session { \"id\" : UUID(\"4bfad3ba-981f-47de-86f9-a1fadbe28e12\") }",
"MongoDB server version: 4.0.6",
"{ \"_id\" : ObjectId(\"5d3a1643c43c898d01a3c740\"), \"count\" : 2 }"
]
}
I tried the following two ways but not successful.
- debug:
msg: "{{ (count_info.stdout_lines[-1] | from_json).count }}"
- name: count value
debug:
msg: "{{ count_info.stdout_lines[-1] | json_query('count') }}"
Error log:
TASK [version_update : debug] ******************************************************************************************************************************************
fatal: [192.168.27.125]: FAILED! => {"msg": "the field 'args' has an invalid value ({u'msg': u'{{ (count_info.stdout_lines[-1] | from_json).count }}'}), and could not be converted to an dict.The error was: No JSON object could be decoded\n\nThe error appears to have been in '/home/admin/playbook-3/roles/version_update/tasks/version_update.yml': line 73, 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- debug:\n ^ here\n"}
to retry, use: --limit #/home/admin/playbook-3/version_update.retry
TASK [version_update : count value] ************************************************************************************************************************************
ok: [192.168.27.125] => {
"msg": ""
}
Your last line in the output is not a pure json string (probably bson from your MongoDB output). The error you get is actually coming from the filter itself not getting a correct input and failing.
You will have to translate that to pure json before you can use the from_json filter. The offending data is the ObjectId(\"5d3a1643c43c898d01a3c740\") that cannot be deserialized by the filter. This should be changed in the task/command you use to register your variable. You can have a look at this interesting question on the subject with many answers that will probably give you some clues.
Once this is done, accessing your data becomes easy as you had already figured out. Here is an example with a modified sample data (the way I think you should finally get it) just to confirm your where on the right track.
- name: Get count in json serialized string
hosts: localhost
gather_facts: false
vars:
"count_info":
"stdout_lines": [
"MongoDB shell version v4.0.6",
"connecting to: mongodb://127.0.0.1:27017/configure-db?gssapiServiceName=mongodb",
"Implicit session: session { \"id\" : UUID(\"4bfad3ba-981f-47de-86f9-a1fadbe28e12\") }",
"MongoDB server version: 4.0.6",
"{ \"_id\" : \"someDeserializedId\", \"count\" : 2 }"
]
tasks:
- name: Get count
debug:
msg: "{{ (count_info.stdout_lines[-1] | from_json).count }}"
And the result
PLAY [Get count in json serialized string] ********************************************************************************************************************************************************************************
TASK [Get count] **********************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "2"
}
although the element has the structure of a dictionary, its in fact a string, which i couldnt filter it with to_json or to_nice_json to convert it to a dictionary.
using the below sequence of tasks will get the value you want to pick up, unfortunately i didnt find a way to do it in one task. the logic is as follows:
get the last element from the list, and split the string into key-value substrings, separated by the ,.
parse this list and find the element that contains the keyword count (you can enhance it here if you think the count may appear in other lines too). then with regex, get the numerical value out of it.
PB:
---
- hosts: localhost
gather_facts: false
vars:
final_count_value: -1
count_info:
stdout_lines:
- MongoDB shell version v4.0.6
- 'connecting to: mongodb://127.0.0.1:27017/configure-db?gssapiServiceName=mongodb'
- 'Implicit session: session { "id" : UUID("4bfad3ba-981f-47de-86f9-a1fadbe28e12")
}'
- 'MongoDB server version: 4.0.6'
- '{ "_id" : ObjectId("5d3a1643c43c898d01a3c740"), "count" : 2 }'
tasks:
- name: prepare list var
set_fact:
temp_list: "{{ (count_info.stdout_lines | last).split(', ') | list }}"
- name: find count
set_fact:
final_count_value: "{{ item | regex_replace('\"count\" : ', '') | regex_replace(' }', '') }}"
when: item is search('count')
with_items:
- "{{ temp_list }}"
- name: print result
debug:
var: final_count_value
output:
PLAY [localhost] *******************************************************************************************************************************************************************************************************
TASK [prepare list var] ************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [find count] ******************************************************************************************************************************************************************************************************
skipping: [localhost] => (item={ "_id" : ObjectId("5d3a1643c43c898d01a3c740"))
ok: [localhost] => (item="count" : 2 })
TASK [print result] ****************************************************************************************************************************************************************************************************
ok: [localhost] => {
"final_count_value": "2"
}
UPDATE
to subtract 1 from the result, you should use:
- name: find count and subtract 1
set_fact:
final_count_value: "{{ item | regex_replace('\"count\" : ', '') | regex_replace(' }', '') | int - 1 }}"
when: item is search('count')
with_items:
- "{{ temp_list }}"
hope it helps!.

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.

Resources