Skip to content
This repository was archived by the owner on Mar 31, 2025. It is now read-only.

Commit 3f942ff

Browse files
leonardocemnencia
authored andcommitted
feat: always remove stale unix sockets (#2)
Signed-off-by: Leonardo Cecchi <[email protected]>
1 parent ce621bb commit 3f942ff

File tree

3 files changed

+134
-49
lines changed

3 files changed

+134
-49
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
github.com/evanphx/json-patch/v5 v5.8.1
1111
github.com/go-logr/logr v1.3.0
1212
github.com/go-logr/zapr v1.2.4
13+
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1
1314
github.com/spf13/cobra v1.8.0
1415
github.com/spf13/viper v1.14.0
1516
go.uber.org/zap v1.26.0

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
170170
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
171171
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
172172
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
173+
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1 h1:HcUWd006luQPljE73d5sk+/VgYPGUReEVz2y1/qylwY=
174+
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1/go.mod h1:w9Y7gY31krpLmrVU5ZPG9H7l9fZuRu5/3R3S3FMtVQ4=
173175
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
174176
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
175177
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
@@ -272,8 +274,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
272274
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
273275
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
274276
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
275-
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
276-
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
277+
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
278+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
277279
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
278280
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
279281
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

pkg/pluginhelper/server.go

Lines changed: 129 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package pluginhelper
22

33
import (
4+
"context"
5+
"errors"
46
"net"
7+
"os"
8+
"os/signal"
59
"path"
10+
"syscall"
611

712
"github.com/cloudnative-pg/cnpg-i/pkg/identity"
13+
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
814
"github.com/spf13/cobra"
915
"github.com/spf13/viper"
1016
"google.golang.org/grpc"
@@ -31,53 +37,7 @@ func CreateMainCmd(identityImpl identity.IdentityServer, enrichers ...ServerEnri
3137
},
3238
Args: cobra.NoArgs,
3339
RunE: func(cmd *cobra.Command, _ []string) error {
34-
logger := logging.FromContext(cmd.Context())
35-
36-
identityResponse, err := identityImpl.GetPluginMetadata(
37-
cmd.Context(),
38-
&identity.GetPluginMetadataRequest{})
39-
if err != nil {
40-
logger.Error(err, "Error while querying the identity service")
41-
return err
42-
}
43-
44-
pluginPath := viper.GetString("plugin-path")
45-
pluginName := identityResponse.Name
46-
pluginDisplayName := identityResponse.DisplayName
47-
pluginVersion := identityResponse.Version
48-
socketName := path.Join(pluginPath, identityResponse.Name)
49-
50-
grpcServer := grpc.NewServer()
51-
identity.RegisterIdentityServer(
52-
grpcServer,
53-
identityImpl)
54-
for _, enrich := range enrichers {
55-
enrich(grpcServer)
56-
}
57-
58-
listener, err := net.Listen(
59-
unixNetwork,
60-
socketName,
61-
)
62-
if err != nil {
63-
logger.Error(err, "While starting server")
64-
return err
65-
}
66-
67-
logger.Info(
68-
"Starting plugin",
69-
"path", pluginPath,
70-
"name", pluginName,
71-
"displayName", pluginDisplayName,
72-
"version", pluginVersion,
73-
"socketName", socketName,
74-
)
75-
err = grpcServer.Serve(listener)
76-
if err != nil {
77-
logger.Error(err, "While terminatind server")
78-
}
79-
80-
return err
40+
return run(cmd.Context(), identityImpl, enrichers...)
8141
},
8242
}
8343

@@ -97,3 +57,125 @@ func CreateMainCmd(identityImpl identity.IdentityServer, enrichers ...ServerEnri
9757

9858
return cmd
9959
}
60+
61+
// run starts listining for GRPC requests
62+
func run(ctx context.Context, identityImpl identity.IdentityServer, enrichers ...ServerEnricher) error {
63+
logger := logging.FromContext(ctx)
64+
65+
identityResponse, err := identityImpl.GetPluginMetadata(
66+
ctx,
67+
&identity.GetPluginMetadataRequest{})
68+
if err != nil {
69+
logger.Error(err, "Error while querying the identity service")
70+
return err
71+
}
72+
73+
pluginPath := viper.GetString("plugin-path")
74+
pluginName := identityResponse.Name
75+
pluginDisplayName := identityResponse.DisplayName
76+
pluginVersion := identityResponse.Version
77+
socketName := path.Join(pluginPath, identityResponse.Name)
78+
79+
// Remove stale unix socket it still existent
80+
if err := removeStaleSocket(ctx, socketName); err != nil {
81+
logger.Error(err, "While removing old unix socket")
82+
return err
83+
}
84+
85+
// Start accepting connections on the socket
86+
listener, err := net.Listen(
87+
unixNetwork,
88+
socketName,
89+
)
90+
if err != nil {
91+
logger.Error(err, "While starting server")
92+
return err
93+
}
94+
95+
// Handle quit-like signal
96+
handleSignals(ctx, listener)
97+
98+
// Create GRPC server
99+
grpcServer := grpc.NewServer(
100+
grpc.ChainUnaryInterceptor(
101+
recovery.UnaryServerInterceptor(recovery.WithRecoveryHandlerContext(panicRecoveryHandler(listener))),
102+
),
103+
grpc.ChainStreamInterceptor(
104+
recovery.StreamServerInterceptor(recovery.WithRecoveryHandlerContext(panicRecoveryHandler(listener))),
105+
),
106+
)
107+
identity.RegisterIdentityServer(
108+
grpcServer,
109+
identityImpl)
110+
for _, enrich := range enrichers {
111+
enrich(grpcServer)
112+
}
113+
114+
logger.Info(
115+
"Starting plugin",
116+
"path", pluginPath,
117+
"name", pluginName,
118+
"displayName", pluginDisplayName,
119+
"version", pluginVersion,
120+
"socketName", socketName,
121+
)
122+
123+
if err = grpcServer.Serve(listener); !errors.Is(err, net.ErrClosed) {
124+
logger.Error(err, "While terminating server")
125+
}
126+
127+
return nil
128+
}
129+
130+
// removeStaleSocket removes a stale unix domain socket
131+
func removeStaleSocket(ctx context.Context, pluginPath string) error {
132+
logger := logging.FromContext(ctx)
133+
_, err := os.Stat(pluginPath)
134+
135+
switch {
136+
case err == nil:
137+
logger.Info("Removing stale socket", "pluginPath", pluginPath)
138+
return os.Remove(pluginPath)
139+
140+
case errors.Is(err, os.ErrNotExist):
141+
return nil
142+
143+
default:
144+
return err
145+
}
146+
}
147+
148+
// handleSignals makes sure that we close the listening socket
149+
// when we receive a quit-like signal
150+
func handleSignals(ctx context.Context, listener net.Listener) {
151+
logger := logging.FromContext(ctx)
152+
153+
sigc := make(chan os.Signal, 1)
154+
signal.Notify(sigc, syscall.SIGTERM, syscall.SIGABRT, syscall.SIGINT)
155+
go func(c chan os.Signal) {
156+
sig := <-c
157+
logger.Info(
158+
"Caught signal, shutting down.",
159+
"signal", sig.String())
160+
161+
if err := listener.Close(); err != nil {
162+
logger.Error(err, "While stopping server")
163+
}
164+
165+
os.Exit(1)
166+
}(sigc)
167+
}
168+
169+
func panicRecoveryHandler(listener net.Listener) recovery.RecoveryHandlerFuncContext {
170+
return func(ctx context.Context, err any) error {
171+
logger := logging.FromContext(ctx)
172+
logger.Info("Panic occurred", "error", err)
173+
174+
if closeError := listener.Close(); closeError != nil {
175+
logger.Error(closeError, "While stopping server")
176+
}
177+
178+
os.Exit(1)
179+
return nil
180+
}
181+
}

0 commit comments

Comments
 (0)