On Mon, 08 Aug 2016, Alexander Bokovoy wrote:
Hi!

Attached patch is what is needed to allow external plugins for FreeIPA
framework to be functional if they need to extend a schema.

The idea is that we would have a separate directory as
/usr/share/ipa/schema.d and will allow to use schema (*.ldif) files from
it and its subdirectories during install and upgrade stages.

Without the patch only selected schema files from /usr/share/ipa are
used during install and upgrade. This leads to a failure to install IPA
server (or upgrade it) if a new plugin is added. If plugin defines
managed permissions, upgrade tool will generate ACIs which will fail to
be inserted into LDAP store due to references to missing attributes and
object classes.

The patch adds a directory to be installed and a helper utility that
loads files from the directory and adds them to the list of schema files
used during update of dsinstance and upgrade of the server.

With this patch I'm successfully managed to make FleetCommander
integration plugin completely independent of FreeIPA.
Patch attached now. ;)

--
/ Alexander Bokovoy
From 045c7b38c387c362358d1ac2aa19a6fe07d18be5 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <aboko...@redhat.com>
Date: Fri, 5 Aug 2016 13:04:19 +0300
Subject: [PATCH 3/5] support schema files from third-party plugins

Allow upgrade process to include schema files from third-party plugins
installed in /usr/share/ipa/schema.d/*.schema.

The directory /usr/shar/eipa/schema.d is owned by the server-common
subpackage and therefore third-party plugins should depend on
freeipa-server-common (ipa-server-common) package in their package
dependencies.

Resolves: https://fedorahosted.org/freeipa/ticket/5864
---
 freeipa.spec.in                     |  5 ++++-
 install/configure.ac                |  1 +
 install/share/Makefile.am           |  1 +
 install/share/schema.d/Makefile.am  | 16 ++++++++++++++++
 install/share/schema.d/README       | 14 ++++++++++++++
 ipaplatform/base/paths.py           |  1 +
 ipaserver/install/dsinstance.py     | 15 ++++++++++++++-
 ipaserver/install/server/upgrade.py |  3 +++
 8 files changed, 54 insertions(+), 2 deletions(-)
 create mode 100644 install/share/schema.d/Makefile.am
 create mode 100644 install/share/schema.d/README

diff --git a/freeipa.spec.in b/freeipa.spec.in
index 135e9c9..8acb3fc 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -871,6 +871,8 @@ mkdir -p %{buildroot}%{_sysconfdir}/cron.d
 
 mkdir -p %{buildroot}%{_sysconfdir}/ipa/custodia
 
+mkdir -p %{buildroot}%{_usr}/share/ipa/schema.d
+
 %endif # ONLY_CLIENT
 
 
@@ -1248,7 +1250,8 @@ fi
 %ghost %{_localstatedir}/lib/ipa/pki-ca/publish
 %ghost %{_localstatedir}/named/dyndb-ldap/ipa
 %dir %attr(0700,root,root) %{_sysconfdir}/ipa/custodia
-
+%dir %{_usr}/share/ipa/schema.d
+%attr(0644,root,root) %{_usr}/share/ipa/schema.d/README
 
 %files server-dns
 %defattr(-,root,root,-)
diff --git a/install/configure.ac b/install/configure.ac
index b5f77bf..81f17b9 100644
--- a/install/configure.ac
+++ b/install/configure.ac
@@ -88,6 +88,7 @@ AC_CONFIG_FILES([
     share/advise/Makefile
     share/advise/legacy/Makefile
     share/profiles/Makefile
+    share/schema.d/Makefile
     ui/Makefile
     ui/css/Makefile
     ui/src/Makefile
diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index cd1c164..d8845ee 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -3,6 +3,7 @@ NULL =
 SUBDIRS =                              \
        advise                          \
        profiles                        \
+       schema.d                        \
        $(NULL)
 
 appdir = $(IPA_DATA_DIR)
diff --git a/install/share/schema.d/Makefile.am 
b/install/share/schema.d/Makefile.am
new file mode 100644
index 0000000..0fef87f
--- /dev/null
+++ b/install/share/schema.d/Makefile.am
@@ -0,0 +1,16 @@
+NULL =
+
+SUBDIRS =                              \
+       $(NULL)
+
+appdir = $(IPA_DATA_DIR)/schema.d
+app_DATA = README                      \
+       $(NULL)
+
+EXTRA_DIST =                           \
+       $(app_DATA)                     \
+       $(NULL)
+
+MAINTAINERCLEANFILES =                 \
+       *~                              \
+       Makefile.in
diff --git a/install/share/schema.d/README b/install/share/schema.d/README
new file mode 100644
index 0000000..19e3e68
--- /dev/null
+++ b/install/share/schema.d/README
@@ -0,0 +1,14 @@
+This directory is indended to store schema files for 3rd-party plugins.
+
+Each schema file should be named NN-description.ldif where NN is a number 
00..90.
+
+The schema files from this directory are merged together with the core IPA
+schema files during the run of ipa-server-upgrade utility. Therefore, they are
+also installed when upgrade happens within the process of ipa-server-install.
+
+The directory is installed as /usr/share/ipa/schema.d and is owned by a
+freeipa-server-common package. Therefore, a 3rd-party plugin would need to
+depend on the freeipa-server-common package if it delivers the schema file(s).
+
+You may place your schema files in a subdirectory too, the code that loads
+schema files processes recursively all subdirectories of schema.d.
diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
index b1fedf5..fff55a3 100644
--- a/ipaplatform/base/paths.py
+++ b/ipaplatform/base/paths.py
@@ -354,6 +354,7 @@ class BasePathNamespace(object):
     IPA_CUSTODIA_SOCKET = '/run/httpd/ipa-custodia.sock'
     IPA_CUSTODIA_AUDIT_LOG = '/var/log/ipa-custodia.audit.log'
     IPA_GETKEYTAB = '/usr/sbin/ipa-getkeytab'
+    EXTERNAL_SCHEMA_DIR = '/usr/share/ipa/schema.d'
 
     @property
     def USER_CACHE_PATH(self):
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index c93b3b4..4d372ee 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -28,6 +28,7 @@ import re
 import time
 import tempfile
 import stat
+import fnmatch
 
 import ldap
 
@@ -180,6 +181,16 @@ def get_domain_level(api=api):
     return int(entry.single_value['ipaDomainLevel'])
 
 
+def get_all_external_schema_files(root):
+    """Get all schema files"""
+    f = []
+    for path, subdirs, files in os.walk(root):
+        for name in files:
+            if fnmatch.fnmatch(name, "*.ldif"):
+                f.append(os.path.join(path, name))
+    return f
+
+
 INF_TEMPLATE = """
 [General]
 FullMachineName=   $FQDN
@@ -656,7 +667,9 @@ class DsInstance(service.Service):
         conn.unbind()
 
     def apply_updates(self):
-        data_upgrade = upgradeinstance.IPAUpgrade(self.realm)
+        schema_files = get_all_external_schema_files(paths.EXTERNAL_SCHEMA_DIR)
+        data_upgrade = upgradeinstance.IPAUpgrade(self.realm,
+                                                  schema_files=schema_files)
         try:
             data_upgrade.create_instance()
         except Exception as e:
diff --git a/ipaserver/install/server/upgrade.py 
b/ipaserver/install/server/upgrade.py
index 4342717..2d6b8cb 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1817,6 +1817,9 @@ def upgrade():
     realm = api.env.realm
     schema_files = [os.path.join(ipautil.SHARE_DIR, f) for f
                     in dsinstance.ALL_SCHEMA_FILES]
+
+    schema_files.extend(dsinstance.get_all_external_schema_files(
+                        paths.EXTERNAL_SCHEMA_DIR))
     data_upgrade = IPAUpgrade(realm, schema_files=schema_files)
 
     try:
-- 
2.7.4

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to