ansible-freeipa automember test https://github.com/freeipa/ansible-freeipa/blob/master/tests/automember/test_automember.yml fails with IPA 4.9.4. The error message is automember_add_condition: testgroup: 'objectclass'. The error is not happening if the ldap cache is turned off or is the module is not run within server context. The issue is also not reproducible on the server directly. It is only triggered using the ansible-freeipa module.
automember_add_condition: testgroup: 'objectclass'
fatal: [ipaserver.test.local]: FAILED! => {"changed": false, "failed_when_result": true, "msg": "automember_add_condition: testgroup: 'objectclass'"}
No failure
$ rpm -q freeipa-server freeipa-client ipa-server ipa-client 389-ds-base pki-ca krb5-server freeipa-server-4.9.4-1.fc34.x86_64 freeipa-client-4.9.4-1.fc34.x86_64 package ipa-server is not installed package ipa-client is not installed 389-ds-base-2.0.5-1.fc34.x86_64 pki-ca-10.10.6-1.fc34.noarch krb5-server-1.19.1-3.fc34.x86_64
This is the traceback:
Traceback (most recent call last): File "/tmp/ansible_ipaautomember_payload_za0tz354/ansible_ipaautomember_payload.zip/ansible/modules/ipaautomember.py", line 366, in main File "/tmp/ansible_ipaautomember_payload_za0tz354/ansible_ipaautomember_payload.zip/ansible/module_utils/ansible_freeipa_module.py", line 207, in api_command return api.Command[command](name, **args) File "/usr/lib/python3.9/site-packages/ipalib/frontend.py", line 471, in __call__ return self.__do_call(*args,**options) File "/usr/lib/python3.9/site-packages/ipalib/frontend.py", line 499, in __do_call ret = self.run(*args, **options) File "/usr/lib/python3.9/site-packages/ipalib/frontend.py", line 821, in run return self.execute(*args, **options) File "/usr/lib/python3.9/site-packages/ipaserver/plugins/automember.py", line 417, in execute result = super(automember_add_condition, self).execute(*keys, **options) File "/usr/lib/python3.9/site-packages/ipaserver/plugins/baseldap.py", line 1511, in execute entry_attrs.dn = callback( File "/usr/lib/python3.9/site-packages/ipaserver/plugins/automember.py", line 389, in pre_callback if not isinstance(entry_attrs[regex], (list, tuple)): File "/usr/lib/python3.9/site-packages/ipapython/ipaldap.py", line 516, in __getitem__ return self._get_nice(name) File "/usr/lib/python3.9/site-packages/ipapython/ipaldap.py", line 483, in _get_nice name = self._get_attr_name(name) File "/usr/lib/python3.9/site-packages/ipapython/ipaldap.py", line 479, in _get_attr_name name = self._names[name] File "/usr/lib/python3.9/site-packages/ipapython/ipautil.py", line 656, in __getitem__ return super(CIDict,self).__getitem__(key.lower()) KeyError: 'objectclass'
Here is a shorter version of the test playbook to trigger the issue:
--- - name: Test automember with ldap cache hosts: ipaserver become: true tasks: # CLEANUP TEST ITEMS - name: Ensure group testgroup is absent ipagroup: ipaadmin_password: SomeADMINpassword name: testgroup state: absent - name: Ensure group automember rule testgroup is absent ipaautomember: ipaadmin_password: SomeADMINpassword name: testgroup state: absent automember_type: group # CREATE TEST ITEMS # TESTS - name: Ensure testgroup group is present ipagroup: ipaadmin_password: SomeADMINpassword name: testgroup - name: Ensure testgroup group automember rule is present ipaautomember: ipaadmin_password: SomeADMINpassword name: testgroup description: testgroup automember rule. automember_type: group register: result failed_when: not result.changed or result.failed - name: Change testgroup group automember rule description ipaautomember: ipaadmin_password: SomeADMINpassword name: testgroup description: testgroup automember rule description. automember_type: group register: result failed_when: not result.changed or result.failed - name: Ensure testgroup group automember rule has conditions ipaautomember: ipaadmin_password: SomeADMINpassword name: testgroup automember_type: group inclusive: - key: 'uid' expression: 'uid' - key: 'uidnumber' expression: 'uidnumber' exclusive: - key: 'uid' expression: 'uid' register: result failed_when: not result.changed or result.failed - name: Add testgroup group automember rule member condition ipaautomember: ipaadmin_password: SomeADMINpassword name: testgroup automember_type: group action: member inclusive: - key: 'manager' expression: 'uid=mscott' register: result failed_when: not result.changed or result.failed - name: Ensure testgroup group automember rule has conditions ipaautomember: ipaadmin_password: SomeADMINpassword name: testgroup automember_type: group inclusive: - key: 'uid' expression: 'uid' - key: 'uidnumber' expression: 'uidnumber' - key: 'manager' expression: 'uid=mscott' exclusive: - key: 'uid' expression: 'uid' register: result failed_when: result.changed or result.failed - name: Remove testgroup group automember rule member condition ipaautomember: ipaadmin_password: SomeADMINpassword name: testgroup automember_type: group action: member state: absent inclusive: - key: 'manager' expression: 'uid=mscott' register: result failed_when: not result.changed or result.failed # CLEANUP TEST ITEMS - name: Ensure group testgroup is absent ipagroup: ipaadmin_password: SomeADMINpassword name: testgroup state: absent - name: Ensure group automember rule testgroup is absent ipaautomember: ipaadmin_password: SomeADMINpassword automember_type: group name: testgroup state: absent
Metadata Update from @rcritten: - Issue assigned to rcritten
I think it might be a strange request pattern but it seems to be related to '*' handling in the cache.
Still early, but it looks like the cache thinks that '*' was originally requested when it wasn't so we end up with a cache HIT when all attributes are not available, in this case objectclass.
I figured it out, not sure of the fix yet.
The entry_attrs value has the typical set of user-provided attributes set. In this case the regex option passed in. It looks like:
LDAPEntry(ipapython.dn.DN('cn=testgroup,cn=group,cn=automember,cn=etc,dc=example,dc=test'), {'automemberinclusiveregex': ['uid=uid']}
So then the code pulls the old_entry and looks to see if this is already set somewhere via:
for regex in old_entry.keys():
This is a bit much and breaks the cache because it doesn't have things like objectclass and cn. And it doesn't need them either. This happens because we have a cached value of the entry, so old_entry contains all the attributes, almost none of which are in the temporary new entry.
So the code can be pretty easily fixed by only examining values we care about. And it would be better that way too, perhaps microscopically faster.
But the cache really shouldn't blow up either. It's just not an obvious fix.
If the attribute requested is not there a KeyError is returned. That seems right. But diagnosing this, particularly with Ansible, was not at all easy.
There is a ton of code that relies on this KeyError behavior so this would be non-trivial to change.
I'm going to submit the automember fix for now.
The issue was that the cache returned the entire cached entry regardless of what attributes were requested. So this gave more for the caller to dig through which led to the error.
So instead the cache should create a new entry to return that just contains those attributes that were requested if all the requested attributes exist within the cached entry.
https://github.com/freeipa/freeipa/pull/5860
Metadata Update from @rcritten: - Custom field rhbz adjusted to https://bugzilla.redhat.com/show_bug.cgi?id=1976286
Issue linked to Bugzilla: Bug 1976286
Metadata Update from @rcritten: - Custom field rhbz adjusted to https://bugzilla.redhat.com/show_bug.cgi?id=1976286 https://bugzilla.redhat.com/show_bug.cgi?id=1976288 (was: https://bugzilla.redhat.com/show_bug.cgi?id=1976286)
master:
ipa-4-9:
Metadata Update from @rcritten: - Issue close_status updated to: fixed - Issue status updated to: Closed (was: Open)
Login to comment on this ticket.