Skip to content

Commit

Permalink
fix: Should handle stale socket file
Browse files Browse the repository at this point in the history
Added a lock file to hold make sure that it's safe to rebuild socket file
  • Loading branch information
orangedeng committed Oct 10, 2024
1 parent 8d1433b commit 4c1db38
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 5 deletions.
4 changes: 2 additions & 2 deletions internal/server/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import (
)

func Serve(ctx context.Context, server *server.Server) error {
listener, ipOrPath, err := ensureListener()
listener, ipOrPath, err := ensureListener(ctx)
if err != nil {
return err
}
if listener != nil {
defer listener.Close()
return serveSocket(ctx, ipOrPath, listener, server)
}
return server.ListenAndServe(ctx, config.Steve.HTTPSListenPort, config.Steve.HTTPListenPort, &dynamicserver.ListenOpts{
Expand Down Expand Up @@ -45,7 +46,6 @@ func serveSocket(ctx context.Context, socketPath string, listener net.Listener,
go func() {
<-ctx.Done()
_ = socketServer.Shutdown(context.Background())
_ = listener.Close()
}()
<-ctx.Done()
return ctx.Err()
Expand Down
70 changes: 68 additions & 2 deletions internal/server/listener_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,44 @@
package server

import (
"context"
"errors"
"fmt"
"net"
"net/url"
"os"
"path/filepath"
"strings"
"syscall"

"github.com/cnrancher/kube-explorer/internal/config"
"github.com/sirupsen/logrus"
)

func ensureListener() (net.Listener, string, error) {
var _ net.Listener = &closerListener{}

type closerListener struct {
listener net.Listener
lockFile *os.File
}

func (l *closerListener) Accept() (net.Conn, error) {
return l.listener.Accept()
}

func (l *closerListener) Close() error {
return errors.Join(
l.listener.Close(),
l.lockFile.Close(),
os.RemoveAll(l.lockFile.Name()),
)
}

func (l *closerListener) Addr() net.Addr {
return l.listener.Addr()
}

func ensureListener(ctx context.Context) (net.Listener, string, error) {
if config.BindAddress == "" {
return nil, "", nil
}
Expand All @@ -25,9 +55,45 @@ func ensureListener() (net.Listener, string, error) {
case "tcp":
return nil, u.Host, nil
case "unix":
listener, err := net.Listen("unix", u.Path)
listener, err := createCloserListener(ctx, u.Path)
if err != nil {
return nil, "", err
}
return listener, u.Path, err
default:
return nil, "", fmt.Errorf("Unsupported scheme %s, only tcp and unix are supported in UNIX OS", u.Scheme)
}
}

func createCloserListener(ctx context.Context, socketPath string) (net.Listener, error) {
lockFilePath := getLockFileName(socketPath)
lockFile, err := os.OpenFile(lockFilePath, os.O_RDONLY|os.O_CREATE, 0600)
if err != nil {
return nil, err
}

lockErr := syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
if lockErr != nil {
return nil, fmt.Errorf("Socket file %s is in use, exiting", socketPath)
}

if _, err := os.Stat(socketPath); err == nil {
logrus.Infof("Removing stale socket file %s", socketPath)
_ = os.Remove(socketPath)
}

var lc net.ListenConfig
listener, err := lc.Listen(ctx, "unix", socketPath)
if err != nil {
return nil, err
}

return &closerListener{
listener: listener,
lockFile: lockFile,
}, nil
}

func getLockFileName(socketPath string) string {
return strings.TrimSuffix(socketPath, filepath.Ext(socketPath)) + ".lock"
}
3 changes: 2 additions & 1 deletion internal/server/listener_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package server

import (
"context"
"fmt"
"net"
"net/url"
Expand All @@ -12,7 +13,7 @@ import (
"github.com/cnrancher/kube-explorer/internal/config"
)

func ensureListener() (net.Listener, string, error) {
func ensureListener(_ context.Context) (net.Listener, string, error) {
if config.BindAddress == "" {
return nil, "", nil
}
Expand Down

0 comments on commit 4c1db38

Please sign in to comment.