[PATCH] add smbcontrol sleep command.

Gary Lockyer gary at catalyst.net.nz
Mon Dec 10 03:02:55 UTC 2018


Add a sleep option to smbcontrol causing the target process to sleep for
the specified number of seconds.
Add support for the smbcontrol inject fault command to the samba daemon.

Both are useful for interactive testing, of process failure and for
triggering timeouts.

CI results: https://gitlab.com/samba-team/devel/samba/pipelines/39499851
Merge Request: https://gitlab.com/samba-team/samba/merge_requests/144

As always review and comments appreciated

Ngā mihi
Gary
-------------- next part --------------
From 3a870c8f0dbbdbd9f61e636690a3983a0829e67b Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Wed, 5 Dec 2018 10:56:42 +1300
Subject: [PATCH 1/6] s4 messaging tests: Add inject fault command

Test for processing of the smbcontrol inject fault message in the samba
daemon.

Signed-off-by: Gary Lockyer<gary at catalyst.net.nz>
---
 .../tests/blackbox/smbcontrol_process.py      | 85 +++++++++++++++++++
 selftest/knownfail.d/smbcontrol               |  1 +
 source4/selftest/tests.py                     |  7 ++
 3 files changed, 93 insertions(+)
 create mode 100644 python/samba/tests/blackbox/smbcontrol_process.py
 create mode 100755 selftest/knownfail.d/smbcontrol

diff --git a/python/samba/tests/blackbox/smbcontrol_process.py b/python/samba/tests/blackbox/smbcontrol_process.py
new file mode 100644
index 00000000000..342bace8422
--- /dev/null
+++ b/python/samba/tests/blackbox/smbcontrol_process.py
@@ -0,0 +1,85 @@
+# Blackbox tests for the smbcontrol fault injection commands
+#
+# Copyright (C) Andrew Bartlett <abartlet at samba.org> 2018
+#
+# 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/>.
+#
+# As the test terminates and sleeps samba processes these tests need to run
+# in the preforkrestartdc test environment to prevent them impacting other
+# tests.
+#
+from __future__ import print_function
+from samba.tests import BlackboxTestCase, BlackboxProcessError
+from samba.messaging import Messaging
+
+COMMAND = "bin/smbcontrol"
+PING = "ping"
+
+
+class SmbcontrolProcessBlockboxTests(BlackboxTestCase):
+
+    def setUp(self):
+        super(SmbcontrolProcessBlockboxTests, self).setUp()
+        lp_ctx = self.get_loadparm()
+        self.msg_ctx = Messaging(lp_ctx=lp_ctx)
+
+    def get_process_data(self):
+        services = self.msg_ctx.irpc_all_servers()
+
+        processes = []
+        for service in services:
+            for id in service.ids:
+                processes.append((service.name, id.pid))
+        return processes
+
+    def get_process(self, name):
+        processes = self.get_process_data()
+        for pname, pid in processes:
+            if name == pname:
+                return pid
+        return None
+
+    def test_inject_fault(self):
+        INJECT = "inject"
+        FAULT = "segv"
+        pid = self.get_process("rpc_server")
+
+        #
+        # Ensure we can ping the process before injecting a fault.
+        #
+        try:
+            self.check_run("%s %s %s" % (COMMAND, pid, PING),
+                           msg="trying to ping rpc_server")
+        except BlackboxProcessError as e:
+            self.fail("Unable to ping rpc_server process")
+
+        #
+        # Now inject a fault.
+        #
+        try:
+            self.check_run("%s %s %s %s" % (COMMAND, pid, INJECT, FAULT),
+                           msg="injecting fault into rpc_server")
+        except BlackboxProcessError as e:
+            print(e)
+            self.fail("Unable to inject a fault into the rpc_server process")
+
+        #
+        # The process should have died, so we should not be able to ping it
+        #
+        try:
+            self.check_run("%s %s %s" % (COMMAND, pid, PING),
+                           msg="trying to ping rpc_server")
+            self.fail("Could ping rpc_server process")
+        except BlackboxProcessError as e:
+            pass
diff --git a/selftest/knownfail.d/smbcontrol b/selftest/knownfail.d/smbcontrol
new file mode 100755
index 00000000000..2747e67c4eb
--- /dev/null
+++ b/selftest/knownfail.d/smbcontrol
@@ -0,0 +1 @@
+^samba.tests.blackbox.smbcontrol_process.samba.tests.blackbox.smbcontrol_process.SmbcontrolProcessBlockboxTests.test_inject_fault\(preforkrestartdc:local\)
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index c676b878b83..d8be5e6c57c 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -1255,6 +1255,13 @@ planoldpythontestsuite("preforkrestartdc:local",
                        extra_args=['-U"$USERNAME%$PASSWORD"'],
                        name="samba.tests.prefork_restart",
                        py3_compatible=True)
