with_subelements when subelement is a dictionary - list

Say I have the following dict defined in my yml
st1:
d1:
f1: fv1
f2: fv2
d:
df1: dfv1
df2: dfv2
d2:
f1: fv3
f2: fv4
d:
df1: dfv3
df2: dfv4
I was able to iterate over the above using with_subelements. like this
with_subelements:
- st1
- d
But I get the following error when I run the playbook.
FAILED! => {"msg": "the key d should point to a list, got '{u'df1':
u'dfv1', u'df2': u'dfv2'}'"}
I am using ansible version 2.4
how can I take only values of dict d into a list to get success with the above playbook.
dictsort or dict2items didn't work for me

It's unfortunate that you are stuck with a bad design. Bad designs result in bad code. So here's some bad code:
---
- hosts: localhost
become: no
connection: local
tasks:
- set_fact:
st1_json: "{{ st1 | to_json }}"
- shell: echo '{{ st1_json }}' | jq '.[].d' | grep ':' | cut -d'"' -f4 | tr '\n' ',' | sed -e 's/^/[/' -e 's/,$/]/' -e 's/,/, /g'
register: output
- debug:
msg: "{{ output.stdout }}"
Pretty hideous. But it gets the desired output:
TASK [debug] ************************************************************************************************************************
ok: [localhost] => {
"msg": "[dfv3, dfv4, dfv1, dfv2]"
}
Enjoy.

OK -- I'm not entirely sure what you want for output, but....
I first restructured the yaml file:
---
st1:
- name: d1
f1: fv1
f2: fv2
d:
- df1: dfv1
- df2: dfv2
- name: d2
f1: fv3
f2: fv4
d:
- df1: dfv3
- df2: dfv4
Then, the play looks like this:
- debug:
var: item.1
with_subelements:
- "{{ st1 }}"
- d
The output, then, looks like this:
TASK [debug] **********************************************************************************************************************************
ok: [localhost] => (item=None) => {
"item.1": {
"df1": "dfv1"
}
}
ok: [localhost] => (item=None) => {
"item.1": {
"df2": "dfv2"
}
}
ok: [localhost] => (item=None) => {
"item.1": {
"df1": "dfv3"
}
}
ok: [localhost] => (item=None) => {
"item.1": {
"df2": "dfv4"
}
}

It would help if you give us some expected output. However, you need lists to use with_subelements. If you cannot change the data file, you have to change the playbook. If you want to see all the df1 values, then this will do it:
- debug:
msg: "{{ item.key }}: {{ item.value.d.df1 }}"
with_dict: "{{ st1 }}"
Using your dictionary file, I got this:
TASK [debug] **********************************************************************************************************************************
ok: [localhost] => (item=None) => {
"msg": "d2: dfv3"
}
ok: [localhost] => (item=None) => {
"msg": "d1: dfv1"
}

Related

How to start %index% with 1 in OS::Heat::ResourceGroup

I use %index% in OS::Heat::ResourceGroup and it starts with a 0 value.
I want it to start with the value of 1. How to do it?
resources:
server_group:
type: OS::Heat::ResourceGroup
properties:
count: 3
resource_def:
type: OS::Nova::Server
name: { get_param: [ server_names, '%index%' ] }
I tried with '%index% + 1' but it did not work:
Error return: invalid literal for int() with base 10: '0 + 1'

Getting empty merged list when trying to merge two dict lists with multiple when conditions in Ansible

