[PATCH] Add backend-store option to backup commands

Tim Beale timbeale at catalyst.net.nz
Sun Oct 28 20:54:42 UTC 2018


This patch extends the backup online/rename commands so that you can
specify either an MDB or TDB database backend for the backup generated.
Previously you could only create TDB backups. The new backend-store
option is similar to the join/provision commands.

CI pass: https://gitlab.com/catalyst-samba/samba/pipelines/34377840

Review appreciated. Thanks.

-------------- next part --------------
From dd57a5152b26cd5238975ea75d09d24a46c4f07c Mon Sep 17 00:00:00 2001
From: Tim Beale <timbeale at catalyst.net.nz>
Date: Thu, 25 Oct 2018 09:03:53 +1300
Subject: [PATCH 1/2] netcmd: Add backend-store option to domain backup/rename
 cmds

Currently the online/rename backup files always use the default backend
(TDB) and there is no way to change this.

This patch adds the backend-store option to the backup commands so that
you can create a backup with an MDB backend, if needed.

Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
---
 python/samba/join.py                 | 18 +++++++++++-------
 python/samba/netcmd/domain_backup.py | 24 +++++++++++++++++-------
 python/samba/tests/domain_backup.py  | 21 +++++++++++++++++++++
 3 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/python/samba/join.py b/python/samba/join.py
index 01636fe..321b8c2 100644
--- a/python/samba/join.py
+++ b/python/samba/join.py
@@ -1539,11 +1539,12 @@ def join_DC(logger=None, server=None, creds=None, lp=None, site=None, netbios_na
 
 def join_clone(logger=None, server=None, creds=None, lp=None,
                targetdir=None, domain=None, include_secrets=False,
-               dns_backend="NONE"):
+               dns_backend="NONE", backend_store=None):
     """Creates a local clone of a remote DC."""
     ctx = DCCloneContext(logger, server, creds, lp, targetdir=targetdir,
                          domain=domain, dns_backend=dns_backend,
-                         include_secrets=include_secrets)
+                         include_secrets=include_secrets,
+                         backend_store=backend_store)
 
     lp.set("workgroup", ctx.domain_name)
     logger.info("workgroup is %s" % ctx.domain_name)
@@ -1616,10 +1617,11 @@ class DCCloneContext(DCJoinContext):
 
     def __init__(ctx, logger=None, server=None, creds=None, lp=None,
                  targetdir=None, domain=None, dns_backend=None,
-                 include_secrets=False):
+                 include_secrets=False, backend_store=None):
         super(DCCloneContext, ctx).__init__(logger, server, creds, lp,
                                             targetdir=targetdir, domain=domain,
-                                            dns_backend=dns_backend)
+                                            dns_backend=dns_backend,
+                                            backend_store=backend_store)
 
         # As we don't want to create or delete these DNs, we set them to None
         ctx.server_dn = None
@@ -1669,12 +1671,13 @@ class DCCloneAndRenameContext(DCCloneContext):
 
     def __init__(ctx, new_base_dn, new_domain_name, new_realm, logger=None,
                  server=None, creds=None, lp=None, targetdir=None, domain=None,
-                 dns_backend=None, include_secrets=True):
+                 dns_backend=None, include_secrets=True, backend_store=None):
         super(DCCloneAndRenameContext, ctx).__init__(logger, server, creds, lp,
                                                      targetdir=targetdir,
                                                      domain=domain,
                                                      dns_backend=dns_backend,
-                                                     include_secrets=include_secrets)
+                                                     include_secrets=include_secrets,
+                                                     backend_store=backend_store)
         # store the new DN (etc) that we want the cloned DB to use
         ctx.new_base_dn = new_base_dn
         ctx.new_domain_name = new_domain_name
@@ -1741,7 +1744,8 @@ class DCCloneAndRenameContext(DCCloneContext):
                             configdn=ctx.rename_dn(ctx.config_dn),
                             domain=ctx.new_domain_name, domainsid=ctx.domsid,
                             serverrole="active directory domain controller",
-                            dns_backend=ctx.dns_backend)
+                            dns_backend=ctx.dns_backend,
+                            backend_store=ctx.backend_store)
 
         print("Provision OK for renamed domain DN %s" % presult.domaindn)
         ctx.local_samdb = presult.samdb
diff --git a/python/samba/netcmd/domain_backup.py b/python/samba/netcmd/domain_backup.py
index 9f4486b..82ea4cb 100644
--- a/python/samba/netcmd/domain_backup.py
+++ b/python/samba/netcmd/domain_backup.py
@@ -25,7 +25,7 @@ import tempfile
 import samba
 import tdb
 import samba.getopt as options
-from samba.samdb import SamDB
+from samba.samdb import SamDB, get_default_backend_store
 import ldb
 from samba import smb
 from samba.ntacls import backup_online, backup_restore, backup_offline
@@ -208,11 +208,15 @@ class cmd_domain_backup_online(samba.netcmd.Command):
         Option("--targetdir", type=str,
                help="Directory to write the backup file to"),
         Option("--no-secrets", action="store_true", default=False,
-               help="Exclude secret values from the backup created")
+               help="Exclude secret values from the backup created"),
+        Option("--backend-store", type="choice", metavar="BACKENDSTORE",
+               choices=["tdb", "mdb"],
+               help="Specify the database backend to be used "
+               "(default is %s)" % get_default_backend_store()),
     ]
 
     def run(self, sambaopts=None, credopts=None, server=None, targetdir=None,
-            no_secrets=False):
+            no_secrets=False, backend_store=None):
         logger = self.get_logger()
         logger.setLevel(logging.DEBUG)
 
@@ -231,7 +235,8 @@ class cmd_domain_backup_online(samba.netcmd.Command):
         include_secrets = not no_secrets
         ctx = join_clone(logger=logger, creds=creds, lp=lp,
                          include_secrets=include_secrets, server=server,
-                         dns_backend='SAMBA_INTERNAL', targetdir=tmpdir)
+                         dns_backend='SAMBA_INTERNAL', targetdir=tmpdir,
+                         backend_store=backend_store)
 
         # get the paths used for the clone, then drop the old samdb connection
         paths = ctx.paths
@@ -608,7 +613,11 @@ class cmd_domain_backup_rename(samba.netcmd.Command):
         Option("--keep-dns-realm", action="store_true", default=False,
                help="Retain the DNS entries for the old realm in the backup"),
         Option("--no-secrets", action="store_true", default=False,
-               help="Exclude secret values from the backup created")
+               help="Exclude secret values from the backup created"),
+        Option("--backend-store", type="choice", metavar="BACKENDSTORE",
+               choices=["tdb", "mdb"],
+               help="Specify the database backend to be used "
+               "(default is %s)" % get_default_backend_store()),
     ]
 
     takes_args = ["new_domain_name", "new_dns_realm"]
@@ -706,7 +715,7 @@ class cmd_domain_backup_rename(samba.netcmd.Command):
 
     def run(self, new_domain_name, new_dns_realm, sambaopts=None,
             credopts=None, server=None, targetdir=None, keep_dns_realm=False,
-            no_secrets=False):
+            no_secrets=False, backend_store=None):
         logger = self.get_logger()
         logger.setLevel(logging.INFO)
 
@@ -738,7 +747,8 @@ class cmd_domain_backup_rename(samba.netcmd.Command):
                                       creds=creds, lp=lp,
                                       include_secrets=include_secrets,
                                       dns_backend='SAMBA_INTERNAL',
-                                      server=server, targetdir=tmpdir)
+                                      server=server, targetdir=tmpdir,
+                                      backend_store=backend_store)
 
         # sanity-check we're not "renaming" the domain to the same values
         old_domain = ctx.domain_name
diff --git a/python/samba/tests/domain_backup.py b/python/samba/tests/domain_backup.py
index 98863db..320ff1f 100644
--- a/python/samba/tests/domain_backup.py
+++ b/python/samba/tests/domain_backup.py
@@ -57,6 +57,12 @@ class DomainBackupBase(SambaToolCmdTest, TestCaseInTempDir):
         self.backup_markers = ['sidForRestore', 'backupDate']
         self.restore_domain = os.environ["DOMAIN"]
         self.restore_realm = os.environ["REALM"]