+planoldpythontestsuite("preforkrestartdc:local",
+                       "samba.tests.blackbox.smbcontrol_process",
+                       extra_path=[
+                           os.path.join(srcdir(), 'python/samba/tests')],
+                       extra_args=['-U"$USERNAME%$PASSWORD"'],
+                       name="samba.tests.blackbox.smbcontrol_process",
+                       py3_compatible=True)
 planoldpythontestsuite("proclimitdc:local",
                        "samba.tests.process_limits",
                        extra_path=[
-- 
2.18.1


From 2fe515f76b743afa45b6a387510c9d0fdcacf389 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Tue, 4 Dec 2018 09:28:56 +1300
Subject: [PATCH 2/6] s4 messaging: support smbcontrol inject fault command

Add support of the smbcontrol inject fault command to the samba daemon.
This is useful for manual testing of process restart etc.

command is only enabled for developer and self test builds

Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
---
 selftest/knownfail.d/smbcontrol   |  1 -
 source3/utils/smbcontrol.c        |  8 +++---
 source4/lib/messaging/messaging.c | 46 +++++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+), 5 deletions(-)
 delete mode 100755 selftest/knownfail.d/smbcontrol

diff --git a/selftest/knownfail.d/smbcontrol b/selftest/knownfail.d/smbcontrol
deleted file mode 100755
index 2747e67c4eb..00000000000
--- a/selftest/knownfail.d/smbcontrol
+++ /dev/null
@@ -1 +0,0 @@
-^samba.tests.blackbox.smbcontrol_process.samba.tests.blackbox.smbcontrol_process.SmbcontrolProcessBlockboxTests.test_inject_fault\(preforkrestartdc:local\)
diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c
index 866217c248b..8ba31c9f841 100644
--- a/source3/utils/smbcontrol.c
+++ b/source3/utils/smbcontrol.c
@@ -380,11 +380,11 @@ static bool do_inject_fault(struct tevent_context *ev_ctx,
 		return False;
 	}
 
-#ifndef DEVELOPER
+#if !defined(DEVELOPER) && !defined(ENABLE_SELFTEST)
 	fprintf(stderr, "Fault injection is only available in "
-		"developer builds\n");
+		"developer and self test builds\n");
 	return False;
-#else /* DEVELOPER */
+#else /* DEVELOPER || ENABLE_SELFTEST */
 	{
 		int sig = 0;
 
@@ -407,7 +407,7 @@ static bool do_inject_fault(struct tevent_context *ev_ctx,
 		return send_message(msg_ctx, pid, MSG_SMB_INJECT_FAULT,
 				    &sig, sizeof(int));
 	}
-#endif /* DEVELOPER */
+#endif /* DEVELOPER || ENABLE_SELFTEST */
 }
 
 /* Force a browser election */
diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c
index 413a19445eb..2832d9ddd43 100644
--- a/source4/lib/messaging/messaging.c
+++ b/source4/lib/messaging/messaging.c
@@ -84,6 +84,45 @@ static void ping_message(struct imessaging_context *msg, void *private_data,
 	imessaging_send(msg, src, MSG_PONG, data);
 }
 
+#if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
+/*
+ * Inject a fault into the currently running process
+ */
+static void do_inject_fault(struct imessaging_context *msg,
+			    void *private_data,
+			    uint32_t msg_type,
+			    struct server_id src,
+			    DATA_BLOB *data)
+{
+	int sig;
+	struct server_id_buf tmp;
+
+	if (data->length != sizeof(sig)) {
+		DBG_ERR("Process %s sent bogus signal injection request\n",
+			server_id_str_buf(src, &tmp));
+		return;
+	}
+
+	sig = *(int *)data->data;
+	if (sig == -1) {
+		DBG_ERR("Process %s requested an iternal failure, "
+			"calling exit(1)\n",
+			server_id_str_buf(src, &tmp));
+		exit(1);
+	}
+
+#if HAVE_STRSIGNAL
+	DBG_ERR("Process %s requested injection of signal %d (%s)\n",
+		server_id_str_buf(src, &tmp), sig, strsignal(sig));
+#else
+	DBG_ERR("Process %s requested injection of signal %d\n",
+		server_id_str_buf(src, &tmp), sig);
+#endif
+
+	kill(getpid(), sig);
+}
+#endif /* defined(DEVELOPER) || defined(ENABLE_SELFTEST) */
+
 static void pool_message(struct imessaging_context *msg, void *private_data,
 			 uint32_t msg_type, struct server_id src,
 			 DATA_BLOB *data)
