[PATCH] Use the same process and krb5 ccache when invoking samba-tool in drs tests

Andrew Bartlett abartlet at samba.org
Fri Jul 21 20:19:25 UTC 2017


This patch removes a number of calls to fork() inside python, and
instead of passing -Uusername%password on the internal command line, we
pass around the name of the krb5 credentials cache we already have. 

I've not been able to quantify the speed benefits - there seems to be
more noise than signal in the timing here, hence my other patch
reducing idle time, but when we had these tests under perf/FlameGraph
the string2key routines really dominated the time what was spent on the
CPU. 

Earlier in the thread, Jeremy looked over the C parts, but if someone
could look over the rest that would be great!

Please review!

Thanks,

Andrew Bartlett

-- 
Andrew Bartlett                       http://samba.org/~abartlet/
Authentication Developer, Samba Team  http://samba.org
Samba Developer, Catalyst IT          http://catalyst.net.nz/services/samba
-------------- next part --------------
From 796d3bd37e202c113074e1d02329232cf0e8dcdc Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 14:44:46 +1200
Subject: [PATCH 01/17] pycredentials: Allow optional "name" argument to
 get_named_ccache() to be missing

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 auth/credentials/pycredentials.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/auth/credentials/pycredentials.c b/auth/credentials/pycredentials.c
index caf30bf..0a29c58 100644
--- a/auth/credentials/pycredentials.c
+++ b/auth/credentials/pycredentials.c
@@ -526,7 +526,7 @@ static PyObject *PyCredentialCacheContainer_from_ccache_container(struct ccache_
 static PyObject *py_creds_get_named_ccache(PyObject *self, PyObject *args)
 {
 	PyObject *py_lp_ctx = Py_None;
-	char *ccache_name;
+	char *ccache_name = NULL;
 	struct loadparm_context *lp_ctx;
 	struct ccache_container *ccc;
 	struct tevent_context *event_ctx;
-- 
2.9.4


From 69496a0428b9071a368da035ba37dc259c76663b Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 14:47:01 +1200
Subject: [PATCH 02/17] pycredentials: Add set_named_ccache() to set a
 particular credentials cache

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
Reviewed-by: Jeremy Allison <jra at samba.org>
---
 auth/credentials/pycredentials.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/auth/credentials/pycredentials.c b/auth/credentials/pycredentials.c
index 0a29c58..bf90eb8 100644
--- a/auth/credentials/pycredentials.c
+++ b/auth/credentials/pycredentials.c
@@ -31,6 +31,8 @@
 #include <tevent.h>
 #include "libcli/auth/libcli_auth.h"
 #include "auth/credentials/credentials_internal.h"
+#include "system/kerberos.h"
+#include "auth/kerberos/kerberos.h"
 
 void initcredentials(void);
 
@@ -793,10 +795,37 @@ PyTypeObject PyCredentials = {
 	.tp_methods = py_creds_methods,
 };
 
+static PyObject *py_ccache_name(PyObject *self, PyObject *unused)
+{
+	struct ccache_container *ccc;
+	char *name;
+	PyObject *py_name;
+	int ret;
+	ccc = pytalloc_get_type(self, struct ccache_container);
+
+	ret = krb5_cc_get_full_name(ccc->smb_krb5_context->krb5_context,
+				    ccc->ccache, &name);
+	if (ret == 0) {
+		py_name = PyString_FromStringOrNULL(name);
+		SAFE_FREE(name);
+	} else {
+		PyErr_SetString(PyExc_RuntimeError,
+				"Failed to get ccache name");
+		return NULL;
+	}
+	return py_name;
+}
+
+static PyMethodDef py_ccache_container_methods[] = {
+	{ "get_name", py_ccache_name, METH_NOARGS,
+	  "S.get_name() -> name\nObtain KRB5 credentials cache name." },
+	{ NULL }
+};
 
 PyTypeObject PyCredentialCacheContainer = {
 	.tp_name = "credentials.CredentialCacheContainer",
 	.tp_flags = Py_TPFLAGS_DEFAULT,
+	.tp_methods = py_ccache_container_methods,
 };
 
 MODULE_INIT_FUNC(credentials)
-- 
2.9.4


From d4525007ff9e14cc514c4fd7c6a9be559daa8099 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 14:48:39 +1200
Subject: [PATCH 03/17] selftest: Add tests for credentials.get_named_ccache()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 python/samba/tests/krb5_credentials.py | 103 +++++++++++++++++++++++++++++++++
 source4/selftest/tests.py              |   3 +
 2 files changed, 106 insertions(+)
 create mode 100644 python/samba/tests/krb5_credentials.py

diff --git a/python/samba/tests/krb5_credentials.py b/python/samba/tests/krb5_credentials.py
new file mode 100644
index 0000000..a3eb034
--- /dev/null
+++ b/python/samba/tests/krb5_credentials.py
@@ -0,0 +1,103 @@
+# Integration tests for pycredentials
+#
+# Copyright (C) Catalyst IT Ltd. 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+from samba.tests import TestCase, delete_force
+import os
+
+import samba
+from samba.auth import system_session
+from samba.credentials import (
+    Credentials,
+)
+from samba.dsdb import (
+    UF_WORKSTATION_TRUST_ACCOUNT,
+    UF_PASSWD_NOTREQD,
+    UF_NORMAL_ACCOUNT)
+from samba.samdb import SamDB
+
+"""KRB5 Integration tests for pycredentials.
+
+Seperated from py_credentials so as to allow running against just one
+environment so we know the server that we add the user on will be our
+KDC
+
+"""
+
+MACHINE_NAME = "krb5credstest"
+
+class PyKrb5CredentialsTests(TestCase):
+
+    def setUp(self):
+        super(PyKrb5CredentialsTests, self).setUp()
+
+        self.server      = os.environ["SERVER"]
+        self.domain      = os.environ["DOMAIN"]
+        self.host        = os.environ["SERVER_IP"]
+        self.lp          = self.get_loadparm()
+
+        self.credentials = self.get_credentials()
+
+        self.session     = system_session()
+        self.ldb = SamDB(url="ldap://%s" % self.host,
+                         session_info=self.session,
+                         credentials=self.credentials,
+                         lp=self.lp)
+
+        self.create_machine_account()
+
+
+    def tearDown(self):
+        super(PyKrb5CredentialsTests, self).tearDown()
+        delete_force(self.ldb, self.machine_dn)
+
+    def test_get_named_ccache(self):
+        name = "MEMORY:py_creds_machine"
+        ccache = self.machine_creds.get_named_ccache(self.lp,
+                                                     name)
+        self.assertEqual(ccache.get_name(), name)
+
+    def test_get_unnamed_ccache(self):
+        ccache = self.machine_creds.get_named_ccache(self.lp)
+        self.assertIsNotNone(ccache.get_name())
+
+    #
+    # Create the machine account
+    def create_machine_account(self):
+        self.machine_pass = samba.generate_random_password(32, 32)
+        self.machine_name = MACHINE_NAME
+        self.machine_dn = "cn=%s,%s" % (self.machine_name, self.ldb.domain_dn())
+
+        # remove the account if it exists, this will happen if a previous test
+        # run failed
+        delete_force(self.ldb, self.machine_dn)
+
+        utf16pw = unicode(
+            '"' + self.machine_pass.encode('utf-8') + '"', 'utf-8'
+        ).encode('utf-16-le')
+        self.ldb.add({
+            "dn": self.machine_dn,
+            "objectclass": "computer",
+            "sAMAccountName": "%s$" % self.machine_name,
+            "userAccountControl":
+                str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD),
+            "unicodePwd": utf16pw})
+
+        self.machine_creds = Credentials()
+        self.machine_creds.guess(self.get_loadparm())
+        self.machine_creds.set_password(self.machine_pass)
+        self.machine_creds.set_username(self.machine_name + "$")
+        self.machine_creds.set_workstation(self.machine_name)
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 15037a2..9e98923 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -663,6 +663,9 @@ planoldpythontestsuite("ad_dc",
                        extra_args=['-U"$USERNAME%$PASSWORD"'])
 
 planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.lsa_string")
+planoldpythontestsuite("ad_dc_ntvfs",
+                       "samba.tests.krb5_credentials",
+                       extra_args=['-U"$USERNAME%$PASSWORD"'])
 for env in ["ad_dc_ntvfs", "vampire_dc", "promoted_dc"]:
     planoldpythontestsuite(env,
                            "samba.tests.py_credentials",
-- 
2.9.4


From 94167d6a329d8eecab81362f1f61a80e804878d4 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 14:51:22 +1200
Subject: [PATCH 04/17] pycredentials: Add set_named_ccache()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 auth/credentials/pycredentials.c       | 42 ++++++++++++++++++++++++++++++++++
 python/samba/tests/krb5_credentials.py |  9 ++++++++
 2 files changed, 51 insertions(+)

diff --git a/auth/credentials/pycredentials.c b/auth/credentials/pycredentials.c
index bf90eb8..9c6faef 100644
--- a/auth/credentials/pycredentials.c
+++ b/auth/credentials/pycredentials.c
@@ -571,6 +571,45 @@ static PyObject *py_creds_get_named_ccache(PyObject *self, PyObject *args)
 	return NULL;
 }
 
+static PyObject *py_creds_set_named_ccache(PyObject *self, PyObject *args)
+{
+	int ret;
+	char *newval;
+	const char *error_string;
+	TALLOC_CTX *mem_ctx;
+	struct loadparm_context *lp_ctx;
+	PyObject *py_lp_ctx = Py_None;
+	enum credentials_obtained obt = CRED_SPECIFIED;
+	int _obt = obt;
+	if (!PyArg_ParseTuple(args, "s|iO", &newval, &_obt, &py_lp_ctx))
+		return NULL;
+
+	mem_ctx = talloc_new(NULL);
+	if (mem_ctx == NULL) {
+		PyErr_NoMemory();
+		return NULL;
+	}
+
+	lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx);
+	if (lp_ctx == NULL) {
+		talloc_free(mem_ctx);
+		return NULL;
+	}
+
+	ret = cli_credentials_set_ccache(PyCredentials_AsCliCredentials(self),
+					 lp_ctx,
+					 newval, CRED_SPECIFIED,
+					 &error_string);
+
+	if (ret != 0) {
+		PyErr_SetString(PyExc_RuntimeError, error_string?error_string:"NULL");
+		return NULL;
+	}
+
+	talloc_free(mem_ctx);
+	Py_RETURN_NONE;
+}
+
 static PyObject *py_creds_set_gensec_features(PyObject *self, PyObject *args)
 {
 	unsigned int gensec_features;
@@ -756,6 +795,9 @@ static PyMethodDef py_creds_methods[] = {
 	{ "guess", py_creds_guess, METH_VARARGS, NULL },
 	{ "set_machine_account", py_creds_set_machine_account, METH_VARARGS, NULL },
 	{ "get_named_ccache", py_creds_get_named_ccache, METH_VARARGS, NULL },
+	{ "set_named_ccache", py_creds_set_named_ccache, METH_VARARGS,
+		"S.set_named_ccache(krb5_ccache_name, obtained, lp) -> None\n"
+		"Set credentials to KRB5 Credentials Cache (by name)." },
 	{ "set_gensec_features", py_creds_set_gensec_features, METH_VARARGS, NULL },
 	{ "get_gensec_features", py_creds_get_gensec_features, METH_NOARGS, NULL },
 	{ "get_forced_sasl_mech", py_creds_get_forced_sasl_mech, METH_NOARGS,
diff --git a/python/samba/tests/krb5_credentials.py b/python/samba/tests/krb5_credentials.py
index a3eb034..cad19da 100644
--- a/python/samba/tests/krb5_credentials.py
+++ b/python/samba/tests/krb5_credentials.py
@@ -74,6 +74,15 @@ class PyKrb5CredentialsTests(TestCase):
         ccache = self.machine_creds.get_named_ccache(self.lp)
         self.assertIsNotNone(ccache.get_name())
 
+    def test_set_named_ccache(self):
+        ccache = self.machine_creds.get_named_ccache(self.lp)
+
+        creds = Credentials()
+        creds.set_named_ccache(ccache.get_name())
+
+        ccache2 = creds.get_named_ccache(self.lp)
+        self.assertEqual(ccache.get_name(), ccache2.get_name())
+
     #
     # Create the machine account
     def create_machine_account(self):
-- 
2.9.4


From daa6087995a327d8639f98899cce44f350b5c121 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 14:52:39 +1200
Subject: [PATCH 05/17] python/getopt: Add --krb5-ccache (for samba-tool etc)
 to match the C binaries

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 python/samba/getopt.py | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/python/samba/getopt.py b/python/samba/getopt.py
index 9e1fb83..befc62b 100644
--- a/python/samba/getopt.py
+++ b/python/samba/getopt.py
@@ -158,6 +158,9 @@ class CredentialsOptions(optparse.OptionGroup):
                         action="callback",
                         help="Use stored machine account password",
                         callback=self._set_machine_pass)
+        self._add_option("--krb5-ccache", metavar="KRB5CCNAME",
+                        action="callback", type=str,
+                        help="Kerberos Credentials cache", callback=self._set_krb5_ccache)
         self.creds = Credentials()
 
     def _add_option(self, *args1, **kwargs):
@@ -198,6 +201,9 @@ class CredentialsOptions(optparse.OptionGroup):
     def _set_simple_bind_dn(self, option, opt_str, arg, parser):
         self.creds.set_bind_dn(arg)
 
+    def _set_krb5_ccache(self, option, opt_str, arg, parser):
+        self.creds.set_named_ccache(arg)
+
     def get_credentials(self, lp, fallback_machine=False):
         """Obtain the credentials set on the command-line.
 
-- 
2.9.4


From 0da2c4a627aaaef4a3892e84d839a062a172622b Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 15:02:00 +1200
Subject: [PATCH 06/17] selftest: Use self.runsubcmd() to run samba-tool for
 _test_join in ridalloc_exop.py

This is the standard way to run samba-tool from in the test scripts and allows
assertion that the command ran as expected

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/torture/drs/python/ridalloc_exop.py | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/source4/torture/drs/python/ridalloc_exop.py b/source4/torture/drs/python/ridalloc_exop.py
index 9196f4a..eacf3c3 100644
--- a/source4/torture/drs/python/ridalloc_exop.py
+++ b/source4/torture/drs/python/ridalloc_exop.py
@@ -305,14 +305,14 @@ class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
     def _test_join(self, server, netbios_name):
         tmpdir = os.path.join(self.tempdir, "targetdir")
         creds = self.get_credentials()
-        cmd = cmd_sambatool.subcommands['domain'].subcommands['join']
-        result = cmd._run("samba-tool domain join",
-                          creds.get_realm(),
-                          "dc", "-U%s%%%s" % (creds.get_username(),
-                                              creds.get_password()),
-                          '--targetdir=%s' % tmpdir,
-                          '--server=%s' % server,
-                          "--option=netbios name = %s" % netbios_name)
+        (result, out, err) = self.runsubcmd("domain", "join",
+                                            creds.get_realm(),
+                                            "dc", "-U%s%%%s" % (creds.get_username(),
+                                                                creds.get_password()),
+                                            '--targetdir=%s' % tmpdir,
+                                            '--server=%s' % server,
+                                            "--option=netbios name = %s" % netbios_name)
+        self.assertCmdSuccess(result, out, err)
         return tmpdir
 
     def _test_force_demote(self, server, netbios_name):
-- 
2.9.4


From e3ed99c14569b9126bbe64e684892a6b0ec1988e Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 15:05:08 +1200
Subject: [PATCH 07/17] selftest: Use self.runsubcmd() to run samba-tool for
 _test_force_demote in ridalloc_exop.py

This is the standard way to run samba-tool from in the test scripts and allows
assertion that the command ran as expected

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/torture/drs/python/ridalloc_exop.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/source4/torture/drs/python/ridalloc_exop.py b/source4/torture/drs/python/ridalloc_exop.py
index eacf3c3..dfab638 100644
--- a/source4/torture/drs/python/ridalloc_exop.py
+++ b/source4/torture/drs/python/ridalloc_exop.py
@@ -317,12 +317,12 @@ class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
 
     def _test_force_demote(self, server, netbios_name):
         creds = self.get_credentials()
-        cmd = cmd_sambatool.subcommands['domain'].subcommands['demote']
-        result = cmd._run("samba-tool domain demote",
-                          "-U%s%%%s" % (creds.get_username(),
-                                              creds.get_password()),
-                          '--server=%s' % server,
-                          "--remove-other-dead-server=%s" % netbios_name)
+        (result, out, err) = self.runsubcmd("domain", "demote",
+                                            "-U%s%%%s" % (creds.get_username(),
+                                                          creds.get_password()),
+                                            '--server=%s' % server,
+                                            "--remove-other-dead-server=%s" % netbios_name)
+        self.assertCmdSuccess(result, out, err)
 
     def test_offline_manual_seized_ridalloc_with_dbcheck(self):
         """Peform the same actions as test_offline_samba_tool_seized_ridalloc,
-- 
2.9.4


From 9f1aefc2bd4017db4b8c1c394fe8622c5369b643 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 15:06:10 +1200
Subject: [PATCH 08/17] selftest: Remove unused import in ridalloc_exop.py

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/torture/drs/python/ridalloc_exop.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/source4/torture/drs/python/ridalloc_exop.py b/source4/torture/drs/python/ridalloc_exop.py
index dfab638..80d0111 100644
--- a/source4/torture/drs/python/ridalloc_exop.py
+++ b/source4/torture/drs/python/ridalloc_exop.py
@@ -40,7 +40,6 @@ from samba.drs_utils import drs_DsBind
 from samba.samdb import SamDB
 
 import shutil, tempfile, os
-from samba.netcmd.main import cmd_sambatool
 from samba.auth import system_session, admin_session
 from samba.dbchecker import dbcheck
 from samba.ndr import ndr_pack
-- 
2.9.4


From e8d38a11af74ecef3fb98a42039d502841b6c249 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Fri, 7 Jul 2017 12:53:25 +1200
Subject: [PATCH 09/17] selftest: Use self.runsubcommand() in
 DrsReplicaSyncTestCase

This will allow catching the correct error messages and failure when _net_drs_replicate()
is reworked to not use a subprocess.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/torture/drs/python/replica_sync.py | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/source4/torture/drs/python/replica_sync.py b/source4/torture/drs/python/replica_sync.py
index dd862ce..65e6f1e 100644
--- a/source4/torture/drs/python/replica_sync.py
+++ b/source4/torture/drs/python/replica_sync.py
@@ -70,12 +70,23 @@ class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
     def test_ReplDisabled(self):
         """Tests we cann't replicate when replication is disabled"""
         self._disable_inbound_repl(self.dnsname_dc1)
-        try:
-            self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=False)
-        except samba.tests.BlackboxProcessError, e:
-            self.assertTrue('WERR_DS_DRA_SINK_DISABLED' in e.stderr)
-        else:
-            self.fail("'drs replicate' command should have failed!")
+        
+        ccache_name = self.get_creds_ccache_name()
+
+        # Tunnel the command line credentials down to the
+        # subcommand to avoid a new kinit
+        cmdline_auth = "--krb5-ccache=%s" % ccache_name
+
+        # bin/samba-tool drs <drs_command> <cmdline_auth>
+        cmd_list = ["drs", "replicate", cmdline_auth]
+
+        nc_dn = self.domain_dn
+        # bin/samba-tool drs replicate <Dest_DC_NAME> <Src_DC_NAME> <Naming Context>
+        cmd_list += [self.dnsname_dc1, self.dnsname_dc2, nc_dn]
+        
+        (result, out, err) = self.runsubcmd(*cmd_list)
+        self.assertCmdFail(result)
+        self.assertTrue('WERR_DS_DRA_SINK_DISABLED' in err)
 
     def test_ReplDisabledForced(self):
         """Tests we can force replicate when replication is disabled"""
-- 
2.9.4


From e48042c7f5ae2fce04f3dd5a3d78889e89fabe3d Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 15:25:36 +1200
Subject: [PATCH 10/17] selftest: Port DrsBaseTestCase._net_drs_replicate() to
 self.runsubcmd()

This avoids forking a subprocess with self.check_run()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/torture/drs/python/drs_base.py | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index f07592d..8703617 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -108,20 +108,32 @@ class DrsBaseTestCase(SambaToolCmdTest):
         # bin/samba-tool drs <drs_command> <cmdline_auth>
         return "%s drs %s %s" % (samba_tool_cmd, drs_command, cmdline_auth)
 
+    def _samba_tool_cmd_list(self, drs_command):
+        # make command line credentials string
+        creds = self.get_credentials()
+        cmdline_auth = "-U%s/%s%%%s" % (creds.get_domain(),
+                                        creds.get_username(), creds.get_password())
+        # bin/samba-tool drs <drs_command> <cmdline_auth>
+        return ["drs", drs_command, cmdline_auth]
+
     def _net_drs_replicate(self, DC, fromDC, nc_dn=None, forced=True, local=False, full_sync=False):
         if nc_dn is None:
             nc_dn = self.domain_dn
         # make base command line
-        samba_tool_cmdline = self._samba_tool_cmdline("replicate")
+        samba_tool_cmdline = self._samba_tool_cmd_list("replicate")
+        # bin/samba-tool drs replicate <Dest_DC_NAME> <Src_DC_NAME> <Naming Context>
+        samba_tool_cmdline += [DC, fromDC, nc_dn]
+
         if forced:
-            samba_tool_cmdline += " --sync-forced"
+            samba_tool_cmdline += ["--sync-forced"]
         if local:
-            samba_tool_cmdline += " --local"
+            samba_tool_cmdline += ["--local"]
         if full_sync:
-            samba_tool_cmdline += " --full-sync"
-        # bin/samba-tool drs replicate <Dest_DC_NAME> <Src_DC_NAME> <Naming Context>
-        cmd_line = "%s %s %s %s" % (samba_tool_cmdline, DC, fromDC, nc_dn)
-        return self.check_output(cmd_line)
+            samba_tool_cmdline += ["--full-sync"]
+
+        (result, out, err) = self.runsubcmd(*samba_tool_cmdline)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEquals(err,"","Shouldn't be any error messages")
 
     def _enable_inbound_repl(self, DC):
         # make base command line
-- 
2.9.4


From 99f88a148bb15fa1bb9d999ace6e53b6d31b8e36 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 16:01:56 +1200
Subject: [PATCH 11/17] selftest: Port DrsBaseTestCase to self.runsubcmd()

This avoids forking a subprocess with self.check_run() for:
 - _disable_inbound_repl
 - _enable_inbound_repl
 - _disable_all_repl
 - _enable_all_repl

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/torture/drs/python/drs_base.py | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index 8703617..97a2bfb 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -139,27 +139,39 @@ class DrsBaseTestCase(SambaToolCmdTest):
         # make base command line
         samba_tool_cmd = self._samba_tool_cmdline("options")
         # disable replication
-        self.check_run("%s %s --dsa-option=-DISABLE_INBOUND_REPL" %(samba_tool_cmd, DC))
+        samba_tool_cmdline += [DC, "--dsa-option=-DISABLE_INBOUND_REPL"]
+        (result, out, err) = self.runsubcmd(*samba_tool_cmdline)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEquals(err,"","Shouldn't be any error messages")
 
     def _disable_inbound_repl(self, DC):
         # make base command line
         samba_tool_cmd = self._samba_tool_cmdline("options")
         # disable replication
-        self.check_run("%s %s --dsa-option=+DISABLE_INBOUND_REPL" %(samba_tool_cmd, DC))
+        samba_tool_cmdline += [DC, "--dsa-option=+DISABLE_INBOUND_REPL"]
+        (result, out, err) = self.runsubcmd(*samba_tool_cmdline)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEquals(err,"","Shouldn't be any error messages")
 
     def _enable_all_repl(self, DC):
+        self.enable_inbound_repl(DC)
         # make base command line
-        samba_tool_cmd = self._samba_tool_cmdline("options")
-        # disable replication
-        self.check_run("%s %s --dsa-option=-DISABLE_INBOUND_REPL" %(samba_tool_cmd, DC))
-        self.check_run("%s %s --dsa-option=-DISABLE_OUTBOUND_REPL" %(samba_tool_cmd, DC))
+        samba_tool_cmdline = self._samba_tool_cmdline("options")
+        # enable replication
+        samba_tool_cmdline += [DC, "--dsa-option=-DISABLE_OUTBOUND_REPL"]
+        (result, out, err) = self.runsubcmd(*samba_tool_cmdline)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEquals(err,"","Shouldn't be any error messages")
 
     def _disable_all_repl(self, DC):
+        self.disable_inbound_repl(DC)
         # make base command line
-        samba_tool_cmd = self._samba_tool_cmdline("options")
+        samba_tool_cmdline = self._samba_tool_cmdline("options")
         # disable replication
-        self.check_run("%s %s --dsa-option=+DISABLE_INBOUND_REPL" %(samba_tool_cmd, DC))
-        self.check_run("%s %s --dsa-option=+DISABLE_OUTBOUND_REPL" %(samba_tool_cmd, DC))
+        samba_tool_cmdline += [DC, "--dsa-option=+DISABLE_OUTBOUND_REPL"]
+        (result, out, err) = self.runsubcmd(*samba_tool_cmdline)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEquals(err,"","Shouldn't be any error messages")
 
     def _get_highest_hwm_utdv(self, ldb_conn):
         res = ldb_conn.search("", scope=ldb.SCOPE_BASE, attrs=["highestCommittedUSN"])
-- 
2.9.4


From fd6440528f3fe1db4727c4145ed597adb180945c Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 16:05:00 +1200
Subject: [PATCH 12/17] selftest: Port DrsBaseTestCase._enable_inbound_repl()
 to self.runsubcmd()

This avoids forking a subprocess with self.check_run()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/torture/drs/python/drs_base.py | 31 +++++++++++--------------------
 1 file changed, 11 insertions(+), 20 deletions(-)

diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index 97a2bfb..5ddd2a7 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -137,10 +137,10 @@ class DrsBaseTestCase(SambaToolCmdTest):
 
     def _enable_inbound_repl(self, DC):
         # make base command line
-        samba_tool_cmd = self._samba_tool_cmdline("options")
+        samba_tool_cmd = self._samba_tool_cmd_list("options")
         # disable replication
-        samba_tool_cmdline += [DC, "--dsa-option=-DISABLE_INBOUND_REPL"]
-        (result, out, err) = self.runsubcmd(*samba_tool_cmdline)
+        samba_tool_cmd += [DC, "--dsa-option=-DISABLE_INBOUND_REPL"]
+        (result, out, err) = self.runsubcmd(*samba_tool_cmd)
         self.assertCmdSuccess(result, out, err)
         self.assertEquals(err,"","Shouldn't be any error messages")
 
@@ -148,30 +148,21 @@ class DrsBaseTestCase(SambaToolCmdTest):
         # make base command line
         samba_tool_cmd = self._samba_tool_cmdline("options")
         # disable replication
-        samba_tool_cmdline += [DC, "--dsa-option=+DISABLE_INBOUND_REPL"]
-        (result, out, err) = self.runsubcmd(*samba_tool_cmdline)
-        self.assertCmdSuccess(result, out, err)
-        self.assertEquals(err,"","Shouldn't be any error messages")
+        self.check_run("%s %s --dsa-option=+DISABLE_INBOUND_REPL" %(samba_tool_cmd, DC))
 
     def _enable_all_repl(self, DC):
-        self.enable_inbound_repl(DC)
         # make base command line
-        samba_tool_cmdline = self._samba_tool_cmdline("options")
-        # enable replication
-        samba_tool_cmdline += [DC, "--dsa-option=-DISABLE_OUTBOUND_REPL"]
-        (result, out, err) = self.runsubcmd(*samba_tool_cmdline)
-        self.assertCmdSuccess(result, out, err)
-        self.assertEquals(err,"","Shouldn't be any error messages")
+        samba_tool_cmd = self._samba_tool_cmdline("options")
+        # disable replication
+        self.check_run("%s %s --dsa-option=-DISABLE_INBOUND_REPL" %(samba_tool_cmd, DC))
+        self.check_run("%s %s --dsa-option=-DISABLE_OUTBOUND_REPL" %(samba_tool_cmd, DC))
 
     def _disable_all_repl(self, DC):
-        self.disable_inbound_repl(DC)
         # make base command line
-        samba_tool_cmdline = self._samba_tool_cmdline("options")
+        samba_tool_cmd = self._samba_tool_cmdline("options")
         # disable replication
-        samba_tool_cmdline += [DC, "--dsa-option=+DISABLE_OUTBOUND_REPL"]
-        (result, out, err) = self.runsubcmd(*samba_tool_cmdline)
-        self.assertCmdSuccess(result, out, err)
-        self.assertEquals(err,"","Shouldn't be any error messages")
+        self.check_run("%s %s --dsa-option=+DISABLE_INBOUND_REPL" %(samba_tool_cmd, DC))
+        self.check_run("%s %s --dsa-option=+DISABLE_OUTBOUND_REPL" %(samba_tool_cmd, DC))
 
     def _get_highest_hwm_utdv(self, ldb_conn):
         res = ldb_conn.search("", scope=ldb.SCOPE_BASE, attrs=["highestCommittedUSN"])
-- 
2.9.4


From ca6816427eb0323aaeb4de32520dd7c04a158b34 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 16:09:54 +1200
Subject: [PATCH 13/17] selftest: Port DrsBaseTestCase._disable_inbound_repl()
 to self.runsubcmd()

This avoids forking a subprocess with self.check_run()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/torture/drs/python/drs_base.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index 5ddd2a7..03131d7 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -146,9 +146,12 @@ class DrsBaseTestCase(SambaToolCmdTest):
 
     def _disable_inbound_repl(self, DC):
         # make base command line
-        samba_tool_cmd = self._samba_tool_cmdline("options")
+        samba_tool_cmd = self._samba_tool_cmd_list("options")
         # disable replication
-        self.check_run("%s %s --dsa-option=+DISABLE_INBOUND_REPL" %(samba_tool_cmd, DC))
+        samba_tool_cmd += [DC, "--dsa-option=+DISABLE_INBOUND_REPL"]
+        (result, out, err) = self.runsubcmd(*samba_tool_cmd)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEquals(err,"","Shouldn't be any error messages")
 
     def _enable_all_repl(self, DC):
         # make base command line
-- 
2.9.4


From 3dff5a3ec7ad9139313714580463e53bc35ff2eb Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 16:11:12 +1200
Subject: [PATCH 14/17] selftest: Port DrsBaseTestCase._{en,dis}able_all_repl()
 to self.runsubcmd()

This avoids forking a subprocess with self.check_run()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/torture/drs/python/drs_base.py | 30 +++++++++++++-----------------
 1 file changed, 13 insertions(+), 17 deletions(-)

diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index 03131d7..c215003 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -98,16 +98,6 @@ class DrsBaseTestCase(SambaToolCmdTest):
     def _make_obj_name(self, prefix):
         return prefix + time.strftime("%s", time.gmtime())
 
-    def _samba_tool_cmdline(self, drs_command):
-        # find out where is net command
-        samba_tool_cmd = os.path.abspath("./bin/samba-tool")
-        # make command line credentials string
-        creds = self.get_credentials()
-        cmdline_auth = "-U%s/%s%%%s" % (creds.get_domain(),
-                                        creds.get_username(), creds.get_password())
-        # bin/samba-tool drs <drs_command> <cmdline_auth>
-        return "%s drs %s %s" % (samba_tool_cmd, drs_command, cmdline_auth)
-
     def _samba_tool_cmd_list(self, drs_command):
         # make command line credentials string
         creds = self.get_credentials()
@@ -154,18 +144,24 @@ class DrsBaseTestCase(SambaToolCmdTest):
         self.assertEquals(err,"","Shouldn't be any error messages")
 
     def _enable_all_repl(self, DC):
+        self._enable_inbound_repl(DC)
         # make base command line
-        samba_tool_cmd = self._samba_tool_cmdline("options")
-        # disable replication
-        self.check_run("%s %s --dsa-option=-DISABLE_INBOUND_REPL" %(samba_tool_cmd, DC))
-        self.check_run("%s %s --dsa-option=-DISABLE_OUTBOUND_REPL" %(samba_tool_cmd, DC))
+        samba_tool_cmd = self._samba_tool_cmd_list("options")
+        # enable replication
+        samba_tool_cmd += [DC, "--dsa-option=-DISABLE_OUTBOUND_REPL"]
+        (result, out, err) = self.runsubcmd(*samba_tool_cmd)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEquals(err,"","Shouldn't be any error messages")
 
     def _disable_all_repl(self, DC):
+        self._disable_inbound_repl(DC)
         # make base command line
-        samba_tool_cmd = self._samba_tool_cmdline("options")
+        samba_tool_cmd = self._samba_tool_cmd_list("options")
         # disable replication
-        self.check_run("%s %s --dsa-option=+DISABLE_INBOUND_REPL" %(samba_tool_cmd, DC))
-        self.check_run("%s %s --dsa-option=+DISABLE_OUTBOUND_REPL" %(samba_tool_cmd, DC))
+        samba_tool_cmd += [DC, "--dsa-option=+DISABLE_OUTBOUND_REPL"]
+        (result, out, err) = self.runsubcmd(*samba_tool_cmd)
+        self.assertCmdSuccess(result, out, err)
+        self.assertEquals(err,"","Shouldn't be any error messages")
 
     def _get_highest_hwm_utdv(self, ldb_conn):
         res = ldb_conn.search("", scope=ldb.SCOPE_BASE, attrs=["highestCommittedUSN"])
-- 
2.9.4


From 03a7d10153062202e73220070936577f70b91dbd Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 16:25:19 +1200
Subject: [PATCH 15/17] selftest: Use new --krb5-ccache in drs_base.py

This means that instead of doing a new kinit, the process-wide ccache
is re-used, which is much faster.

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/torture/drs/python/drs_base.py | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index c215003..8af1af3 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -100,9 +100,15 @@ class DrsBaseTestCase(SambaToolCmdTest):
 
     def _samba_tool_cmd_list(self, drs_command):
         # make command line credentials string
+
         creds = self.get_credentials()
-        cmdline_auth = "-U%s/%s%%%s" % (creds.get_domain(),
-                                        creds.get_username(), creds.get_password())
+        ccache = creds.get_named_ccache(self.get_loadparm())
+        ccache_name = ccache.get_name()
+
+        # Tunnel the command line credentials down to the
+        # subcommand to avoid a new kinit
+        cmdline_auth = "--krb5-ccache=%s" % ccache_name
+
         # bin/samba-tool drs <drs_command> <cmdline_auth>
         return ["drs", drs_command, cmdline_auth]
 
-- 
2.9.4


From cfefe78fbd5b794ec81fdbaf6c864bcc1fa5a436 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 16:29:14 +1200
Subject: [PATCH 16/17] selftest: Add and use new helper function
 get_creds_ccache_name()

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 python/samba/tests/__init__.py         | 7 +++++++
 source4/torture/drs/python/drs_base.py | 4 +---
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py
index 07c68c4..2ddfd9d 100644
--- a/python/samba/tests/__init__.py
+++ b/python/samba/tests/__init__.py
@@ -67,6 +67,13 @@ class TestCase(unittest.TestCase):
     def get_credentials(self):
         return cmdline_credentials
 
+    def get_creds_ccache_name(self):
+        creds = self.get_credentials()
+        ccache = creds.get_named_ccache(self.get_loadparm())
+        ccache_name = ccache.get_name()
+
+        return ccache_name
+
     def hexdump(self, src):
         N = 0
         result = ''
diff --git a/source4/torture/drs/python/drs_base.py b/source4/torture/drs/python/drs_base.py
index 8af1af3..9abfa15 100644
--- a/source4/torture/drs/python/drs_base.py
+++ b/source4/torture/drs/python/drs_base.py
@@ -101,9 +101,7 @@ class DrsBaseTestCase(SambaToolCmdTest):
     def _samba_tool_cmd_list(self, drs_command):
         # make command line credentials string
 
-        creds = self.get_credentials()
-        ccache = creds.get_named_ccache(self.get_loadparm())
-        ccache_name = ccache.get_name()
+        ccache_name = self.get_creds_ccache_name()
 
         # Tunnel the command line credentials down to the
         # subcommand to avoid a new kinit
-- 
2.9.4


From 42d773fbd2e466ab237dad4927f1b4b8be678361 Mon Sep 17 00:00:00 2001
From: Andrew Bartlett <abartlet at samba.org>
Date: Thu, 6 Jul 2017 16:31:15 +1200
Subject: [PATCH 17/17] selftest: Use get_creds_ccache_name() in fsmo.py

This avoids a new kinit for every role transfer

Signed-off-by: Andrew Bartlett <abartlet at samba.org>
---
 source4/torture/drs/python/fsmo.py | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/source4/torture/drs/python/fsmo.py b/source4/torture/drs/python/fsmo.py
index 4dd652d..50b7dc3 100644
--- a/source4/torture/drs/python/fsmo.py
+++ b/source4/torture/drs/python/fsmo.py
@@ -58,9 +58,8 @@ class DrsFsmoTestCase(drs_base.DrsBaseTestCase):
         # find out where is samba-tool command
         net_cmd = os.path.abspath("./bin/samba-tool")
         # make command line credentials string
-        creds = self.get_credentials()
-        cmd_line_auth = "-U%s/%s%%%s" % (creds.get_domain(),
-                                         creds.get_username(), creds.get_password())
+        ccache_name = self.get_creds_ccache_name()
+        cmd_line_auth = "--krb5-ccache=%s" % ccache_name
         (result, out, err) = self.runsubcmd("fsmo", "transfer",
                                             "--role=%s" % role,
                                             "-H", "ldap://%s:389" % DC,
-- 
2.9.4



More information about the samba-technical mailing list