I am trying to read a csv file. However, during print its not reading line by line instead its going over some internal loop and duplicating results.
- name: read csv
read_csv:
path: /u00/app/monitor/newrelic_test.csv
key: Application
register: newrelic
- name: Print newrelic var
ansible.builtin.debug:
var: newrelic.list
output looks lke below:
[testserver1] =>
"newrelic.list":
"Application": "Microsoft",
"env": "Test",
"Datacenter": "DC1",
"Hostname": "testserver1",
},
"Application": "Apple",
"env": "Test",
"Datacenter": "DC2",
"Hostname": "testserver2",
}
[testserver2] => {
"newrelic.list":
{
"Application": "Microsoft",
"env": "Test",
"Datacenter": "DC1",
"Hostname": "testserver1",
},
"Application": "Apple",
"env": "Test",
"Datacenter": "DC2",
"Hostname": "testserver2",
}
]
csv file:
Application,env,Datacenter,Hostname
Microsoft,Test,DC1,testserver1
Apple,Test,DC2,testserver2
Expected result shall be:
[testserver1] =>
"newrelic.list":
"Application": "Microsoft",
"env": "Test",
"Datacenter": "DC1",
"Hostname": "testserver1",
}
[testserver2] => {
"newrelic.list":
{
"Application": "Apple",
"env": "Test",
"Datacenter": "DC2",
"Hostname": "testserver2",
}
]
Edit : - Next block
- name: copy template
template:
src: /u00/ansible/Playbooks/files/infra-config.yml_template
dest: /u00/app/monitor/infra-config.yml
loop: "{{ newrelic.list }}"
loop_control:
loop_var: item
Issue: if newrelic.list is not been used then get error as below:
[testserver1]: FAILED! => {"msg": "Invalid data passed to 'loop', it requires a list, got this instead: {'dict':
I tried adding dict2items but then template not able to read items.
The read_csv module doesn't read a CSV file "line by line"; from the documentation:
Read[s] a CSV file and return[s] a list or a dictionary, containing one dictionary per row.
So when you run this task:
- name: read csv
read_csv:
path: data.csv
key: Application
register: newrelic
You get a variable newrelic which has an empty list element and a dict element containing the data from the CSV file, keyed by Application (because that's what you asked for). If use a debug task to look at the value of newrelic, we see:
ok: [localhost] => {
"newrelic": {
"changed": false,
"dict": {
"Apple": {
"Application": "Apple",
"Datacenter": "DC2",
"Hostname": "testserver2",
"env": "Test"
},
"Microsoft": {
"Application": "Microsoft",
"Datacenter": "DC1",
"Hostname": "testserver1",
"env": "Test"
}
},
"failed": false,
"list": []
}
}
It's not clear exactly what you're trying to do here, but if you want to look up values from your CSV file by inventory hostname, you would need to key it by Hostname instead:
- name: read csv
read_csv:
path: data.csv
key: Hostname
register: newrelic
And then you could write:
- name: Print newrelic var
ansible.builtin.debug:
var: newrelic.dict[inventory_hostname]
Assuming you have hosts testserver1 and testserver2 in your inventory, a playbook like this:
- hosts: localhost
gather_facts: false
tasks:
- name: read csv
read_csv:
path: data.csv
key: Hostname
register: newrelic
- hosts: all
gather_facts: false
tasks:
- name: Print newrelic var
ansible.builtin.debug:
var: hostvars.localhost.newrelic.dict[inventory_hostname]
Would result in this output:
PLAY [localhost] ***************************************************************
TASK [read csv] ****************************************************************
ok: [localhost]
PLAY [all] *********************************************************************
TASK [Print newrelic var] ******************************************************
ok: [testserver1] => {
"hostvars.localhost.newrelic.dict[inventory_hostname]": {
"Application": "Microsoft",
"Datacenter": "DC1",
"Hostname": "testserver1",
"env": "Test"
}
}
ok: [testserver2] => {
"hostvars.localhost.newrelic.dict[inventory_hostname]": {
"Application": "Apple",
"Datacenter": "DC2",
"Hostname": "testserver2",
"env": "Test"
}
}
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
testserver1 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
testserver2 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Related
I am trying to execute a playbook for setting up Dell servers and I have some problems with a dictionary in module idrac_redfish_config. I need to enable SOL for a specific user, but for this I want to use a key in the dictionary with a variable because ID of user can be different from server to server.
How I try to add a variable to a dictionary key like this:
- name: Store id test-user
set_fact:
ID: "{{ result.redfish_facts.user.entries | json_query(\"[?UserName=='test-user'].Id\") }}"
- name: Enable SOL for test-user
community.general.idrac_redfish_config:
category: Manager
command: SetManagerAttributes
resource_id: iDRAC.Embedded.1
manager_attributes:
Users.{{ ID[0] }}.SolEnable: "Enabled" <---
Users.{{ ID[0] }}.IpmiLanPrivilege: "Administrator" <---
baseuri: "testhost"
username: "admin"
password: "admin"
I get this error:
TASK [Store id test-user] **************************************************************************************************************************************************************************************
ok: [localhost] => {
"ansible_facts": {
"ID": [
"8"
]
},
"changed": false
}
TASK [Enable SOL for test-user] ********************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {
"changed": false,
"invocation": {
"module_args": {
"baseuri": "testhost",
"category": "Manager",
"command": [
"SetManagerAttributes"
],
"manager_attribute_name": null,
"manager_attribute_value": null,
"manager_attributes": {
"Users.{{ ID[0] }}.IpmiLanPrivilege": "Administrator",
"Users.{{ ID[0] }}.SolEnable": "Enabled"
},
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"resource_id": "iDRAC.Embedded.1",
"timeout": 10,
"username": "admin"
}
},
"msg": "SetManagerAttributes: Manager attribute Users.{{ ID[0] }}.SolEnable not found"
}
If I do this:
manager_attributes: "{
'Users.{{ ID[0] }}.SolEnable': Enabled
'Users.{{ ID[0] }}.IpmiLanPrivilege': Administrator
}"
I get:
fatal: [localhost]: FAILED! => {
"changed": false,
"invocation": {
"module_args": {
"baseuri": "testhost",
"category": "Manager",
"command": [
"SetManagerAttributes"
],
"manager_attributes": "{ 'Users.8.SolEnable': Enabled 'Users.8.IpmiLanPrivilege': Administrator }",
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"resource_id": "iDRAC.Embedded.1",
"timeout": 10,
"username": "admin"
}
},
"msg": "argument manager_attributes is of type <class 'str'> and we were unable to convert to dict: unable to evaluate string as dictionary"
}
I didn't find in Ansible documentation how to do this correctly.
According to documentation, manager_attributes should be a dict of key/value pairs to set on your device. The keys have dots in their names and you cannot "statically" create dynamic key names as you tried above (i.e. "prefix{{ dynamic_value }}suffix": "some content" does not work as you experienced by yourself since the key name does not go through jinja2 templating).
Below is a solution. It's far from being the only one but that's the first that came to my mind and I could setup an example for you quickly. In this case, I create a list of {key: X, value: Y} dicts with your dynamic names as keys and use the items2dict filter to transform this back to a dict itself.
I don't have a network device to play this against so I could not verify that the final result is actually accepted by the module. My example simply uses a debug with your input data to illustrate and outputs a dictionary as the module expects. You will have to tune the exact key names if they are wrong but at least you should be able to move forward.
- name: Dynamic dict
hosts: localhost
gather_facts: false
vars:
ID:
- "8"
my_attributes:
- key: "Users.{{ ID[0] }}.IpmiLandPrivilege"
value: Administrator
- key: "Users.{{ ID[0] }}.SolEnable"
value: Enabled
tasks:
- name: construct a dynamic dict and debug
vars:
manager_attributes: "{{ my_attributes | items2dict }}"
debug:
var: manager_attributes
Which gives:
PLAY [Dynamic dict demo] ***************************************************************************************************************************************************************************************************************
TASK [construct a dynamic dict and debug] **********************************************************************************************************************************************************************************************
ok: [localhost] => {
"manager_attributes": {
"Users.8.IpmiLandPrivilege": "Administrator",
"Users.8.SolEnable": "Enabled"
}
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Edit: An additional (out of many others) example to achieve the same goal. The output is exactly the same as above:
- name: Dynamic dict
hosts: localhost
gather_facts: false
vars:
ID:
- "8"
manager_attributes: "{{
{
'Users.' + ID[0] + '.IpmiLandPrivilege': 'Administrator',
'Users.' + ID[0] + '.SolEnable': 'Enabled'
}
}}"
tasks:
- name: construct a dynamic dict and debug
debug:
var: manager_attributes
I have a list of json objects, that looks something like this
[
{
"apiVersion": "v1",
"count": 11,
"eventTime": null,
"firstTimestamp": "2020-10-20T16:17:08Z",
"lastTimestamp": "2020-10-20T16:30:38Z",
"involvedObject": {
"apiVersion": "v1"
},
"kind": "Event"
},
{
"apiVersion": "v1",
"count": 11,
"eventTime": "2020-10-20T16:17:10.182317Z"
"firstTimestamp": null,
"lastTimestamp": null,
"involvedObject": {
"apiVersion": "v1"
},
"kind": "Event"
}
]
I would like to be able to sort this array by lastTimestamp and if lastTimestamp was not defined by eventTime. Since this does not work with sort - to my knowledge at least, I was thinking about manipulating the array, setting lastTimestamp to eventTime when lastTimestamp is null.
Since I am new to Ansible, I am not sure how to manipulate a list in place in order to archive my goal. Or is there even a way to sort by two attributes?
To sumarize briefly, you don't edit in place in ansible. You manipulate the data to create a new data structure adapted to your need
In your specific case, I don't think there is any other way than using set_fact and looping over your original data to examine each item (i.e. I don't see a solution by simply applying a series of filters on the original data).
The new items in your new list will be obtained by combining the original dict with a dict containing the correct date or an empty one to keep the current date.
Here is a quick example playbook:
---
- name: Process date and sort
hosts: localhost
gather_facts: false
vars:
# Your original data as json on a single line to shorten display
api_events: [{"apiVersion": "v1", "count": 11, "eventTime": null, "firstTimestamp": "2020-10-20T16:17:08Z", "lastTimestamp": "2020-10-20T16:30:38Z", "involvedObject": {"apiVersion": "v1"}, "kind": "Event"}, {"apiVersion": "v1", "count": 11, "eventTime": "2020-10-20T16:17:10.182317Z", "firstTimestamp": null, "lastTimestamp": null, "involvedObject": {"apiVersion": "v1"}, "kind": "Event"}]
tasks:
- name: Process API events to determine time we will use
vars:
new_timestamp: "{{ item.firstTimestamp | ternary({}, {'firstTimestamp': item.eventTime}) }}"
current_event: "{{ item | combine(new_timestamp) }}"
set_fact:
processed_api_events: "{{ processed_api_events | default([]) + [current_event] }}"
loop: "{{ api_events }}"
- name: Show result sorted
debug:
msg: "{{ processed_api_events | sort(attribute='firstTimestamp') }}"
which gives:
PLAY [Process date and sort] ***********************************************************************************************************************************************************************************************************
TASK [Process API events to determine time we will use] ********************************************************************************************************************************************************************************
ok: [localhost] => (item={'apiVersion': 'v1', 'count': 11, 'eventTime': None, 'firstTimestamp': '2020-10-20T16:17:08Z', 'lastTimestamp': '2020-10-20T16:30:38Z', 'involvedObject': {'apiVersion': 'v1'}, 'kind': 'Event'})
ok: [localhost] => (item={'apiVersion': 'v1', 'count': 11, 'eventTime': '2020-10-20T16:17:10.182317Z', 'firstTimestamp': None, 'lastTimestamp': None, 'involvedObject': {'apiVersion': 'v1'}, 'kind': 'Event'})
TASK [Show result sorted] **************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
{
"apiVersion": "v1",
"count": 11,
"eventTime": null,
"firstTimestamp": "2020-10-20T16:17:08Z",
"involvedObject": {
"apiVersion": "v1"
},
"kind": "Event",
"lastTimestamp": "2020-10-20T16:30:38Z"
},
{
"apiVersion": "v1",
"count": 11,
"eventTime": "2020-10-20T16:17:10.182317Z",
"firstTimestamp": "2020-10-20T16:17:10.182317Z",
"involvedObject": {
"apiVersion": "v1"
},
"kind": "Event",
"lastTimestamp": null
}
]
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
I'm trying to extract value of vm datastore with ansible snippet:
- name: Gather disk facts from virtual machine using name
vmware_guest_disk_facts:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
datacenter: "{{ datacenter }}"
validate_certs: no
name: "{{ item }}"
delegate_to: localhost
register: disk_facts
with_items: "{{ vm_list }}"
- name: Get disk info
debug:
var: disk_facts.results.guest_disk_facts.backing_datastore
Output:
[root#sysmgttl1 lvm]# ansible-playbook -i hosts vmfacts.yml -e vcenter_server=vmimgtpw002 -e vm_list=sndprfql8
PLAY [sndprfql8] ***********************************************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************************************
ok: [sndprfql8]
TASK [Gather disk facts from virtual machine using name] *******************************************************************************************************************
ok: [sndprfql8 -> localhost] => (item=sndprfql8)
TASK [Get disk info] *******************************************************************************************************************************************************
ok: [sndprfql8] => {
"disk_facts.results.guest_disk_facts.backing_datastore": "VARIABLE IS NOT DEFINED!"
}
PLAY RECAP *****************************************************************************************************************************************************************
sndprfql8 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
This is what my disk_facts looks like.
ok: [sndprfql8] => {
"disk_facts": {
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"guest_disk_facts": {
"0": {
"backing_datastore": "QADEV07",
"backing_eagerlyscrub": false,
"backing_filename": "[QADEV07] sndprfql8/sndprfql8.vmdk",
"backing_thinprovisioned": true,
"backing_type": "FlatVer2",
"backing_uuid": "6000C292-7716-6296-de04-69bac9186661",
"backing_writethrough": false,
"capacity_in_bytes": 68719476736,
"capacity_in_kb": 67108864,
"controller_key": 1000,
"key": 2000,
"label": "Hard disk 1",
"summary": "67,108,864 KB",
"unit_number": 0
}
},
"invocation": {
"module_args": {
"datacenter": "RDC",
"folder": null,
"hostname": "vmimgtpw002",
"name": "sndprfql8",
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"port": 443,
"use_instance_uuid": false,
"username": "svcvread#chop.edu",
"uuid": null,
"validate_certs": false
}
},
"item": "sndprfql8"
}
]
}
}
If this is really for a one shot use, the following should do:
- name: Get disk info
debug:
var: disk_facts.results[0].guest_disk_facts['0'].backing_datastore
If you goal is to get all values for a list of vms in the result possibly having several disks, the following will give you a flattened list (that you can de-duplicate with the unique filter if needed)
- debug:
msg: "{{ disk_facts | json_query('results[].guest_disk_facts.*[].backing_datastore') }}"
I've got multiple values under mounts, I want to have all 'mountpoints' of these attributes.
"mounts": {
"/dev/sdb": {
"fstype": "xfs",
"mountpoint": "/my/point1",
"opts": "defaults,_netdev",
"partition": "/dev/sdb1",
"state": "mounted"
},
"/dev/sdc": {
"fstype": "xfs",
"mountpoint": "/my/point2",
"opts": "defaults,_netdev",
"partition": "/dev/sdc1",
"state": "mounted"
},
"/dev/sdd": {
"fstype": "xfs",
"mountpoint": "/my/point3",
"opts": "defaults,_netdev",
"partition": "/dev/sdd1",
"state": "mounted"
How do I register the three mountpoints in memory for later use, so I get:
/my/point1, /my/point2, /my/point3
I want to place the values in /etc/updatedb.conf with lineinfile, so there should be no spacing.
My end result would look like; cat /etc/updatedb.conf
PRUNEPATHS = "/my/point1 /my/point2 /my/point3"
Currently, I use a template to copy pre-defined variables. But this is not dynamic enough.
I'm playing around how to get the right variables, but no success:
- debug: var=mount[all].mountpoints
To get a list:
- debug: msg="{{ mounts.values() | map(attribute='mountpoint') | list }}"
Or a string:
- debug: msg="{{ mounts.values() | map(attribute='mountpoint') | list | join(' ') }}"
EDIT:
You can get the join of the keys from mounts like this:
mounts: {{ mounts.keys()|join(', ') }}
(old answer that is not valid for this question)
as this describes, you can do
---
- hosts: all
tasks:
- set_fact: mounts={{ ansible_mounts | map(attribute='device')|join(',')}}
- debug: var=ansible_mounts
- debug: var=mounts
sample output
ap test.yml -i hosts -l server
PLAY [all] *********************************************************************
TASK [setup] *******************************************************************
ok: [server]
TASK [set_fact] ****************************************************************
ok: [server]
TASK [debug] *******************************************************************
ok: [server] => {
"ansible_mounts": [
{
"device": "/dev/sda1",
"fstype": "ext4",
"mount": "/",
"options": "rw,errors=remount-ro",
"size_available": 2890289152,
"size_total": 9376751616,
"uuid": "N/A"
},
{
"device": "/dev/sdb1",
"fstype": "ext4",
"mount": "/mnt/data1",
"options": "rw",
"size_available": 50684461056,
"size_total": 200674758656,
"uuid": "N/A"
}
]
}
TASK [debug] *******************************************************************
ok: [server] => {
"mounts": "/dev/sda1,/dev/sdb1"
}
PLAY RECAP *********************************************************************
server : ok=4 changed=0 unreachable=0 failed=0
I am playing with ansible to automate ec2 instances. I created ec2 instance and then m trying to get its public dns name via ec2_remote_facts module. but it is giving variable not defined in output.
playbook:
- hosts: localhost
connection: local
tasks:
- name: ec2 instance facts
ec2_remote_facts:
region: ap-southeast-2
filters:
instance-state-name: running
register: ec2
- debug: var=ec2.instances.public_name
Output:PLAY [localhost] ***************************************************************
TASK [setup] *******************************************************************
ok: [localhost]
TASK [create ec2 instance] *****************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"ec2.instances.public_name": "VARIABLE IS NOT DEFINED!"
}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
Output for ec2.instances.
ok: [localhost] => {
"ec2.instances": [
{
"ami_launch_index": "0",
"architecture": "x86_64",
"client_token": "",
"ebs_optimized": false,
"groups": [
{
"id": "sg-6c016a08",
"name": "default"
}
],
"hypervisor": "xen",
"id": "i-915b1813",
"image_id": "ami-fedafc9d",
"instance_profile": null,
"interfaces": [
{
"id": "eni-96de4acf",
"mac_address": "0a:14:ac:64:c4:13"
}
],
"kernel": null,
"key_name": "ansible.key",
"launch_time": "2016-08-29T07:32:10.000Z",
"monitoring_state": "disabled",
"persistent": false,
"placement": {
"tenancy": "default",
"zone": "ap-southeast-2c"
},
"private_dns_name": "ip-xx-xx-xx-107.ap-southeast-2.compute.internal",
"private_ip_address": "xx.xx.xx.107",
"public_dns_name": "ec2-xx-xxx-xx-80.ap-southeast-2.compute.amazonaws.com",
"ramdisk": null,
"region": "ap-southeast-2",
"requester_id": null,
"root_device_type": "ebs",
"source_destination_check": "true",
"spot_instance_request_id": null,
"state": "running",
"tags": {
"Name": "Demo"
},
"virtualization_type": "hvm",
"vpc_id": "vpc-abcaf4ce"
}
]
}
what i m missing here?
Thanks
Benjo
If you look closely to ec2.instances you may note that:
it is a list, so you either access items by index ec2.instances[0] or iterate over them with with_items: structure.
there is no public_name attribute, only public_dns_name.