'dict object' has no attribute....

I’ve been working this issue for a week now. The code used to work perfectly and now it fails. Here is the error I get:

The task includes an option with an undefined variable. The error was: {‘CentOS’: ‘{{ iptables_directory[ansible_distribution] }}/iptables’,
‘Rocky’: ‘{{ iptables_directory[ansible_distribution] }}/iptables’, ‘Debian’: ‘{{ iptables_directory[ansible_distribution] }}/rules.v4’,
‘Ubuntu’: ‘{{ iptables_directory[ansible_distribution] }}/rules.v4’}: ‘dict object’ has no attribute ‘Debian’. ‘dict object’ has no attribute ‘Debian’.

The error appears to be in ‘/work/armory/roles/xxx/tasks/xxx.yml’: line 266, column 3, but may be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:

  • name: Save new iptables - IPv4
    ^ here

I’ve been working this issue for a week now. The code used to work perfectly and now it fails. Here is the error I get:

Logic dictates that something has changed. Did you upgrade anything? Or otherwise make changes?
That would be the obvious thing to check for you.

I get a similar error when I target CentOS 9.

Similar means that it is different. What is the actual error there?

ansible-core 2.14.3
python 3.11.2
jinja version = 3.1.2

default.yml is being read in as I refer to other variables in the same file. Can anyone see an error that I’ve missed?

Where does this file reside? I.e. how is it “being read in”?

When I target CentOS I get this error:

The task includes an option with an undefined variable. The error was: {‘CentOS’: ‘{{ iptables_directory[ansible_distribution] }}/iptables’,
‘Rocky’: ‘{{ iptables_directory[ansible_distribution] }}/iptables’, ‘Debian’: ‘{{ iptables_directory[ansible_distribution] }}/rules.v4’,
‘Ubuntu’: ‘{{ iptables_directory[ansible_distribution] }}/rules.v4’}: ‘dict object’ has no attribute ‘CentOS’. ‘dict object’ has no attribute ‘CentOS’.

The error appears to be in ‘/work/armory/roles/xxx/tasks/xxx.yml’: line 266, column 3, but may be elsewhere in the file depending on the exact syntax problem.

Default.yml is at the playbook level in a folder called group_vars. It is being read in by my playbook like this:

vars_files:

  • group_vars/default.yml

Does the same thing happen for all distros? Or only for Debian/CentOS, and not for Rocky/Ubuntu?

Hey Kathy,

I’ve been trying to reproduce the problem without success. However, I think you’ve got one level of indirection too many going on. You have

iptables_directory:
  CentOS: "/etc/sysconfig"
  Fedora: "/etc/sysconfig"
  Rocky: "/etc/sysconfig"
  Debian: "/etc/iptables"
  Ubuntu: "/etc/iptables"
iptables_v4_rules:
  CentOS: "{{ iptables_directory[ansible_distribution] }}/iptables"
  Fedora: "{{ iptables_directory[ansible_distribution] }}/iptables"
  Rocky: "{{ iptables_directory[ansible_distribution] }}/iptables"
  Debian: "{{ iptables_directory[ansible_distribution] }}/rules.v4"
  Ubuntu: "{{ iptables_directory[ansible_distribution] }}/rules.v4"

(I added “Fedora” because that’s what I’m testing on; otherwise this doesn’t work at all.)

But, surly, the iptables_v4_rules[‘Rocky’] value is not going to change if I’m running on “Debian”? The way its written, if I’m on a Debian host, all of the iptables_v4_rules values will be “/etc/iptables/rules.v4”.

I think what it should be is this:

iptables_directory:
  CentOS: "/etc/sysconfig"
  Fedora: "/etc/sysconfig"
  Rocky: "/etc/sysconfig"
  Debian: "/etc/iptables"
  Ubuntu: "/etc/iptables"
