The specific error, "'list objec' has no attribute 'address'", is pretty
clear. You're trying to take some short-cuts with your data
manipulation, and Ansible can't read your mind wrt what you're really
trying to accomplish. Your intuition is correct though, that this is not
so much an issue with the module but rather a data manipulation problem.
I think I understand what you want, though. In fact, I wrote a filter
years ago to avoid repeating data in similar circumstances. I've put off
responding, partly because I had hoped to see what some of the regulars
around ansible-project proposed, and partly because it'd be kind of
crazy to suggest incorporating my filter into your project. However,
no-one has responded yet, and the more I look at your problem the more
it feels like this might be the shortest path to a workable solution.
Before I present my toy playbook, let me just say that you've thrown
some real brain-benders at me with this data, embedding some fields
within others and, if you /really/ want DRY (don't repeat yourself) even
throwing in a dig with deferred Jinja2 evaluation. Ouch! Even still, I
think the result, which can all go into a single vars section, is more
maintainable that a bunch of set_fact tasks doing obscure Jinja2 tricks.
Enough qualifiers. Here's my toy playbook:
---
- name: Abstracting loop items
hosts: localhost
tasks:
- name: Debug some data manips
ansible.builtin.debug:
msg: "{{ kcl }}"
vars:
__kcl:
pw_crypt: scram-sha-256
conntype: host
db: keycloak
polymac:
- - ip: 172.27.130.214 # "10.4.253.146"
role: keycloak
- ip: 172.27.130.215
role: eycloakk
pw_crypt: cleartext
- ip: 172.27.130.216
role: ycloakke
- ip: 172.27.130.217
role: cloakkey
- address: '%ip%/32'
fqdn: "{{ '{' ~ '{' }} lookup('community.general.dig', '%ip%/PTR') |
trim('.') }}"
comment: "%role% - {{ '{' ~ '{' }} lookup('community.general.dig',
'%ip%/PTR') | trim('.') }}"
database: "%db%%role%"
pw_crypt: "%pw_crypt%"
kcl: "{{ lookup('items', __kcl | polymac ) }}"
And here's the output:
TASK [Debug some data manips] ***************************************
ok: [localhost] => {
"msg": [
{
"address": "172.27.130.214/32",
"comment": "keycloak - itvpn-214.vpn.my.org",
"conntype": "host",
"database": "keycloakkeycloak",
"db": "keycloak",
"fqdn": "itvpn-214.vpn.my.org",
"pw_crypt": "scram-sha-256"
},
{
"address": "172.27.130.215/32",
"comment": "eycloakk - itvpn-215.vpn.my.org",
"conntype": "host",
"database": "keycloakeycloakk",
"db": "keycloak",
"fqdn": "itvpn-215.vpn.my.org",
"pw_crypt": "cleartext"
},
{
"address": "172.27.130.216/32",
"comment": "ycloakke - itvpn-216.vpn.my.org",
"conntype": "host",
"database": "keycloakycloakke",
"db": "keycloak",
"fqdn": "itvpn-216.vpn.my.org",
"pw_crypt": "scram-sha-256"
},
{
"address": "172.27.130.217/32",
"comment": "cloakkey - itvpn-217.vpn.my.org",
"conntype": "host",
"database": "keycloakcloakkey",
"db": "keycloak",
"fqdn": "itvpn-217.vpn.my.org",
"pw_crypt": "scram-sha-256"
}
]
}
The polymac filter is available in a gist on github at
https://gist.github.com/utoddl/fc303d5b9dcad58871d2956cfed0aa68.
Some explanation is in order. Lots, in fact. "polymac" is both a filter,
and a key in the __kcl dict. The filter looks for such eponymous keys to
find its instructions regarding how the dict should be transformed. Each
polymac key (there can be more than one) contains a list. The first item
defines one or more sets of "input" data. In this case, it's four sets
of data, and each of those contains an "ip" and a "role". Note that one
of them also contains a "pw_crypt" string of value "cleartext". More on
that later.
So, that's polymac[0] described. Subsequent elements of the polymac list
(in this case there is only one) contain templates for the output dicts.
In this example, the sole template dict contains five field definitions:
"address", "fqdn", "comment", "database", and "pw_crypt". However, if
you look at the output, each resulting dict contains seven attributes,
not five. These additional attributes are the three siblings of the
original "polymac" key: "pw_crypt", "conntype", and "db", and they act
as defaults for all the generated dicts. Note that one of these
attributes, "pw_crypt" is also in the sole template dict where it has
the value "%pw_crypt%".
Notice that the output dicts contain all the keys that are siblings of
"polymac" and all the keys in the template(s). The output dicts however
do not contain attributes corresponding to the "input" keys, i.e. those
contained at some level within polymac[0].
You've probably figured out by now that template values containing
"input" keys or "sibling" keys sandwiched between percent signs get
those parts of their strings substituted by the indicated "input" or
"sibling" values. This is how, for example, "address: '%ip%/32'" becomes
the "input" dict's "ip" value with "/32" concatenated to it.
Remember that one "input" dict that contains "pw_crypt: 'cleartext'"?
For the corresponding output dict, 'cleartext' takes precedence over the
"sibling" value of "scram-sha-256". For all the others, the "sibling"
value acts as a default.
That pretty much covers "polymac" for this example. The rest is an
exploration of generating and forcing evaluation of Jinja2 expressions
within strings. Consider what's going on with
fqdn: "{{ '{' ~ '{' }} lookup('community.general.dig', '%ip%/PTR') | trim('.')
}}"
The first part of that expression - the bit between the opening and
closing mustaches - actually creates another opening mustache! In the
mean time, the "%ip%" gets the relevant IPv4 address inserted. So on the
very last line of the example playbook, "__kcl | polymac" produces a
list of dicts, but where the fqdn should be, there is instead "{{
lookup('community.general.dig', '172.27.130.214/PTR') | trim('.') }}"
for example. In fact, it's in each output dict twice. (I tried to work
around that, but life is short enough! Left as an exercise for the reader.)
The final bit then is feeding the entire list of dicts with embedded
Jinja2 to the "items" lookup. This has the necessary effect of
evaluating all the embedded Jinja2 expressions while copying the list to
create "kcl". Note that it's "kcl" rather than "__kcl" that the debug
task prints.
That's how /I/ would handle this problem, but I wrote and can support
the polymac filter for my own purposes. Whether anyone else should
consider it is up to them, but at least you're aware of the possibility.
Good luck, and let us know how you get on.
--
Todd
On 6/27/23 2:51 AM, dulhaver via Ansible Project wrote:
I want to create pg_hba.conf entries with the
community.postgresql.postgresql_pg_hba module. I think generally my issue here
is not releated to how that module works though
I can do this with a TASK like the below ...
*******************************************************************************************************
name: create pg_hba entries
community.postgresql.postgresql_pg_hba:
state: present
address: "{{ item.address }}"
databases: "{{ item.databases }}"
contype: "{{ item.contype }}"
users: "{{ item.users }}"
method: "{{ item.method }}"
comment: "{{ item.comment }}"
backup: true
backup_file: /opt/db/data/postgres/data/pg_hba.conf.bak
dest: /opt/db/data/postgres/data/pg_hba.conf
keep_comments_at_rules: true
become: true
loop:
- { address: "10.250.111.53/32", databases: 'keycloak', contype: "host", users: "keycloak",
method: "scram-sha-256", comment: " Keycloak @10.250.111.53 - created by Ansible" }
- { address: "10.250.111.54/32", databases: 'keycloak', contype: "host", users:
"someone_else", method: "scram-sha-256", comment: " someonle else @10.250.111.54 - created by
Ansible" }
*******************************************************************************************************
... but need to make this more abstract, so I do not have to provide all those
values (there will be n amount of entries in the same manner) in the TASK
itself but get this gathered into a centralized defaults file. ALso the amount
of entries to be created can be 2, or 5 or n.
I try to achive this with 2 components
*** 1. a defaults file
********************************************************************************
kcl_ip:
- "10.4.253.146/32"
kcl_fqdn: VM-413426-0045.step.zrz.dvz.cn-mv.de
kcl_pw_crypt: scram-sha-256
kcl_conntype: host
kcl_db: keycloak
kcl_role:
- keycloak
kcl_comment:
- "keycloak - {{ kcl_fqdn.0 }}"
kcl_hba_entries:
- { address: "{{ kcl_ip.0 }}", databases: "{{ kcl_db }}", contype: "{{ kcl_conntype }}", users:
"{{ kcl_role.0 }}", method: "{{ kcl_pw_crypt }}", comment: "{{ kcl_comment.0 }}" }
*** 2. an adjusted TASK
*******************************************************************************
- name: create pg_hba entries
community.postgresql.postgresql_pg_hba:
state: present
address: "{{ kcl_hba_entries.address }}"
databases: "{{ kcl_hba_entries.databases }}"
contype: "{{ kcl_hba_entries.contype }}"
users: "{{ kcl_hba_entries.users }}"
method: "{{ kcl_hba_entries.method }}"
comment: "{{ kcl_hba_entries.comment }}"
backup: true
backup_file: /opt/db/data/postgres/data/pg_hba.conf.bak
dest: /opt/db/data/postgres/data/pg_hba.conf
keep_comments_at_rules: true
become: true
*******************************************************************************************************
So I wanted to add a couple of lines to kcl_hba_entries and hope that
(depending on the amount of entries I have in kcl_ip, kcl_role, ... ) it shoudl
produce one, or 4 or n entries to the pg_hba.conf file
this does not work unfortunately
*******************************************************************************************************
TASK [eakte_postgres_config : create pg_hba entries]
**************************************************
task path:
/home/gwagner/repos/automation_postgres/roles/eakte_postgres_config/tasks/config_keycloak.yml:55
fatal: [VM-413426-0048.step.zrz.dvz.cn-mv.de]: FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was:
'list object' has no attribute 'address'\n\nThe error appears to be in
'/home/gwagner/repos/automation_postgres/roles/eakte_postgres_config/tasks/config_keycloak.yml':
line 55, 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: create pg_hba entries\n ^ here\n"
}
*******************************************************************************************************
I am probably having some sort of problem with the logic in general. Can
anybody kindly advise, what my problem may be caused by?
--
You received this message because you are subscribed to the Google Groups "Ansible
Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/ansible-project/e87b23e1-2972-2e4c-1052-75369c3d82c4%40gmail.com.