@@ -464,6 +503,13 @@ static struct imessaging_context *imessaging_init_internal(TALLOC_CTX *mem_ctx,
 	if (!NT_STATUS_IS_OK(status)) {
 		goto fail;
 	}
+#if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
+	status = imessaging_register(
+	    msg, NULL, MSG_SMB_INJECT_FAULT, do_inject_fault);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto fail;
+	}
+#endif /* defined(DEVELOPER) || defined(ENABLE_SELFTEST) */
 
 	DLIST_ADD(msg_ctxs, msg);
 
-- 
2.18.1


From 449bef0dbefa4b1961205b0b69ffa005ecab6183 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Wed, 5 Dec 2018 14:50:22 +1300
Subject: [PATCH 3/6] s4 messaging tests: Tests for smbcontrol sleep command

Add a sleep command that pauses the target process for the specified
number seconds

This command is only enabled on developer and self test builds.

Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
---
 .../tests/blackbox/smbcontrol_process.py      | 39 +++++++++++++++++++
 selftest/knownfail.d/smbcontrol               |  1 +
 2 files changed, 40 insertions(+)
 create mode 100644 selftest/knownfail.d/smbcontrol

diff --git a/python/samba/tests/blackbox/smbcontrol_process.py b/python/samba/tests/blackbox/smbcontrol_process.py
index 342bace8422..4313c6faef3 100644
--- a/python/samba/tests/blackbox/smbcontrol_process.py
+++ b/python/samba/tests/blackbox/smbcontrol_process.py
@@ -20,6 +20,7 @@
 # tests.
 #
 from __future__ import print_function
+import time
 from samba.tests import BlackboxTestCase, BlackboxProcessError
 from samba.messaging import Messaging
 
@@ -83,3 +84,41 @@ class SmbcontrolProcessBlockboxTests(BlackboxTestCase):
             self.fail("Could ping rpc_server process")
         except BlackboxProcessError as e:
             pass
+
+    def test_sleep(self):
+        SLEEP = "sleep"  # smbcontrol sleep command
+        DURATION = 5     # duration to sleep server for
+        DELTA = 1        # permitted error for the sleep duration
+
+        pid = self.get_process("rpc_server")
+        #
+        # Ensure we can ping the process before getting it to sleep
+        #
+        try:
+            self.check_run("%s %s %s" % (COMMAND, pid, PING),
+                           msg="trying to ping rpc_server")
+        except BlackboxProcessError as e:
+            self.fail("Unable to ping rpc_server process")
+
+        #
+        # Now ask it to sleep
+        #
+        start = time.time()
+        try:
+            self.check_run("%s %s %s %s" % (COMMAND, pid, SLEEP, DURATION),
+                           msg="putting rpc_server to sleep for %d" % DURATION)
+        except BlackboxProcessError as e:
+            print(e)
+            self.fail("Failed to get rpc_server to sleep for %d" % DURATION)
+
+        #
+        # The process should be sleeping and not respond until it wakes
+        #
+        try:
+            self.check_run("%s %s %s" % (COMMAND, pid, PING),
+                           msg="trying to ping rpc_server")
+            end = time.time()
+            duration = end - start
+            self.assertGreater(duration + DELTA, DURATION)
+        except BlackboxProcessError as e:
+            self.fail("Unable to ping rpc_server process")
diff --git a/selftest/knownfail.d/smbcontrol b/selftest/knownfail.d/smbcontrol
new file mode 100644
index 00000000000..d9e5480a83e
--- /dev/null
+++ b/selftest/knownfail.d/smbcontrol
@@ -0,0 +1 @@
+^samba.tests.blackbox.smbcontrol_process.samba.tests.blackbox.smbcontrol_process.SmbcontrolProcessBlockboxTests.test_sleep\(preforkrestartdc:local\)
-- 
2.18.1


