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

Graceful: Allow graceful restart for unix sockets #9113

Merged
merged 3 commits into from
Nov 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 6 additions & 23 deletions cmd/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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) {
Expand Down Expand Up @@ -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))
Expand All @@ -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
Expand All @@ -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)
}
Expand Down
12 changes: 6 additions & 6 deletions cmd/web_graceful.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
15 changes: 14 additions & 1 deletion modules/graceful/net_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"sync"

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)

const (
Expand Down Expand Up @@ -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
}
Expand Down
5 changes: 5 additions & 0 deletions modules/graceful/restart_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package graceful

import (
"fmt"
"net"
"os"
"os/exec"
"strings"
Expand Down Expand Up @@ -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()
}
Expand Down