aboutsummaryrefslogtreecommitdiff
path: root/core/restart.go
diff options
context:
space:
mode:
authorGravatar Miek Gieben <miek@miek.nl> 2016-08-19 17:14:17 -0700
committerGravatar GitHub <noreply@github.com> 2016-08-19 17:14:17 -0700
commit9ac3cab1b7b1b1e78f86ce3c6a80fbee312162e6 (patch)
tree437e9755927c33af16276ad2602a6da115f948cb /core/restart.go
parenta1989c35231b0e5ea271b2f68d82c1a63e697cd0 (diff)
downloadcoredns-9ac3cab1b7b1b1e78f86ce3c6a80fbee312162e6.tar.gz
coredns-9ac3cab1b7b1b1e78f86ce3c6a80fbee312162e6.tar.zst
coredns-9ac3cab1b7b1b1e78f86ce3c6a80fbee312162e6.zip
Make CoreDNS a server type plugin for Caddy (#220)
* Make CoreDNS a server type plugin for Caddy Remove code we don't need and port all middleware over. Fix all tests and rework the documentation. Also make `go generate` build a caddy binary which we then copy into our directory. This means `go build`-builds remain working as-is. And new etc instances in each etcd test for better isolation. Fix more tests and rework test.Server with the newer support Caddy offers. Fix Makefile to support new mode of operation.
Diffstat (limited to 'core/restart.go')
-rw-r--r--core/restart.go177
1 files changed, 0 insertions, 177 deletions
diff --git a/core/restart.go b/core/restart.go
deleted file mode 100644
index aa77e152d..000000000
--- a/core/restart.go
+++ /dev/null
@@ -1,177 +0,0 @@
-// +build !windows
-
-package core
-
-import (
- "bytes"
- "encoding/gob"
- "errors"
- "io/ioutil"
- "log"
- "net"
- "os"
- "os/exec"
- "path"
- "sync/atomic"
-
- "github.com/miekg/coredns/core/https"
-)
-
-func init() {
- gob.Register(CorefileInput{})
-}
-
-// Restart restarts the entire application; gracefully with zero
-// downtime if on a POSIX-compatible system, or forcefully if on
-// Windows but with imperceptibly-short downtime.
-//
-// The restarted application will use newCorefile as its input
-// configuration. If newCorefile is nil, the current (existing)
-// Corefile configuration will be used.
-//
-// Note: The process must exist in the same place on the disk in
-// order for this to work. Thus, multiple graceful restarts don't
-// work if executing with `go run`, since the binary is cleaned up
-// when `go run` sees the initial parent process exit.
-func Restart(newCorefile Input) error {
- log.Println("[INFO] Restarting")
-
- if newCorefile == nil {
- corefileMu.Lock()
- newCorefile = corefile
- corefileMu.Unlock()
- }
-
- // Get certificates for any new hosts in the new Corefile without causing downtime
- err := getCertsForNewCorefile(newCorefile)
- if err != nil {
- return errors.New("TLS preload: " + err.Error())
- }
-
- if len(os.Args) == 0 { // this should never happen, but...
- os.Args = []string{""}
- }
-
- // Tell the child that it's a restart
- os.Setenv("COREDNS_RESTART", "true")
-
- // Prepare our payload to the child process
- crfileGob := corefileGob{
- ListenerFds: make(map[string]uintptr),
- Corefile: newCorefile,
- OnDemandTLSCertsIssued: atomic.LoadInt32(https.OnDemandIssuedCount),
- }
-
- // Prepare a pipe to the fork's stdin so it can get the Corefile
- rpipe, wpipe, err := os.Pipe()
- if err != nil {
- return err
- }
-
- // Prepare a pipe that the child process will use to communicate
- // its success with us by sending > 0 bytes
- sigrpipe, sigwpipe, err := os.Pipe()
- if err != nil {
- return err
- }
-
- // Pass along relevant file descriptors to child process; ordering
- // is very important since we rely on these being in certain positions.
- extraFiles := []*os.File{sigwpipe} // fd 3
-
- // Add file descriptors of all the sockets
- serversMu.Lock()
- j := 0
- for _, s := range servers {
- extraFiles = append(extraFiles, s.ListenerFd())
- extraFiles = append(extraFiles, s.PacketConnFd())
- // So this will be 0 1 2 3 TCP UDP TCP UDP ... etc.
- crfileGob.ListenerFds["tcp"+s.Addr] = uintptr(4 + j) // 4 fds come before any of the listeners
- crfileGob.ListenerFds["udp"+s.Addr] = uintptr(4 + j + 1) // add udp after that
- j += 2
- }
- serversMu.Unlock()
-
- // Set up the command
- cmd := exec.Command(os.Args[0], os.Args[1:]...)
- cmd.Stdin = rpipe // fd 0
- cmd.Stdout = os.Stdout // fd 1
- cmd.Stderr = os.Stderr // fd 2
- cmd.ExtraFiles = extraFiles
-
- // Spawn the child process
- err = cmd.Start()
- if err != nil {
- return err
- }
-
- // Immediately close our dup'ed fds and the write end of our signal pipe
- for _, f := range extraFiles {
- f.Close()
- }
-
- // Feed Corefile to the child
- err = gob.NewEncoder(wpipe).Encode(crfileGob)
- if err != nil {
- return err
- }
- wpipe.Close()
-
- // Run all shutdown functions for the middleware, if child start fails, restart them all...
- executeShutdownCallbacks("SIGUSR1")
-
- // Determine whether child startup succeeded
- answer, readErr := ioutil.ReadAll(sigrpipe)
- if answer == nil || len(answer) == 0 {
- cmdErr := cmd.Wait() // get exit status
- log.Printf("[ERROR] Restart: child failed to initialize (%v) - changes not applied", cmdErr)
- if readErr != nil {
- log.Printf("[ERROR] Restart: additionally, error communicating with child process: %v", readErr)
- }
- // re-call all startup functions.
- // TODO(miek): this needs to be tested, somehow.
- executeStartupCallbacks("SIGUSR1")
- return errIncompleteRestart
- }
-
- // Looks like child is successful; we can exit gracefully.
- return Stop()
-}
-
-func getCertsForNewCorefile(newCorefile Input) error {
- // parse the new corefile only up to (and including) TLS
- // so we can know what we need to get certs for.
- configs, _, _, err := loadConfigsUpToIncludingTLS(path.Base(newCorefile.Path()), bytes.NewReader(newCorefile.Body()))
- if err != nil {
- return errors.New("loading Corefile: " + err.Error())
- }
-
- // first mark the configs that are qualified for managed TLS
- https.MarkQualified(configs)
-
- // since we group by bind address to obtain certs, we must call
- // EnableTLS to make sure the port is set properly first
- // (can ignore error since we aren't actually using the certs)
- https.EnableTLS(configs, false)
-
- // find out if we can let the acme package start its own challenge listener
- // on port 80
- var proxyACME bool
- serversMu.Lock()
- for _, s := range servers {
- _, port, _ := net.SplitHostPort(s.Addr)
- if port == "80" {
- proxyACME = true
- break
- }
- }
- serversMu.Unlock()
-
- // place certs on the disk
- err = https.ObtainCerts(configs, false, proxyACME)
- if err != nil {
- return errors.New("obtaining certs: " + err.Error())
- }
-
- return nil
-}