cmogstored dev/user discussion/issues/patches/etc
 help / color / mirror / code / Atom feed
From: Eric Wong <e@80x24.org>
To: cmogstored-public@bogomips.org
Cc: Eric Wong <e@80x24.org>
Subject: [PATCH] support systemd-style socket activation via environment
Date: Wed, 11 Nov 2015 02:40:17 +0000	[thread overview]
Message-ID: <20151111024017.4786-1-e@80x24.org> (raw)

While I have my reservations about systemd, socket activation alone
is a good idea and we already have existing infrastructure for
supporting it in SIGUSR2 upgrades.

We are intentionally avoiding linkage to libsystemd to avoid dealing
with ABI compatibility issues between old and new systems.  This
also allows us to integrate more easily with non-systemd systems
which use the same environment variables as systemd.
---
 cmogstored.x    |  7 +++++++
 inherit.c       | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 test/inherit.rb | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+), 4 deletions(-)

diff --git a/cmogstored.x b/cmogstored.x
index bd5956d..a6b96e6 100644
--- a/cmogstored.x
+++ b/cmogstored.x
@@ -15,6 +15,13 @@ MOG_IOSTAT_CMD - command-line for invoking iostat(1).  This is used
 by the sidechannel to report disk utilization to trackers.
 Default: "iostat -dx 1 30"
 
+LISTEN_FDS, LISTEN_PID - may be used for systemd-style socket activation
+regardless of whether systemd is on the system.  See sd_listen_fds(3)
+for more information.  Since cmogstored supports two protocols on
+different sockets, the command line or config file must still specify
+which addresses to listen on.  This feature is available in cmogstored
+1.5.0 and later.
+
 See MALLOC TUNING for environment variables which may affect memory
 usage.
 
diff --git a/inherit.c b/inherit.c
index ca7afa7..0229a04 100644
--- a/inherit.c
+++ b/inherit.c
@@ -89,6 +89,55 @@ static bool listener_close_each(void *_l, void *unused)
 	return true;
 }
 
+static void listeners_init(void)
+{
+	if (listeners) return;
+	listeners = hash_initialize(3, NULL, listener_hash, listener_cmp, free);
+	mog_oom_if_null(listeners);
+	atexit(listeners_cleanup);
+}
+
+static unsigned long listen_env(const char *env)
+{
+	const char *e = getenv(env);
+	unsigned long tmp;
+	char *end;
+
+	if (!e) return ULONG_MAX;
+	errno = 0;
+	tmp = strtoul(e, &end, 10);
+	if (errno) die_errno("failed to parse %s: %s", env, e);
+	if (*end) die("trailing byte in %s: %s", env, e);
+
+	return tmp;
+}
+
+/* systemd-style socket activation in the vein of sd_listen_fds(3) */
+static void systemd_inherit_fds(void)
+{
+	const int listen_fds_start = 3; /* SD_LISTEN_FDS_START */
+	int fd, listen_fds_end;
+	unsigned long tmp = listen_env("LISTEN_PID");
+
+	if (getpid() != (pid_t)tmp) goto out;
+
+	tmp = listen_env("LISTEN_FDS");
+	if (tmp > INT_MAX) die("LISTEN_FDS out of range: %lu", tmp);
+
+	listeners_init();
+	listen_fds_end = listen_fds_start + (int)tmp;
+	for (fd = listen_fds_start; fd < listen_fds_end; fd++) {
+		if (mog_set_cloexec(fd, true) == 0)
+			register_listen_fd(fd);
+		else
+			die("inherited out %d of %lu LISTEN_FDS",
+			    fd - listen_fds_start, tmp);
+	}
+out:
+	unsetenv("LISTEN_FDS");
+	unsetenv("LISTEN_PID");
+}
+
 /* close all inherited listeners we do not need */
 void mog_inherit_cleanup(void)
 {
@@ -131,13 +180,12 @@ void mog_inherit_init(void)
 	unsigned long fd;
 	unsigned endbyte;
 
+	systemd_inherit_fds();
+
 	if (orig == NULL)
 		return;
 
-	listeners = hash_initialize(3, NULL, listener_hash, listener_cmp, free);
-	mog_oom_if_null(listeners);
-	atexit(listeners_cleanup);
-
+	listeners_init();
 	fds = xstrdup(orig);
 	tip = fds;
 
diff --git a/test/inherit.rb b/test/inherit.rb
index b342ab0..34aa52f 100644
--- a/test/inherit.rb
+++ b/test/inherit.rb
@@ -142,4 +142,36 @@ def test_inherit_high
     @err.rewind
     assert_match(/failed to parse/, @err.read)
   end
+
+  def test_inherit_systemd
+    # disabled test on old Rubies: https://bugs.ruby-lang.org/issues/11336
+    # [ruby-core:69895] [Bug #11336] fixed by r51576
+    return unless RUBY_VERSION.to_f >= 2.3
+
+    mgmt = TCPServer.new(@host, 0)
+    @to_close << mgmt
+    mport = mgmt.addr[1]
+    cmd = %W(cmogstored --docroot=#@tmpdir --httplisten=#@host:#@port
+             --mgmtlisten=#@host:#{mport} --maxconns=100)
+    @pid = fork do
+      ENV['LISTEN_PID'] = "#$$"
+      ENV['LISTEN_FDS'] = '2'
+      exec(*cmd, 3 => mgmt.fileno, 4 => @srv.fileno)
+    end
+
+    # just ensure HTTP works after being inherited
+    Net::HTTP.start(@host, @port) do |http|
+      [ Net::HTTP::Get, Net::HTTP::Head ].each do |meth|
+        resp = http.request(meth.new("/"))
+        assert_kind_of Net::HTTPOK, resp
+      end
+    end
+
+    # still works since drop is open in _this_ process
+    c = TCPSocket.new(@host, mport)
+    assert_instance_of(TCPSocket, c)
+    @to_close << c
+    c.write "hello\n"
+    assert_match /ERROR: unknown command/, c.gets
+  end
 end
-- 
EW


             reply	other threads:[~2015-11-11  2:40 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-11  2:40 Eric Wong [this message]
2015-11-11  3:38 ` [PATCH] set TCP listener options on inherited sockets Eric Wong
2015-11-11  4:01 ` [PATCH] doc: add example systemd config files Eric Wong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://yhbt.net/cmogstored/README

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20151111024017.4786-1-e@80x24.org \
    --to=e@80x24.org \
    --cc=cmogstored-public@bogomips.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://yhbt.net/cmogstored.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).