]> source.dussan.org Git - gitea.git/commitdiff
Graceful: Allow graceful restart for unix sockets (#9113)
authorzeripath <art27@cantab.net>
Sun, 24 Nov 2019 02:11:24 +0000 (02:11 +0000)
committerAntoine GIRARD <sapk@users.noreply.github.com>
Sun, 24 Nov 2019 02:11:24 +0000 (03:11 +0100)
Previously we could not handle graceful restarts for http over unix
sockets. These can now be handled.

cmd/web.go
cmd/web_graceful.go
modules/graceful/net_unix.go
modules/graceful/restart_unix.go

index 22a7f9082db127663e76fe2bf883006492a6ce89..e45e52be3746ee70551f0a59b00903cbdb2e5aba 100644 (file)
@@ -60,7 +60,7 @@ func runHTTPRedirector() {
                http.Redirect(w, r, target, http.StatusTemporaryRedirect)
        })
 
-       var err = runHTTP(source, context2.ClearHandler(handler))
+       var err = runHTTP("tcp", source, context2.ClearHandler(handler))
 
        if err != nil {
                log.Fatal("Failed to start port redirection: %v", err)
@@ -77,12 +77,12 @@ func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler)
        go func() {
                log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
                // all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
-               var err = runHTTP(setting.HTTPAddr+":"+setting.PortToRedirect, certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)))
+               var err = runHTTP("tcp", setting.HTTPAddr+":"+setting.PortToRedirect, certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler)))
                if err != nil {
                        log.Fatal("Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
                }
        }()
-       return runHTTPSWithTLSConfig(listenAddr, certManager.TLSConfig(), context2.ClearHandler(m))
+       return runHTTPSWithTLSConfig("tcp", listenAddr, certManager.TLSConfig(), context2.ClearHandler(m))
 }
 
 func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
@@ -171,7 +171,7 @@ func runWeb(ctx *cli.Context) error {
        switch setting.Protocol {
        case setting.HTTP:
                NoHTTPRedirector()
-               err = runHTTP(listenAddr, context2.ClearHandler(m))
+               err = runHTTP("tcp", listenAddr, context2.ClearHandler(m))
        case setting.HTTPS:
                if setting.EnableLetsEncrypt {
                        err = runLetsEncrypt(listenAddr, setting.Domain, setting.LetsEncryptDirectory, setting.LetsEncryptEmail, context2.ClearHandler(m))
@@ -182,7 +182,7 @@ func runWeb(ctx *cli.Context) error {
                } else {
                        NoHTTPRedirector()
                }
-               err = runHTTPS(listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m))
+               err = runHTTPS("tcp", listenAddr, setting.CertFile, setting.KeyFile, context2.ClearHandler(m))
        case setting.FCGI:
                NoHTTPRedirector()
                // FCGI listeners are provided as stdin - this is orthogonal to the LISTEN_FDS approach
@@ -200,25 +200,8 @@ func runWeb(ctx *cli.Context) error {
                }()
                err = fcgi.Serve(listener, context2.ClearHandler(m))
        case setting.UnixSocket:
-               // This could potentially be inherited using LISTEN_FDS but currently
-               // these cannot be inherited
                NoHTTPRedirector()
-               NoMainListener()
-               if err := os.Remove(listenAddr); err != nil && !os.IsNotExist(err) {
-                       log.Fatal("Failed to remove unix socket directory %s: %v", listenAddr, err)
-               }
-               var listener *net.UnixListener
-               listener, err = net.ListenUnix("unix", &net.UnixAddr{Name: listenAddr, Net: "unix"})
-               if err != nil {
-                       break // Handle error after switch
-               }
-
-               // FIXME: add proper implementation of signal capture on all protocols
-               // execute this on SIGTERM or SIGINT: listener.Close()
-               if err = os.Chmod(listenAddr, os.FileMode(setting.UnixSocketPermission)); err != nil {
-                       log.Fatal("Failed to set permission of unix socket: %v", err)
-               }
-               err = http.Serve(listener, context2.ClearHandler(m))
+               err = runHTTP("unix", listenAddr, context2.ClearHandler(m))
        default:
                log.Fatal("Invalid protocol: %s", setting.Protocol)
        }
index a37f669d0909333ceb2d806bade2a25f9a5a1b3a..3907e843a2b7ae8920ad053cbae0bb857b68d89c 100644 (file)
@@ -11,16 +11,16 @@ import (
        "code.gitea.io/gitea/modules/graceful"
 )
 
-func runHTTP(listenAddr string, m http.Handler) error {
-       return graceful.HTTPListenAndServe("tcp", listenAddr, m)
+func runHTTP(network, listenAddr string, m http.Handler) error {
+       return graceful.HTTPListenAndServe(network, listenAddr, m)
 }
 
-func runHTTPS(listenAddr, certFile, keyFile string, m http.Handler) error {
-       return graceful.HTTPListenAndServeTLS("tcp", listenAddr, certFile, keyFile, m)
+func runHTTPS(network, listenAddr, certFile, keyFile string, m http.Handler) error {
+       return graceful.HTTPListenAndServeTLS(network, listenAddr, certFile, keyFile, m)
 }
 
-func runHTTPSWithTLSConfig(listenAddr string, tlsConfig *tls.Config, m http.Handler) error {
-       return graceful.HTTPListenAndServeTLSConfig("tcp", listenAddr, tlsConfig, m)
+func runHTTPSWithTLSConfig(network, listenAddr string, tlsConfig *tls.Config, m http.Handler) error {
+       return graceful.HTTPListenAndServeTLSConfig(network, listenAddr, tlsConfig, m)
 }
 
 // NoHTTPRedirector tells our cleanup routine that we will not be using a fallback http redirector
index 2b8efe0353d4d3c5ddbbc8d3bcda5ead254017e4..5550c09f427ce8c340d19be7c4a323a8856ce716 100644 (file)
@@ -16,6 +16,7 @@ import (
        "sync"
 
        "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/modules/setting"
 )
 
 const (
@@ -165,15 +166,27 @@ func GetListenerUnix(network string, address *net.UnixAddr) (*net.UnixListener,
                if isSameAddr(l.Addr(), address) {
                        providedListeners = append(providedListeners[:i], providedListeners[i+1:]...)
                        activeListeners = append(activeListeners, l)
-                       return l.(*net.UnixListener), nil
+                       unixListener := l.(*net.UnixListener)
+                       unixListener.SetUnlinkOnClose(true)
+                       return unixListener, nil
                }
        }
 
        // make a fresh listener
+       if err := os.Remove(address.Name); err != nil && !os.IsNotExist(err) {
+               return nil, fmt.Errorf("Failed to remove unix socket %s: %v", address.Name, err)
+       }
+
        l, err := net.ListenUnix(network, address)
        if err != nil {
                return nil, err
        }
+
+       fileMode := os.FileMode(setting.UnixSocketPermission)
+       if err = os.Chmod(address.Name, fileMode); err != nil {
+               return nil, fmt.Errorf("Failed to set permission of unix socket to %s: %v", fileMode.String(), err)
+       }
+
        activeListeners = append(activeListeners, l)
        return l, nil
 }
index 8c68965f5dfae2c4c9209eb717399dd2af530184..3fc4f0511d1df1fb308404cb0171576777a860da 100644 (file)
@@ -9,6 +9,7 @@ package graceful
 
 import (
        "fmt"
+       "net"
        "os"
        "os/exec"
        "strings"
@@ -48,6 +49,10 @@ func RestartProcess() (int, error) {
                if err != nil {
                        return 0, err
                }
+
+               if unixListener, ok := l.(*net.UnixListener); ok {
+                       unixListener.SetUnlinkOnClose(false)
+               }
                // Remember to close these at the end.
                defer files[i].Close()
        }