Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Willingness to support non-forking readiness notification for s6 and other service supervisors?#21

Closed
CameronNemo opened this issue Jun 28, 2019 · 8 comments

Comments

@CameronNemo
Copy link

CameronNemo commented Jun 28, 2019

Hello,

I have implemented a non-forking service readiness notification that is compatible with the s6 service supervision suite as well as my own personal fork of Upstart.

Would you accept a patch to support this protocol, which would:

  • accept a CLI argument telling nsd when to use the mechanism
  • grab an fd number from the environment and write a newline to it
  • close the fd and unset the environment variable

The patch would look largely similar to swaywm/swaylock#42 or apple/cups#5507.

More information on the mechanism can be found at https://gitlab.com/chinstrap/ready

Regards,
Cameron Nemo

@tomascharvat
Copy link

Running NSD from Daemontools I would also welcome option not to use PID file. As its useless if your NSD run supervised and it simplify configuration.

If I comment out pid from nsd.conf, /var/run/nsd.pid is used .. and its outside of working directory, outside chroot...... so I have to deal with another non-rediness to operate under supervision.

At least PID file did not prevent NSD from start if it get killed by KILL.

Please consider option to disable PID.

wcawijngaards added a commit that referenced this issue Sep 2, 2019
  startup management tools like daemontools.
@wcawijngaards
Copy link
Member

Hi,
So I added the option to set the pidfile to "", this disables the pidfile. That should help enable this different startup processing to some extent.
For the readiness notification, I would simply want to wait to see if there are users. We already have libsystemd notification support. We do not really want to just implement features that are not used.

@CameronNemo
Copy link
Author

re: pidfile, thanks I find stray PID files a frustration often.

re: readiness notification

See there is a chicken-egg scenario. A certain threshold of services must implement it before it can be generally useful. I am not asking that you implement the feature, just review my implementation which will likely end up being ~100 lines with no modification to the build system necessary (but can be done).

@wcawijngaards
Copy link
Member

So, I do not want unused code, because of wanting avoid code bloat. But at the same time I want to support startup management systems, and also that the software works well for being managed. We have a contrib directory with patches, and files where this could go. It already contains a number of things, package management scripts, startup scripts, rc.d scripts, systemd example files, ... And also code patches like libfastrpz.
So I think the contrib dir patch file is a good idea, you can contribute the code you want, and we'll include it into the git repo and release tarballs.

@wcawijngaards
Copy link
Member

Oh, and if there is more to the integration than that, eg. settings or config files for the s6 integration, then you can also add a file that is an example how to do this. eg. instruct how to set it up to integrate with the startup management system, or the file or settings the user needs to set it up so the readiness notification gets used.

@CameronNemo
Copy link
Author

I have successfully used the following patch with my supervisor, startup.

diff --git nsd.c nsd.c
index 98dec613..e9d7b2cc 100644
--- nsd.c
+++ nsd.c
@@ -91,6 +91,9 @@ usage (void)
 		"  -n tcp-count         The maximum number of TCP connections per server.\n"
 		"  -P pidfile           Specify the PID file to write.\n"
 		"  -p port              Specify the port to listen to.\n"
+		"  -r                   Print a newline into the file descriptor index\n"
+		"                          described in the READY_FD environment variable to\n"
+		"                          indicate that nsd is ready to accept connections.\n"
 		"  -s seconds           Dump statistics every SECONDS seconds.\n"
 		"  -t chrootdir         Change root to specified directory on startup.\n"
 		);
@@ -323,6 +326,24 @@ sig_handler(int sig)
 	}
 }
 
+/*
+ * Parse envvar as a positive integer.
+ *
+ */
+int
+get_fd_from_env(const char* key)
+{
+	char *env = getenv(key);
+	if (!env || env[0] == '\0')
+		return -1;
+	errno = 0;
+	char *endptr;
+	int fd = (int)strtol(env, &endptr, 10);
+	if (errno != 0 || endptr[0] != '\0')
+		return -1;
+	return fd;
+}
+
 /*
  * Statistic output...
  *
@@ -450,7 +471,7 @@ main(int argc, char *argv[])
 	}
 
 	/* Parse the command line... */
-	while ((c = getopt(argc, argv, "46a:c:df:hi:I:l:N:n:P:p:s:u:t:X:V:v"
+	while ((c = getopt(argc, argv, "46a:c:df:hi:I:l:N:n:P:p:rs:u:t:X:V:v"
 #ifndef NDEBUG /* <mattthijs> only when configured with --enable-checking */
 		"F:L:"
 #endif /* NDEBUG */
@@ -533,6 +554,9 @@ main(int argc, char *argv[])
 			tcp_port = optarg;
 			udp_port = optarg;
 			break;
+		case 'r':
+			nsd.readyfd = 1;
+			break;
 		case 's':
 #ifdef BIND8_STATS
 			nsd.st.period = atoi(optarg);
@@ -965,6 +989,18 @@ main(int argc, char *argv[])
 	}
 #endif /* HAVE_SSL */
 
+	/* When asked to notify readiness via REⒶDY_FD, do so. */
+	if (nsd.readyfd) {
+		int readyfd = get_fd_from_env("READY_FD");
+		if (readyfd < 0)
+			error("READY_FD unset or contains garbage");
+		unsetenv("READY_FD");
+		int ret = dprintf(readyfd, "\n");
+		close(readyfd);
+		if (ret < 0)
+			error("could not write to READY_FD index");
+	}
+
 	/* Unless we're debugging, fork... */
 	if (!nsd.debug) {
 		int fd;
diff --git nsd.h nsd.h
index de3ae8e1..ff27b798 100644
--- nsd.h
+++ nsd.h
@@ -179,6 +179,7 @@ struct	nsd
 	unsigned		server_kind;
 	struct namedb	*db;
 	int				debug;
+	int readyfd;
 
 	size_t            child_count;
 	struct nsd_child *children;

wcawijngaards added a commit that referenced this issue Oct 21, 2019
  contrib/patch_for_s6_startup_and_other_service_supervisors.diff
  that adds support for readiness notification with READY_FD from
  Cameron Nemo.
@wcawijngaards
Copy link
Member

Thanks for the patch, I added it to the repository with a note in contrib/README.
The file is called contrib/patch_for_s6_startup_and_other_service_supervisors.diff.

@Crest
Copy link

Crest commented Aug 2, 2022

It would be really helpful to enable this feature by default. That way it would trickle downstream into package managers for ready to use instead of requiring users to apply the patch and build from the patched source bypassing package managers. This patch doesn't add any additional dependencies and adds just a handful of lines. It would also prevent this useful patch from falling prey to bitrot as the code diverges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants