[lxc-devel] [lxd/master] main_forkdns: Ensures forkdns remains running when LXD exits

tomponline on Github lxc-bot at linuxcontainers.org
Tue Jun 11 16:44:04 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 442 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190611/457f27c4/attachment.bin>
-------------- next part --------------
From a98648e58284e817517a2d250e9e0762b447c368 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 11 Jun 2019 17:14:31 +0100
Subject: [PATCH] main_forkdns: Ensures forkdns remains running when LXD exits

Adds double fork to forkdns.

Also adds PID path as first command argument.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/main_forkdns.go | 112 +++++++++++++++++++++++++++++++++++++++++---
 lxd/main_nsexec.go  |   3 ++
 lxd/networks.go     |  10 +---
 3 files changed, 109 insertions(+), 16 deletions(-)

diff --git a/lxd/main_forkdns.go b/lxd/main_forkdns.go
index 2ac8b0d366..3f11e830ea 100644
--- a/lxd/main_forkdns.go
+++ b/lxd/main_forkdns.go
@@ -20,6 +20,99 @@ import (
 	"github.com/lxc/lxd/shared/logging"
 )
 
+/*
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+extern char* advance_arg(bool required);
+
+static int wait_for_pid(pid_t pid)
+{
+	int status, ret;
+
+again:
+	ret = waitpid(pid, &status, 0);
+	if (ret == -1) {
+		if (errno == EINTR)
+			goto again;
+		return -1;
+	}
+	if (ret != pid)
+		goto again;
+	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+		return -1;
+	return 0;
+}
+
+void forkdns()
+{
+	ssize_t ret;
+	pid_t pid;
+	FILE *pid_file;
+	char *pid_path;
+
+	pid_path = advance_arg(true);
+
+	pid_file = fopen(pid_path, "we+");
+	if (!pid_file) {
+		fprintf(stderr,
+			"%s - Failed to create pid file for forkdns daemon\n",
+			strerror(errno));
+		_exit(EXIT_FAILURE);
+	}
+
+	// daemonize
+	pid = fork();
+	if (pid < 0)
+		_exit(EXIT_FAILURE);
+
+	if (pid != 0) {
+		ret = wait_for_pid(pid);
+		if (ret < 0)
+			_exit(EXIT_FAILURE);
+
+		_exit(EXIT_SUCCESS);
+	}
+
+	pid = fork();
+	if (pid < 0)
+		_exit(EXIT_FAILURE);
+
+	if (pid != 0) {
+		ret = fprintf(pid_file, "%d", pid);
+		fclose(pid_file);
+		if (ret < 0) {
+			fprintf(stderr, "Failed to write forkdns daemon pid %d to \"%s\"\n",
+				pid, pid_path);
+			ret = EXIT_FAILURE;
+		}
+		close(STDIN_FILENO);
+		close(STDOUT_FILENO);
+		close(STDERR_FILENO);
+		_exit(EXIT_SUCCESS);
+	}
+
+	ret = setsid();
+	if (ret < 0)
+		fprintf(stderr, "%s - Failed to setsid in forkdns daemon\n",
+			strerror(errno));
+}
+*/
+// #cgo CFLAGS: -std=gnu11 -Wvla
+import "C"
+
 type cmdForkDNS struct {
 	global *cmdGlobal
 }
@@ -303,7 +396,7 @@ func (h *dnsHandler) getLeaseHostByDNSName(dnsName string) (string, error) {
 func (c *cmdForkDNS) Command() *cobra.Command {
 	// Main subcommand
 	cmd := &cobra.Command{}
-	cmd.Use = "forkdns <listen address> <domain> <network name>"
+	cmd.Use = "forkdns <pid path> <listen address> <domain> <network name>"
 	cmd.Short = "Internal DNS proxy for clustering"
 	cmd.Long = `Description:
   Spawns a specialised DNS server designed for relaying A and PTR queries that cannot be answered by
@@ -324,7 +417,7 @@ func (c *cmdForkDNS) Command() *cobra.Command {
 
 func (c *cmdForkDNS) Run(cmd *cobra.Command, args []string) error {
 	// Sanity checks
-	if len(args) < 3 {
+	if len(args) < 4 {
 		cmd.Help()
 
 		if len(args) == 0 {
@@ -346,24 +439,29 @@ func (c *cmdForkDNS) Run(cmd *cobra.Command, args []string) error {
 		return fmt.Errorf("Unable to setup fsnotify: %s", err)
 	}
 
-	networkName := args[2]
-	err = watcher.Watch(shared.VarPath("networks", networkName, forkdnsServersListPath))
+	networkName := args[3]
+	path := shared.VarPath("networks", networkName, forkdnsServersListPath)
+	err = watcher.Watch(path)
 	if err != nil {
-		return fmt.Errorf("Unable to setup fsnotify watch: %s", err)
+		return fmt.Errorf("Unable to setup fsnotify watch on %s: %s", path, err)
 	}
 
+	os.Stdin.Close()
+	os.Stderr.Close()
+	os.Stdout.Close()
+
 	// Run the server list monitor concurrently waiting for file changes.
 	go serversFileMonitor(watcher, networkName)
 
 	logger.Info("Started")
 
 	srv := &dns.Server{
-		Addr: args[0],
+		Addr: args[1],
 		Net:  "udp",
 	}
 
 	srv.Handler = &dnsHandler{
-		domain:    args[1],
+		domain:    args[2],
 		leaseFile: shared.VarPath("networks", networkName, "dnsmasq.leases"),
 	}
 
diff --git a/lxd/main_nsexec.go b/lxd/main_nsexec.go
index 8fa6db708a..69c2d4e6d2 100644
--- a/lxd/main_nsexec.go
+++ b/lxd/main_nsexec.go
@@ -41,6 +41,7 @@ extern void forkfile();
 extern void forkmknod();
 extern void forkmount();
 extern void forknet();
+extern void forkdns();
 extern void forkproxy();
 extern void forkuevent();
 
@@ -272,6 +273,8 @@ __attribute__((constructor)) void init(void) {
 		forkmount();
 	else if (strcmp(cmdline_cur, "forknet") == 0)
 		forknet();
+	else if (strcmp(cmdline_cur, "forkdns") == 0)
+		forkdns();
 	else if (strcmp(cmdline_cur, "forkproxy") == 0)
 		forkproxy();
 	else if (strcmp(cmdline_cur, "forkuevent") == 0)
diff --git a/lxd/networks.go b/lxd/networks.go
index b28fecfa93..86412ec629 100644
--- a/lxd/networks.go
+++ b/lxd/networks.go
@@ -17,7 +17,6 @@ import (
 	"github.com/gorilla/mux"
 	log "github.com/lxc/lxd/shared/log15"
 	"github.com/pkg/errors"
-	"golang.org/x/sys/unix"
 
 	lxd "github.com/lxc/lxd/client"
 	"github.com/lxc/lxd/lxd/cluster"
@@ -2088,6 +2087,7 @@ func (n *network) spawnForkDNS(listenAddress string) error {
 	cmd.Args = []string{
 		n.state.OS.ExecPath,
 		"forkdns",
+		shared.VarPath("networks", n.name, "forkdns.pid"),
 		fmt.Sprintf("%s:1053", listenAddress),
 		dnsDomain,
 		n.name,
@@ -2098,14 +2098,6 @@ func (n *network) spawnForkDNS(listenAddress string) error {
 		return err
 	}
 
-	// Write the PID file
-	pidPath := shared.VarPath("networks", n.name, "forkdns.pid")
-	err = ioutil.WriteFile(pidPath, []byte(fmt.Sprintf("%d\n", cmd.Process.Pid)), 0600)
-	if err != nil {
-		unix.Kill(cmd.Process.Pid, unix.SIGKILL)
-		return err
-	}
-
 	return nil
 }
 


More information about the lxc-devel mailing list