here are my two list -
listone -
list1":
[
{
"_ref": "LAB1/1/4094",
"vlan_id": 12,
"vlan_name": "test_vlan_1",
"vlan_subnet": "192.168.1.0/28",
"vlan_vrf": "vrf_1"
},
{
"_ref": "LAB2/1/4094",
"vlan_id": 12,
"vlan_name": "test_vlan_1",
"vlan_subnet": "192.168.2.0/28",
"vlan_vrf": "vrf_1"
}
]
secondlist -
"list2":
[
{
"_ref": "LAB1/1/4094",
"vlan_id": "12",
"vlan_name": "test_vlan_1",
"vlan_ref": "vlan/ZG5zLnZsYW4kLmNvbS5pbmZvYmxveC5kbnMudmxhbl92aWV3JElORlJBTEFCLjEuNDA5NC4xMg:LAB1/test_vlan_1/12"
}
]
- name: merge lists final
set_fact:
merged_list: "{{ merged_list|default([]) + [ item[0] | union(item[1]) ] }}"
when: item[0]._ref == item[1]._ref and item[0].vlan_id == item[1].vlan_id and item[0].vlan_name == item[1].vlan_name
loop: "{{ query('nested', list1, list2) }}"
- name: print results
debug:
var: merged_list
I get output as:
TASK [print results] ***********************************************************
ok: [localhost] => {
"merged_list": "VARIABLE IS NOT DEFINED!"
}
desired output: in below, if you notice list2 has a match with list1 first dict item so list2 item merged with list1 first item, in the final output i want merged with a match and also unmatched item of list1 which is second one.
"merged_list":
[
{
"_ref": "LAB1/1/4094",
"vlan_id": 12,
"vlan_name": "test_vlan_1",
"vlan_subnet": "192.168.1.0/28",
"vlan_vrf": "vrf_1",
"vlan_ref": "vlan/ZG5zLnZsYW4kLmNvbS5pbmZvYmxveC5kbnMudmxhbl92aWV3JElORlJBTEFCLjEuNDA5NC4xMg:LAB1/test_vlan_1/12"
},
{
"_ref": "LAB2/1/4094",
"vlan_id": 12,
"vlan_name": "test_vlan_1",
"vlan_subnet": "192.168.2.0/28",
"vlan_vrf": "vrf_1"
}
]
i believe when: item[0]._ref == item[1]._ref and item[0].vlan_id == item[1].vlan_id and item[0].vlan_name == item[1].vlan_name condition is not working as i expected. Any suggestions/clue to make this work and get merged_list as the way i am looking for.
The items in the lists are dictionaries. You need the filter combine to merge them. For example, the playbook below (simplified for testing)
- hosts: localhost
vars:
list1:
- {_ref: ZG5, name: LAB1, vlan_id: 12, vlan_name: test_vlan_1}
- {_ref: XXX, name: LAB2, vlan_id: 12, vlan_name: test_vlan_1}
- {_ref: YYY, name: LAB3, vlan_id: 13, vlan_name: test_vlan_1}
list2:
- {_ref: ZG5, vlan_id: 12, vlan_name: test_vlan_1, vlan_ref: vlan/ZG5}
tasks:
- set_fact:
merged_list: "{{ merged_list|d([]) + [_item] }}"
loop: "{{ query('nested', list1, list2) }}"
vars:
_conditions:
- "{{ item.0._ref == item.1._ref }}"
- "{{ item.0.vlan_id == item.1.vlan_id }}"
- "{{ item.0.vlan_name == item.1.vlan_name }}"
_item: "{{ _conditions is all|ternary(item.0|combine(item.1), item.0) }}"
- debug:
var: merged_list
gives
merged_list:
- {_ref: ZG5, name: LAB1, vlan_id: 12, vlan_name: test_vlan_1, vlan_ref: vlan/ZG5}
- {_ref: XXX, name: LAB2, vlan_id: 12, vlan_name: test_vlan_1}
- {_ref: YYY, name: LAB3, vlan_id: 13, vlan_name: test_vlan_1}

How to compare or lookup specific values from two lists in ansible and print

How to compare two lists in ansible and print desired output below, i have looked other posts in stackoverflow regarding comparing/lookup list , but the way i want desired output is a bit different, unable to figure out the logic to get this working. Please point me to any post that can help me.Thanks
List1:
[
{
"DES": "server1",
"PORT": "E46",
},
{
"DESCRIP": "server2",
"PORT": "E47",
},
{
"DESCRIP": "server3",
"PORT": "E4",
},
{
"DESCRIP": "server4",
"PORT": "E7",
}
]
List2:
[
{
"INTERFACES": [
"E6",
"E8",
"E9",
"E10",
"E11",
"E12",
"E13",
"E14",
"E27",
"E28",
"E37",
"E43",
"E44",
"E45",
"E46",
"E47"
],
"VLAN_ID": "17"
},
{
"INTERFACES": [
"E7",
"E10",
"E11",
"E12",
"E13",
"E14",
"E27",
"E28",
"E45",
"E46"
],
"VLAN_ID": "16"
}
]
desired output:
If list1 PORT value matches/present in list2 INTERFACES then print something like this: server1 E46 has: VLAN_ID: 17 ; VLAN_ID: 16 or server2 E47 has: VLAN_ID: 17 ; NO VLAN_ID: 16
If list1 PORT value dosen't matches/present in list2 INTERFACES then print something like server3 E4 has NO VLAN_ID: 17 NO VLAN_ID: 16
below is full desired print:
server1 E46 has: VLAN_ID: 17 ; VLAN_ID: 16
server2 E47 has: VLAN_ID: 17 ; NO VLAN_ID: 16
server3 E4 has: NO VLAN_ID: 17 ; NO VLAN_ID: 16
server4 E7 has: VLAN_ID: 16 ; NO VLAN_ID: 17
For example
- set_fact:
srv_id: "{{ srv_id|d({})|combine({item.DESCRIP: _id}) }}"
loop: "{{ List1 }}"
vars:
_id: "{{ List2|
selectattr('INTERFACES', 'contains', item.PORT)|
map(attribute='VLAN_ID')|
list }}"
gives
srv_id:
server1: ['17', '16']
server2: ['17']
server3: []
server4: ['16']
(Formatting should be trivial.)

Paws::S3::ListObjectVersions - Call returning empty versions array

I'm trying to get the list of versionIds for an S3 object using Paws::S3::ListObjectVersions.
Sample code:
use Paws;
use Data::Dumper;
my $bucket = '<bucket>';
my $s3 = Paws->service('S3', region => '<region>');
my $s3_object_list = $s3->ListObjects(Bucket => $bucket);
foreach my $s3_object (#{$s3_object_list->Contents}){
print($s3_object->Key."\n");
$s3_object_versions = $s3->ListObjectVersions(Bucket => $bucket, Prefix => $s3_object->Key);
print Dumper($s3_object_versions);
foreach my $s3_object_version (#{$s3_object_versions->Versions}){
print($s3_object_version."\n");
};
}
This kind of works, but it returns an empty list of versions:
$VAR1 = bless( {
'CommonPrefixes' => [],
'Versions' => [],
'_request_id' => '1234567890ABCDEF',
'MaxKeys' => '1000',
'Prefix' => '<prefix>',
'IsTruncated' => 0,
'DeleteMarkers' => [],
'Name' => '<bucket>'
}, 'Paws::S3::ListObjectVersionsOutput' );
When doing the same with Powershell, I get this:
PS > (Get-S3Version -BucketName <bucket> -Prefix <prefix>).Versions
BucketName Key IsLatest VersionId LastModified Size StorageClass
---------- --- -------- --------- ------------ ---- ------------
<bucket> <prefix> True llmRo1gSe4.3ByyXurXodl_wpKlecABw 8/16/2019 10:25:43 AM 198702 STANDARD
<bucket> <prefix> False ZxJzCX5kTHH3MMh.7ZL2E3Tkz.pQOCYw 8/16/2019 10:18:08 AM 198702 STANDARD
Is there something I'm missing when using Paws?
I use Paws under Windows Server 2012R2 with Strawberry Perl 5.30 32bit.

Fn::Sub expression does not resolve to a string

I have created a parameter:
Parameters:
..
list:
Description: "Provide a list .."
Type: CommaDelimitedList
Default: "test1, test2"
Now I want to reference this list (which will resolve in "test1", "test2", ..) from a file in my cloudformation which looks like this:
configure_xx:
files:
/etc/file.conf:
content: !Sub |
input {
logs {
log_group => [ "${list}" ]
access_key_id => "${logstashUserKey}"
secret_access_key => "${logstashUserKey.SecretAccessKey}"
region => "eu-west-1"
}
}
How can I make this work for the parameter list? (the keys work).
error: Fn::Sub expression does not resolve to a string
Just switch the parameter type for a "String"
Parameters:
..
list:
Description: "Provide a list .."
Type: String
Default: "test1, test2"
If, for some reason, you have no control over this parameter type, you could use Fn::Join to transform the list to a string. For exemple:
configure_xx:
files:
/etc/file.conf:
content:
Fn::Sub:
- |-
input {
logs {
log_group => [ "${joinedlist}" ]
access_key_id => "${logstashUserKey}"
secret_access_key => "${logstashUserKey.SecretAccessKey}"
region => "eu-west-1"
}
}
- joinedlist:
Fn::Join:
- ', '
- !Ref list