+        self.backend = None
+
+    def use_backend(self, backend):
+        """Explicitly set the DB backend that the backup should use"""
+        self.backend = backend
+        self.base_cmd += ["--backend-store=" + backend]
 
     def assert_partitions_present(self, samdb):
         """Asserts all expected partitions are present in the backup samdb"""
@@ -278,6 +284,13 @@ class DomainBackupBase(SambaToolCmdTest, TestCaseInTempDir):
         self.assertIsNone(res[0].get('repsFrom'))
         self.assertIsNone(res[0].get('repsTo'))
 
+        # check the DB is using the backend we supplied
+        if self.backend:
+            res = samdb.search(base="@PARTITION", scope=ldb.SCOPE_BASE,
+                               attrs=["backendStore"])
+            backend = str(res[0].get("backendStore"))
+            self.assertEqual(backend, self.backend)
+
         # check the restored DB has the expected partitions/DC/FSMO roles
         self.assert_partitions_present(samdb)
         self.assert_dcs_present(samdb, self.new_server, expected_count=1)
@@ -391,15 +404,19 @@ class DomainBackupOnline(DomainBackupBase):
         self._test_backup_untar()
 
     def test_backup_restore(self):
+        self.use_backend("tdb")
         self._test_backup_restore()
 
     def test_backup_restore_with_conf(self):
+        self.use_backend("mdb")
         self._test_backup_restore_with_conf()
 
     def test_backup_restore_no_secrets(self):
+        self.use_backend("tdb")
         self._test_backup_restore_no_secrets()
 
     def test_backup_restore_into_site(self):
+        self.use_backend("mdb")
         self._test_backup_restore_into_site()
 
 
@@ -422,15 +439,19 @@ class DomainBackupRename(DomainBackupBase):
         self._test_backup_untar()
 
     def test_backup_restore(self):
+        self.use_backend("mdb")
         self._test_backup_restore()
 
     def test_backup_restore_with_conf(self):
+        self.use_backend("tdb")
         self._test_backup_restore_with_conf()
 
     def test_backup_restore_no_secrets(self):
+        self.use_backend("mdb")
         self._test_backup_restore_no_secrets()
 
     def test_backup_restore_into_site(self):
+        self.use_backend("tdb")
         self._test_backup_restore_into_site()
 
     def test_backup_invalid_args(self):
-- 
2.7.4


From 0f913b6227a03dffa752c08d7d12f5691f35c243 Mon Sep 17 00:00:00 2001
From: Tim Beale <timbeale at catalyst.net.nz>
Date: Fri, 26 Oct 2018 13:21:48 +1300
Subject: [PATCH 2/2] selftest: Specify different DB backends for restored
 testenvs

Vary the DB backend that we use for the renamed DCs. The labdc and
renamedc are fairly similar, so let's have each of them use a different
backend.

Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
---
 selftest/target/Samba4.pm | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index 0a04aa2..770ba4f 100755
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -2867,6 +2867,7 @@ sub setup_renamedc
 	my $backupdir = File::Temp->newdir();
 	my $server_args = $self->get_backup_server_args($dcvars);
 	my $backup_args = "rename $env->{DOMAIN} $env->{REALM} $server_args";
+	$backup_args .= " --backend-store=tdb";
 	my $backup_file = $self->create_backup($env, $dcvars, $backupdir,
 					       $backup_args);
 	unless($backup_file) {
@@ -2963,7 +2964,7 @@ sub setup_labdc
 	my $backupdir = File::Temp->newdir();
 	my $server_args = $self->get_backup_server_args($dcvars);
 	my $backup_args = "rename $env->{DOMAIN} $env->{REALM} $server_args";
-	$backup_args .= " --no-secrets";
+	$backup_args .= " --no-secrets --backend-store=mdb";
 	my $backup_file = $self->create_backup($env, $dcvars, $backupdir,
 					       $backup_args);
 	unless($backup_file) {
-- 
2.7.4



More information about the samba-technical mailing list