e3ffab
From cc256391c89c9d8d7c8ae9e1ce647396cded0674 Mon Sep 17 00:00:00 2001
e3ffab
From: Jan Cholasta <jcholast@redhat.com>
e3ffab
Date: Mon, 1 Dec 2014 12:12:15 +0000
e3ffab
Subject: [PATCH] Improve validation of --instance and --backend options in
e3ffab
 ipa-restore
e3ffab
e3ffab
https://fedorahosted.org/freeipa/ticket/4744
e3ffab
e3ffab
Reviewed-By: David Kupka <dkupka@redhat.com>
e3ffab
---
e3ffab
 ipaplatform/base/paths.py        |  2 +-
e3ffab
 ipaserver/install/ipa_backup.py  |  2 +-
e3ffab
 ipaserver/install/ipa_restore.py | 73 ++++++++++++++++++++++++----------------
e3ffab
 3 files changed, 46 insertions(+), 31 deletions(-)
e3ffab
e3ffab
diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
e3ffab
index e28147ab4aa1faa3859c38665a83f57fb67e96b2..8bfab1bc92f79b5e76555b35a8b646e1ff56f84b 100644
e3ffab
--- a/ipaplatform/base/paths.py
e3ffab
+++ b/ipaplatform/base/paths.py
e3ffab
@@ -261,7 +261,7 @@ class BasePathNamespace(object):
e3ffab
     VAR_LIB_DIRSRV_INSTANCE_SCRIPTS_TEMPLATE = "/var/lib/dirsrv/scripts-%s"
e3ffab
     VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE = "/var/lib/dirsrv/slapd-%s"
e3ffab
     SLAPD_INSTANCE_BACKUP_DIR_TEMPLATE = "/var/lib/dirsrv/slapd-%s/bak/%s"
e3ffab
-    IPACA_DIRSRV_INSTANCE_DB_TEMPLATE = "/var/lib/dirsrv/slapd-%s/db/ipaca"
e3ffab
+    SLAPD_INSTANCE_DB_DIR_TEMPLATE = "/var/lib/dirsrv/slapd-%s/db/%s"
e3ffab
     SLAPD_INSTANCE_LDIF_DIR_TEMPLATE = "/var/lib/dirsrv/slapd-%s/ldif"
e3ffab
     VAR_LIB_SLAPD_PKI_IPA_DIR_TEMPLATE = "/var/lib/dirsrv/slapd-PKI-IPA"
e3ffab
     VAR_LIB_IPA = "/var/lib/ipa"
e3ffab
diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py
e3ffab
index 5d583f7e9186f20ebe8187ba70db28de0c255ae7..72d1475d6db92b6b9e715afdae85d169a036c085 100644
e3ffab
--- a/ipaserver/install/ipa_backup.py
e3ffab
+++ b/ipaserver/install/ipa_backup.py
e3ffab
@@ -292,7 +292,7 @@ class Backup(admintool.AdminTool):
e3ffab
 
e3ffab
             for instance in [realm_to_serverid(api.env.realm), 'PKI-IPA']:
e3ffab
                 if os.path.exists(paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % instance):
e3ffab
-                    if os.path.exists(paths.IPACA_DIRSRV_INSTANCE_DB_TEMPLATE % instance):
e3ffab
+                    if os.path.exists(paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % (instance, 'ipaca')):
e3ffab
                         self.db2ldif(instance, 'ipaca', online=options.online)
e3ffab
                     self.db2ldif(instance, 'userRoot', online=options.online)
e3ffab
                     self.db2bak(instance, online=options.online)
e3ffab
diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py
e3ffab
index 9cb978a516f4f85307735b7428f6053461061022..097703938a7ba3820f4acae2148760146464fa08 100644
e3ffab
--- a/ipaserver/install/ipa_restore.py
e3ffab
+++ b/ipaserver/install/ipa_restore.py
e3ffab
@@ -188,15 +188,35 @@ class Restore(admintool.AdminTool):
e3ffab
         self.log.info("Preparing restore from %s on %s",
e3ffab
             self.backup_dir, api.env.host)
e3ffab
 
e3ffab
-        if not options.instance:
e3ffab
-            instances = []
e3ffab
-            for instance in [realm_to_serverid(api.env.realm), 'PKI-IPA']:
e3ffab
-                if os.path.exists(paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % instance):
e3ffab
-                    instances.append(instance)
e3ffab
+        if options.instance and options.backend:
e3ffab
+            database = (options.instance, options.backend)
e3ffab
+            if not os.path.exists(paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE %
e3ffab
+                                  database):
e3ffab
+                raise admintool.ScriptError(
e3ffab
+                    "Instance %s with backend %s does not exist" % database)
e3ffab
+
e3ffab
+            databases = [database]
e3ffab
         else:
