netcmd: Re-create default site for backup-restore (if missing)
authorTim Beale <timbeale@catalyst.net.nz>
Tue, 18 Sep 2018 02:54:51 +0000 (14:54 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 26 Sep 2018 05:49:17 +0000 (07:49 +0200)
Normally when a new DC joins a domain, samba-tool works out the new
DC's site automatically. However, it does this by querying the existing
DC using CLDAP. In the restore case, there is no DC running. We could
still query the DB on disk and work out the correct site based on the
new DC's IP, however:
- comparing between the CN=Subnet DNs and an IP-address string seems
  like it'd be non-trivial to write, and
- in the lab-domain rename case, chances are the user will want a
  completely different subnet to what's already in the DB.

The restore command now has a --site option so the user can specify an
appropriate site for the restored DC. This patch makes the restore
command work by default (i.e. without a --site option) even if the
default Default-First-Site-Name doesn't exist. Basically the solution is
to just check Default-First-Site-Name exists and create it if it
doesn't. As the recommended workflow is to use the restored DC as a
temporary seed that you'll later throw away, this approach seems
acceptable. Subsequent DCs will then be joined to the running restored
DC, so an appropriate site will be determined using CLDAP. The only
side-effect is potentially an extra Site object.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13621

Signed-off-by: Tim Beale <timbeale@catalyst.net.nz>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/netcmd/domain_backup.py

index 89de40db7aaf215c001228b78c83126b27b74492..ee6d2848decdbac0b9515c76ea04f7919b3e3427 100644 (file)
@@ -51,6 +51,7 @@ from samba.mdb_util import mdb_copy
 import errno
 import tdb
 from subprocess import CalledProcessError
+from samba import sites
 
 
 # work out a SID (based on a free RID) to use when the domain gets restored.
@@ -361,9 +362,23 @@ class cmd_domain_backup_restore(cmd_fsmo_seize):
         chk.check_database(controls=controls, attrs=attrs)
         samdb.transaction_commit()
 
+    def create_default_site(self, samdb, logger):
+        '''Creates the default site, if it doesn't already exist'''
+
+        sitename = DEFAULTSITE
+        search_expr = "(&(cn={0})(objectclass=site))".format(sitename)
+        res = samdb.search(samdb.get_config_basedn(), scope=ldb.SCOPE_SUBTREE,
+                           expression=search_expr)
+
+        if len(res) == 0:
+            logger.info("Creating default site '{0}'".format(sitename))
+            sites.create_site(samdb, samdb.get_config_basedn(), sitename)
+
+        return sitename
+
     def run(self, sambaopts=None, credopts=None, backup_file=None,
             targetdir=None, newservername=None, host_ip=None, host_ip6=None,
-            site=DEFAULTSITE):
+            site=None):
         if not (backup_file and os.path.exists(backup_file)):
             raise CommandError('Backup file not found.')
         if targetdir is None:
@@ -407,6 +422,13 @@ class cmd_domain_backup_restore(cmd_fsmo_seize):
         samdb_path = os.path.join(private_dir, 'sam.ldb')
         samdb = SamDB(url=samdb_path, session_info=system_session(), lp=lp)
 
+        if site is None:
+            # There's no great way to work out the correct site to add the
+            # restored DC to. By default, add it to Default-First-Site-Name,
+            # creating the site if it doesn't already exist
+            site = self.create_default_site(samdb, logger)
+            logger.info("Adding new DC to site '{0}'".format(site))
+
         # Create account using the join_add_objects function in the join object
         # We need namingContexts, account control flags, and the sid saved by
         # the backup process.