From 45bb222206244ce2c9347743a441d1fdcfb08b98 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Tue, 4 Dec 2018 09:31:22 +1300
Subject: [PATCH 4/6] s3 smbcontrol: Add sleep command

Add a sleep command that pauses the target process for the specified
number of seconds

This command is only enabled on developer and self test builds.

Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
---
 librpc/idl/messaging.idl   |  1 +
 source3/utils/smbcontrol.c | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/librpc/idl/messaging.idl b/librpc/idl/messaging.idl
index c916768ccec..c2f62f673b2 100644
--- a/librpc/idl/messaging.idl
+++ b/librpc/idl/messaging.idl
@@ -109,6 +109,7 @@ interface messaging
 		MSG_SMB_NOTIFY_DB		= 0x031D,
 		MSG_SMB_NOTIFY_REC_CHANGES	= 0x031E,
 		MSG_SMB_NOTIFY_STARTED          = 0x031F,
+		MSG_SMB_SLEEP			= 0x0320,
 
 		/* winbind messages */
 		MSG_WINBIND_FINISHED		= 0x0401,
diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c
index 8ba31c9f841..1d60f0eeef8 100644
--- a/source3/utils/smbcontrol.c
+++ b/source3/utils/smbcontrol.c
@@ -410,6 +410,43 @@ static bool do_inject_fault(struct tevent_context *ev_ctx,
 #endif /* DEVELOPER || ENABLE_SELFTEST */
 }
 
+static bool do_sleep(struct tevent_context *ev_ctx,
+		     struct messaging_context *msg_ctx,
+		     const struct server_id pid,
+		     const int argc, const char **argv)
+{
+	unsigned int seconds;
+	long input;
+	const long MAX_SLEEP = 60 * 60; /* One hour maximum sleep */
+
+	if (argc != 2) {
+		fprintf(stderr, "Usage: smbcontrol <dest> sleep seconds\n");
+		return False;
+	}
+
+#if !defined(DEVELOPER) && !defined(ENABLE_SELFTEST)
+	fprintf(stderr, "Sleep is only available in "
+		"developer and self test builds\n");
+	return False;
+#else /* DEVELOPER || ENABLE_SELFTEST */
+
+	input = atol(argv[1]);
+	if (input < 1 || input > MAX_SLEEP) {
+		fprintf(stderr,
+			"Invalid duration for sleep '%s'\n"
+			"It should be at least 1 second and no more than %ld\n",
+			argv[1],
+			MAX_SLEEP);
+		return False;
+	}
+	seconds = input;
+	return send_message(msg_ctx, pid,
+			    MSG_SMB_SLEEP,
+			    &seconds,
+			    sizeof(unsigned int));
+#endif /* DEVELOPER || ENABLE_SELFTEST */
+}
+
 /* Force a browser election */
 
 static bool do_election(struct tevent_context *ev_ctx,
@@ -1421,6 +1458,7 @@ static const struct {
 	  "Print number of smbd child processes" },
 	{ "msg-cleanup", do_msg_cleanup },
 	{ "noop", do_noop, "Do nothing" },
+	{ "sleep", do_sleep, "Cause the target process to sleep" },
 	{ NULL }
 };
 
-- 
2.18.1


From b7424ac37c6057d9760397f405f169c123cafe08 Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Thu, 6 Dec 2018 14:26:22 +1300
Subject: [PATCH 5/6] s3 server: Add support for smbcontrol sleep

Add a sleep command that pauses the target process for the specified number
of seconds

This command is only enabled on developer builds.

Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
---
 source3/smbd/server.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 68cd1d7bd54..33805b01a5c 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -193,6 +193,36 @@ static void msg_inject_fault(struct messaging_context *msg,
 }
 #endif /* DEVELOPER */
 
+#ifdef DEVELOPER
+/*
+ * Sleep for the specified number of seconds.
+ */
+static void msg_sleep(struct messaging_context *msg,
+		      void *private_data,
+		      uint32_t msg_type,
+		      struct server_id src,
+		      DATA_BLOB *data)
+{
+	unsigned int seconds;
+	struct server_id_buf tmp;
+
+	if (data->length != sizeof(seconds)) {
+		DBG_ERR("Process %s sent bogus sleep request\n",
+			server_id_str_buf(src, &tmp));
+		return;
+	}
+
+	seconds = *(unsigned int *)data->data;
+	DBG_ERR("Process %s request a sleep of %u seconds\n",
+		server_id_str_buf(src, &tmp),
+		seconds);
+	sleep(seconds);
+	DBG_ERR("Restarting after %u second sleep requested by process %s\n",
+		seconds,
+		server_id_str_buf(src, &tmp));
+}
+#endif /* DEVELOPER */
+
 static NTSTATUS messaging_send_to_children(struct messaging_context *msg_ctx,
 					   uint32_t msg_type, DATA_BLOB* data)
 {
@@ -1301,6 +1331,10 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent,
 			   msg_inject_fault);
 #endif
 