e3ffab
-            instances = [options.instance]
e3ffab
-        if options.data_only and not instances:
e3ffab
-            raise admintool.ScriptError('No instances to restore to')
e3ffab
+            if options.instance:
e3ffab
+                instances = [options.instance]
e3ffab
+            else:
e3ffab
+                instances = [realm_to_serverid(api.env.realm), 'PKI-IPA']
e3ffab
+
e3ffab
+            if options.backend:
e3ffab
+                backends = [options.backend]
e3ffab
+            else:
e3ffab
+                backends = ['userRoot', 'ipaca']
e3ffab
+
e3ffab
+            databases = []
e3ffab
+            for instance in instances:
e3ffab
+                for backend in backends:
e3ffab
+                    database = (instance, backend)
e3ffab
+                    if os.path.exists(paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE %
e3ffab
+                                      database):
e3ffab
+                        databases.append(database)
e3ffab
+
e3ffab
+            if options.data_only and not databases:
e3ffab
+                raise admintool.ScriptError('No instances to restore to')
e3ffab
 
e3ffab
         create_ds_user()
e3ffab
         pent = pwd.getpwnam(DS_USER)
e3ffab
@@ -223,7 +243,7 @@ class Restore(admintool.AdminTool):
e3ffab
             # These two checks would normally be in the validate method but
e3ffab
             # we need to know the type of backup we're dealing with.
e3ffab
             if (self.backup_type != 'FULL' and not options.data_only and
e3ffab
-                not instances):
e3ffab
+                not databases):
e3ffab
                 raise admintool.ScriptError('Cannot restore a data backup into an empty system')
e3ffab
             if (self.backup_type == 'FULL' and not options.data_only and
e3ffab
                 (options.instance or options.backend)):
e3ffab
@@ -244,6 +264,15 @@ class Restore(admintool.AdminTool):
e3ffab
                     not user_input("Continue to restore?", False)):
e3ffab
                     raise admintool.ScriptError("Aborted")
e3ffab
 
e3ffab
+            self.extract_backup(options.gpg_keyring)
e3ffab
+
e3ffab
+            for database in databases:
e3ffab
+                ldifname = '%s-%s.ldif' % database
e3ffab
+                ldiffile = os.path.join(self.dir, ldifname)
e3ffab
+                if not os.path.exists(ldiffile):
e3ffab
+                    raise admintool.ScriptError(
e3ffab
+                        "Instance %s with backend %s not in backup" % database)
e3ffab
+
e3ffab
             # Big fat warning
e3ffab
             if  (not options.unattended and
e3ffab
                 not user_input("Restoring data will overwrite existing live data. Continue to restore?", False)):
e3ffab
@@ -261,7 +290,6 @@ class Restore(admintool.AdminTool):
e3ffab
             self.log.info("Disabling all replication.")
e3ffab
             self.disable_agreements()
e3ffab
 
e3ffab
-            self.extract_backup(options.gpg_keyring)
e3ffab
             if options.data_only:
e3ffab
                 if not options.online:
e3ffab
                     self.log.info('Stopping Directory Server')
e3ffab
@@ -295,16 +323,8 @@ class Restore(admintool.AdminTool):
e3ffab
             # userRoot backend in it and the main IPA instance. If we
e3ffab
             # have a unified instance we need to restore both userRoot and
e3ffab
             # ipaca.
e3ffab
-            for instance in instances:
e3ffab
-                if os.path.exists(paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % instance):
e3ffab
-                    if options.backend is None:
e3ffab
-                        self.ldif2db(instance, 'userRoot', online=options.online)
e3ffab
-                        if os.path.exists(paths.IPACA_DIRSRV_INSTANCE_DB_TEMPLATE % instance):
e3ffab
-                            self.ldif2db(instance, 'ipaca', online=options.online)
e3ffab
-                    else:
e3ffab
-                        self.ldif2db(instance, options.backend, online=options.online)
e3ffab
-                else:
e3ffab
-                    raise admintool.ScriptError('389-ds instance %s does not exist' % instance)
e3ffab
+            for instance, backend in databases:
e3ffab
+                self.ldif2db(instance, backend, online=options.online)
e3ffab
 
e3ffab
             if options.data_only:
e3ffab
                 if not options.online:
e3ffab
@@ -447,20 +467,15 @@ class Restore(admintool.AdminTool):
e3ffab
             try:
e3ffab
                 conn.add_entry(ent)
e3ffab
             except Exception, e:
e3ffab
-                raise admintool.ScriptError(
e3ffab
-                    'Unable to bind to LDAP server: %s' % e)
e3ffab
+                self.log.error("Unable to bind to LDAP server: %s" % e)
e3ffab
+                return
e3ffab
 
e3ffab
             self.log.info("Waiting for LDIF to finish")
e3ffab
             wait_for_task(conn, dn)
e3ffab
         else:
e3ffab
             args = ['%s/ldif2db' % self.__find_scripts_dir(instance),
e3ffab
-                    '-i', ldiffile]
e3ffab
-            if backend is not None:
e3ffab
-                args.append('-n')
e3ffab
-                args.append(backend)
e3ffab
-            else:
e3ffab
-                args.append('-n')
e3ffab
-                args.append('userRoot')
e3ffab
+                    '-i', ldiffile,
e3ffab
+                    '-n', backend]
e3ffab
             (stdout, stderr, rc) = run(args, raiseonerr=False)
e3ffab
             if rc != 0:
e3ffab
                 self.log.critical("ldif2db failed: %s" % stderr)
e3ffab
-- 
e3ffab
2.1.0
e3ffab