lvps / 389ds-server

Ansible role to configure 389DS
Apache License 2.0
23 stars 14 forks source link

dirsrv_install_additional_ldif fails on CentOS8 #18

Closed b00ga closed 3 years ago

b00ga commented 3 years ago

Trying to use an LDIF in a demo setup to create some demo users. The Install additional ldif files (dsconf) task fails with dsconf reporting:

Could not open LDIF file "/tmp/users.ldif", errno 2 (No such file or directory)

when I set vars for the role of:

      dirsrv_install_additional_ldif:
        - users.ldif

System info:

[root@hq ~]# uname -a
Linux hq.boulderhill.net 4.18.0-240.22.1.el8_3.x86_64 #1 SMP Thu Apr 8 19:01:30 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
[root@hq ~]# cat /etc/redhat-release 
CentOS Linux release 8.3.2011
[root@hq ~]# ansible --version
ansible 2.9.21
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.6/site-packages/ansible
  executable location = /bin/ansible
  python version = 3.6.8 (default, Aug 24 2020, 17:57:11) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
[root@hq ~]# cat /etc/ansible/roles/lvps.389ds_server/meta/.galaxy_install_info 
{install_date: 'Tue May 25 02:14:12 2021', version: v3.0.2}
b00ga commented 3 years ago

After some debugging, experimentation and googling, I think I found what the issue is thanks largely to Red Hat Bugzilla – Bug 1914554.

In this task: https://github.com/lvps/389ds-server/blob/52f65c76aafa1b3e8ce7b8dfc4333d7b01fd0709/tasks/install_389ds.yml#L46-L54 the LDIF file is copied explicitly to /tmp. However, as noted in the referenced Bugzilla, on EL8, 389ds gets a private /tmp and /var/tmp, so they don't see the main system /tmp where the LDIF has been copied, and in turn causes the No such file or directory error.

If I try to run the same dsconf as this role by hand, but with a relative path to the LDIF, 389ds tries to find it in /var/lib/dirsrv/slapd-default/ldif/ where default is the name of my instance. This seems to be a directory that you can query from the 389ds config:

[root@hq ~]# dsconf config get nsslapd-ldifdir
nsslapd-ldifdir: /var/lib/dirsrv/slapd-default/ldif

Perhaps lookup this value and copy there instead? Or make the LDIF location configurable instead of hard-coded to /tmp perhaps with tmp or ldifdir as a "sane" default?

b00ga commented 3 years ago

Just one more comment with some background on the systemd setting. Here's the template service for dirsrv instances on CentOS8:

[root@hq ~]# cat /usr/lib/systemd/system/dirsrv@.service
# You should not need to edit this file. Instead, use a drop-in file as described in:
#   /usr/lib/systemd/system/dirsrv@.service.d/custom.conf

[Unit]
Description=389 Directory Server %i.
PartOf=dirsrv.target
After=chronyd.service ntpd.service network-online.target
Before=radiusd.service

[Service]
Type=notify
NotifyAccess=all
EnvironmentFile=-/etc/sysconfig/dirsrv
EnvironmentFile=-/etc/sysconfig/dirsrv-%i
PIDFile=/run/dirsrv/slapd-%i.pid
ExecStartPre=/usr/libexec/dirsrv/ds_systemd_ask_password_acl /etc/dirsrv/slapd-%i/dse.ldif
ExecStart=/usr/sbin/ns-slapd -D /etc/dirsrv/slapd-%i -i /run/dirsrv/slapd-%i.pid
PrivateTmp=on

[Install]
WantedBy=multi-user.target

Note that PrivateTmp=on setting. And here's the relevant info from systemd.exec(5):

       PrivateTmp=
           Takes a boolean argument. If true, sets up a new file system namespace for the executed
           processes and mounts private /tmp and /var/tmp directories inside it that is not shared by
           processes outside of the namespace. This is useful to secure access to temporary files of the
           process, but makes sharing between processes via /tmp or /var/tmp impossible. If this is
           enabled, all temporary files created by a service in these directories will be removed after
           the service is stopped.
lvps commented 3 years ago

Thanks for taking the time to investigate this.

I agree with you that the best thing would be to make the directory configurable, but also to have a sane default: I looked up nsslapd-ldifdir in the manual but it seems to be the default output directory for db2ldif, so maybe it's not the most accurate place for additional ldif files?

Anyway, later today I'll try to make it configurable at least, I'll figure out the directory later. Or you can send me a pull request, I'll surely accept it!

lvps commented 3 years ago

I've added a dirsrv_install_additional_ldif_dir variable which defaults to /var/lib/dirsrv/slapd-{{ dirsrv_serverid }}/ldif and made the tasks use it.

I've had lots of problems with tests (they don't run on my machine and resist any attempt at debugging, but they work fine on Travis CI) so I didn't really test this, apart from linting - can you check if it works for you and/or provide me an example ldif file that can be imported in a plain 389DS install? That way I can add the file to the tests. Thanks.

b00ga commented 3 years ago

Hrm. I created an LDIF that has a couple of demo users and it works to apply with ldapmodify (confirmed with ldapsearch and Apache Directory Studio).

I pulled master via my requirements.yml and deployed this LDIF (and I have _dirsrv_installexamples set to true as well). When I deploy with this config and connect to the directory, there don't see to be any entries at all (examples or what I add via LDIF).

I haven't had a chance to verify by trying to run the dsconf command myself manually against the LDIF to see what's going on. I probably won't have time to look at it again until the weekend, but I'll try and assemble a test rig.

b00ga commented 3 years ago

Ok, so I finally had some time to look at this tonight. So I was thinking that I'd be able to provide an LDIF file with changetype: add so add some user entires, and that works with ldapmodify. But I guess LDIF is a file format, and there are lots of things that you can do with an LDIF.

So I think I'm understanding that dsconf backend import is used to import some kind of more detailed DS LDIF, for example as created with dsconf backend export, e.g.

[root@hq ldif]# dsconf -D 'cn=Directory Manager' -W  default backend export userRoot
Enter password for cn=Directory Manager on default: 
The export task has finished successfully
[root@hq ldif]# pwd
/var/lib/dirsrv/slapd-default/ldif
[root@hq ldif]# ls -l
total 4
-rw-------. 1 dirsrv dirsrv 12 Jun  8 02:21 default-userRoot-2021_06_08_02_21_38.ldif

I took one of those exports, then deleted the directory instance (dsctl default remove --do-it), then re-ran your role (adding _dirsrv_install_additionalldif with a copy of the exported LDIF, and commented out my dirsrv_install_examples: true), your role seems to have run successfully (and re-created the example entries that were in the LDIF).

So for the purposes of this issue, I'd say that the LDIF copy/install worked successfully. I tried running dsconf import manually against my "add demo users" LDIF, and it complained and the logs don't like it, even though it works fine with ldapmodify. So I think for what I'm attempting to do, I actually need to use the ansible ldap_entry module (which I think creates it's own LDIFs under the hood to make directory modifications).

So anyway, I'd say success :) Thanks for your time and attention.