+#ifdef DEVELOPER
+	messaging_register(msg_ctx, NULL, MSG_SMB_INJECT_FAULT, msg_sleep);
+#endif
+
 	if (lp_multicast_dns_register() && (dns_port != 0)) {
 #ifdef WITH_DNSSD_SUPPORT
 		smbd_setup_mdns_registration(ev_ctx,
-- 
2.18.1


From e83ad5a4744db7f9f39939cd04147491d8765b7d Mon Sep 17 00:00:00 2001
From: Gary Lockyer <gary at catalyst.net.nz>
Date: Thu, 6 Dec 2018 14:27:31 +1300
Subject: [PATCH 6/6] s4 messaging: Add support for smbcontrol sleep

Add a sleep command that pauses the target process for the specified
number of seconds

This command is only enabled on developer and self test builds.

Signed-off-by: Gary Lockyer <gary at catalyst.net.nz>
---
 selftest/knownfail.d/smbcontrol   |  1 -
 source4/lib/messaging/messaging.c | 36 +++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)
 delete mode 100644 selftest/knownfail.d/smbcontrol

diff --git a/selftest/knownfail.d/smbcontrol b/selftest/knownfail.d/smbcontrol
deleted file mode 100644
index d9e5480a83e..00000000000
--- a/selftest/knownfail.d/smbcontrol
+++ /dev/null
@@ -1 +0,0 @@
-^samba.tests.blackbox.smbcontrol_process.samba.tests.blackbox.smbcontrol_process.SmbcontrolProcessBlockboxTests.test_sleep\(preforkrestartdc:local\)
diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c
index 2832d9ddd43..b7ecc06456a 100644
--- a/source4/lib/messaging/messaging.c
+++ b/source4/lib/messaging/messaging.c
@@ -123,6 +123,36 @@ static void do_inject_fault(struct imessaging_context *msg,
 }
 #endif /* defined(DEVELOPER) || defined(ENABLE_SELFTEST) */
 
+#if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
+/*
+ * Cause the current process to sleep for a specified number of seconds
+ */
+static void do_sleep(struct imessaging_context *msg,
+			    void *private_data,
+			    uint32_t msg_type,
+			    struct server_id src,
+			    DATA_BLOB *data)
+{
+	unsigned int seconds;
+	struct server_id_buf tmp;
+
+	if (data->length != sizeof(seconds)) {
+		DBG_ERR("Process %s sent bogus sleep request\n",
+			server_id_str_buf(src, &tmp));
+		return;
+	}
+
+	seconds = *(unsigned int *)data->data;
+	DBG_ERR("Process %s requested a sleep of %u seconds\n",
+		server_id_str_buf(src, &tmp),
+		seconds);
+	sleep(seconds);
+	DBG_ERR("Restarting after %u second sleep requested by process %s\n",
+		seconds,
+		server_id_str_buf(src, &tmp));
+}
+#endif /* defined(DEVELOPER) || defined(ENABLE_SELFTEST) */
+
 static void pool_message(struct imessaging_context *msg, void *private_data,
 			 uint32_t msg_type, struct server_id src,
 			 DATA_BLOB *data)
@@ -510,6 +540,12 @@ static struct imessaging_context *imessaging_init_internal(TALLOC_CTX *mem_ctx,
 		goto fail;
 	}
 #endif /* defined(DEVELOPER) || defined(ENABLE_SELFTEST) */
+#if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
+	status = imessaging_register(msg, NULL, MSG_SMB_SLEEP, do_sleep);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto fail;
+	}
+#endif /* defined(DEVELOPER) || defined(ENABLE_SELFTEST) */
 
 	DLIST_ADD(msg_ctxs, msg);
 
-- 
2.18.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20181210/b50d942a/signature.sig>


More information about the samba-technical mailing list