iptables_v4_rules:
  CentOS: "{{ iptables_directory['CentOS'] }}/iptables"
  Fedora: "{{ iptables_directory['Fedora'] }}/iptables"
  Rocky: "{{ iptables_directory['Rocky'] }}/iptables"
  Debian: "{{ iptables_directory['Debian'] }}/rules.v4"
  Ubuntu: "{{ iptables_directory['Ubuntu'] }}/rules.v4"

In any case, it looks like somehow you’ve tricked the “lazy evaluation” engine to be even more lazy than it’s supposed to be, because it looks like it isn’t resolving the templates in the values. Not sure how you’ve managed that, but I’d really like to know!

Hope this helps. Cheers,

If ‘group_vars’ is adjacent to your playbook, then ‘group_vars/default.yml’ would also load if the host is in a group called ‘default’.
So this file name/location is a bit ambiguous.

In any case I would only use the ‘vars_files’ statement for files that are not automatically loaded.
So I would remove the vars_files statement from your playbook and then rename the vars file to ‘group_vars/all.yml’.

Or create a dir ‘group_vars/all’ and move it there: ‘group_vars/all/default.yml’ (or main.yml, doesn’t matter)

When I make Todd’s changes, I get the same original error EXCEPT it tells me CentOS is not a dict, even though I am targeting a Debian box.

Dick, are you saying that the file all.yml in the group_vars folder does not need to be explicitly stated in my playbook?

The error appears to be in ‘/work/armory/roles/xxx/tasks/xxx.yml’: line 266, column 3, but may be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

  • name: Save new iptables - IPv4
    ^ here

The error is being reported by a role.

Is the group_vars/default.yml being sourced by the role, or by the playbook that invokes the role? How are you invoking the role?

Walter

Yes.
It sounds like the vars file is somehow used twice, which I think (after Todd’s comment) may screw up the level of laziness.
(speculation on my side, but let’s see)

This bears repeating. I know I missed it the first few times I was told, and then the light came on.

  • All hosts are in the “all” group. (That much I got the first time. :slight_smile:

  • Any files or directories in ./group_vars/ that match a host’s group names – including “all” – get loaded for that host. It was the “or directories” part I didn’t appreciate at first. For example, if a host is in the “foo” group, then the files ./group_vars/foo, or better, ./group_vars/foo.yml (the former won’t be ansible-linted; the latter will be) get loaded for that host. But more than that, if ./group_vars/foo/ is a directory, then all the files within ./group_vars/foo/ get loaded for all hosts in the foo group.

  • That works even for groups that don’t exist when the playbook starts but are created on-they-fly by, for example, the ansible.builtin.group_by module. This allows you to have amazingly crazy ad hoc groups – like “hosts the CEO has logged into in the last 30 minutes” – and still use relevant ./group_vars/ files in a straightforward way.

We suffered a bit initially because in some of our projects different competing interests clashed over ownership of the ./group_vars/all.yml file. When we realized we could have files ./group_vars/all/interest_aaa.yml, ./group_vars/all/interest_bbb.yml, ./group_vars/all/interest_ccc.yml, ./group_vars/all/interest_ddd.yml, etc., then the competition for that namespace became cooperation, and things just got much easier.

Todd- thank you for clearing that up for me

I made default.yml all.yml amd reran things with the same errors.

I am running my roles from within a playbook like this.

  • roles

  • role1
    become: true

  • role2
    become: true

Do you still have that vars_files: thing? As Dick suggested, it feels like that file is getting loaded more than once, and you don’t want that.

Is it at all possible that variables iptables_v4_rules and/or iptables_directory are being set anywhere else?

[If you want to toss the whole thing in a private repo that I can clone, or some other way get to me, I’m willing to take a look; I’m really curious to know how this is happening.]

I removed the vars_file from my playbook.

I just double-checked and I am not loading iptables_v4_rules and/or iptables_directory twice…

I wish I could throw it into a repo but this is on a non-Internet connected device and can’t be moved off.

I’ve moved from curious to frustrated.

What if you don’t place the vars file in a groups_vars subdirectory. What if you place it in the directory of the playbook that runs the roles.

vars_files:

  • my_vars.yml

Where my_vars.yml exists next to the playbook?

Walter