From 8853403147159c61acef4829e8368a094f3383fa Mon Sep 17 00:00:00 2001 From: Davanum Srinivas Date: Sun, 27 Sep 2026 08:36:05 -0400 Subject: [PATCH] apiserver: move the signal handlers into a stdlib-only leaf package k8s.io/apiserver/pkg/server/signals now owns the shared SIGTERM/SIGINT handler. server keeps SetupSignalHandler, SetupSignalContext and RequestShutdown as wrappers, so existing callers and the single shutdown state are unchanged. pkg/windows/service imports the leaf, which takes the generic API server, and with it the CEL stack, out of kube-proxy.exe. Signed-off-by: Davanum Srinivas --- pkg/windows/service/service.go | 4 +- .../src/k8s.io/apiserver/pkg/server/signal.go | 49 +++---------- .../apiserver/pkg/server/signals/signal.go | 71 +++++++++++++++++++ .../pkg/server/{ => signals}/signal_posix.go | 2 +- .../server/{ => signals}/signal_windows.go | 2 +- 5 files changed, 85 insertions(+), 43 deletions(-) create mode 100644 staging/src/k8s.io/apiserver/pkg/server/signals/signal.go rename staging/src/k8s.io/apiserver/pkg/server/{ => signals}/signal_posix.go (97%) rename staging/src/k8s.io/apiserver/pkg/server/{ => signals}/signal_windows.go (97%) diff --git a/pkg/windows/service/service.go b/pkg/windows/service/service.go index 818a736a0bc..59636f8e347 100644 --- a/pkg/windows/service/service.go +++ b/pkg/windows/service/service.go @@ -24,7 +24,7 @@ import ( "time" "unsafe" - "k8s.io/apiserver/pkg/server" + "k8s.io/apiserver/pkg/server/signals" "k8s.io/klog/v2" "golang.org/x/sys/windows" @@ -171,7 +171,7 @@ Loop: // If we do not do this, our main threads won't be notified of the upcoming shutdown. // Since Windows services do not use any console, we cannot simply generate a CTRL_BREAK_EVENT // but need a dedicated notification mechanism. - graceful := server.RequestShutdown() + graceful := signals.RequestShutdown() // Free up the control handler and let us terminate as gracefully as possible. // If that takes too long, the service controller will kill the remaining threads. diff --git a/staging/src/k8s.io/apiserver/pkg/server/signal.go b/staging/src/k8s.io/apiserver/pkg/server/signal.go index e5334ae4c15..ef9f5e0567c 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/signal.go +++ b/staging/src/k8s.io/apiserver/pkg/server/signal.go @@ -18,52 +18,23 @@ package server import ( "context" - "os" - "os/signal" + + "k8s.io/apiserver/pkg/server/signals" ) -var onlyOneSignalHandler = make(chan struct{}) -var shutdownHandler chan os.Signal - -// SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned -// which is closed on one of these signals. If a second signal is caught, the program -// is terminated with exit code 1. -// Only one of SetupSignalContext and SetupSignalHandler should be called, and only can -// be called once. +// SetupSignalHandler is signals.SetupSignalHandler. The wrappers in this file +// keep the published API and the single shared shutdown state for existing +// callers. func SetupSignalHandler() <-chan struct{} { - return SetupSignalContext().Done() + return signals.SetupSignalHandler() } -// SetupSignalContext is same as SetupSignalHandler, but a context.Context is returned. -// Only one of SetupSignalContext and SetupSignalHandler should be called, and only can -// be called once. +// SetupSignalContext is signals.SetupSignalContext. func SetupSignalContext() context.Context { - close(onlyOneSignalHandler) // panics when called twice - - shutdownHandler = make(chan os.Signal, 2) - - ctx, cancel := context.WithCancel(context.Background()) - signal.Notify(shutdownHandler, shutdownSignals...) - go func() { - <-shutdownHandler - cancel() - <-shutdownHandler - os.Exit(1) // second signal. Exit directly. - }() - - return ctx + return signals.SetupSignalContext() } -// RequestShutdown emulates a received event that is considered as shutdown signal (SIGTERM/SIGINT) -// This returns whether a handler was notified +// RequestShutdown is signals.RequestShutdown. func RequestShutdown() bool { - if shutdownHandler != nil { - select { - case shutdownHandler <- shutdownSignals[0]: - return true - default: - } - } - - return false + return signals.RequestShutdown() } diff --git a/staging/src/k8s.io/apiserver/pkg/server/signals/signal.go b/staging/src/k8s.io/apiserver/pkg/server/signals/signal.go new file mode 100644 index 00000000000..e81567f59d5 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/server/signals/signal.go @@ -0,0 +1,71 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package signals installs the shared SIGTERM and SIGINT shutdown handler. +// It depends only on the standard library. +package signals + +import ( + "context" + "os" + "os/signal" +) + +var onlyOneSignalHandler = make(chan struct{}) +var shutdownHandler chan os.Signal + +// SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned +// which is closed on one of these signals. If a second signal is caught, the program +// is terminated with exit code 1. +// Only one of SetupSignalContext and SetupSignalHandler should be called, and only can +// be called once. +func SetupSignalHandler() <-chan struct{} { + return SetupSignalContext().Done() +} + +// SetupSignalContext is same as SetupSignalHandler, but a context.Context is returned. +// Only one of SetupSignalContext and SetupSignalHandler should be called, and only can +// be called once. +func SetupSignalContext() context.Context { + close(onlyOneSignalHandler) // panics when called twice + + shutdownHandler = make(chan os.Signal, 2) + + ctx, cancel := context.WithCancel(context.Background()) + signal.Notify(shutdownHandler, shutdownSignals...) + go func() { + <-shutdownHandler + cancel() + <-shutdownHandler + os.Exit(1) // second signal. Exit directly. + }() + + return ctx +} + +// RequestShutdown emulates a received event that is considered as shutdown signal (SIGTERM/SIGINT) +// This returns whether a handler was notified +func RequestShutdown() bool { + if shutdownHandler != nil { + select { + case shutdownHandler <- shutdownSignals[0]: + return true + default: + } + } + + return false +} diff --git a/staging/src/k8s.io/apiserver/pkg/server/signal_posix.go b/staging/src/k8s.io/apiserver/pkg/server/signals/signal_posix.go similarity index 97% rename from staging/src/k8s.io/apiserver/pkg/server/signal_posix.go rename to staging/src/k8s.io/apiserver/pkg/server/signals/signal_posix.go index fc0ab2d6716..2b24faa4280 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/signal_posix.go +++ b/staging/src/k8s.io/apiserver/pkg/server/signals/signal_posix.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package server +package signals import ( "os" diff --git a/staging/src/k8s.io/apiserver/pkg/server/signal_windows.go b/staging/src/k8s.io/apiserver/pkg/server/signals/signal_windows.go similarity index 97% rename from staging/src/k8s.io/apiserver/pkg/server/signal_windows.go rename to staging/src/k8s.io/apiserver/pkg/server/signals/signal_windows.go index e7645a20888..4907d573fe0 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/signal_windows.go +++ b/staging/src/k8s.io/apiserver/pkg/server/signals/signal_windows.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package server +package signals import ( "os"