apiservers: add synchronous shutdown mechanism on SIGTERM+INT
Kubernetes-commit: 11b25366bc7bfe2ad273c8bf9c332fd9d233bffc
This commit is contained in:
parent
10e9a53d92
commit
86ef841256
|
|
@ -34,4 +34,8 @@ type Backend interface {
|
||||||
// Run will initialize the backend. It must not block, but may run go routines in the background. If
|
// Run will initialize the backend. It must not block, but may run go routines in the background. If
|
||||||
// stopCh is closed, it is supposed to stop them. Run will be called before the first call to ProcessEvents.
|
// stopCh is closed, it is supposed to stop them. Run will be called before the first call to ProcessEvents.
|
||||||
Run(stopCh <-chan struct{}) error
|
Run(stopCh <-chan struct{}) error
|
||||||
|
|
||||||
|
// Shutdown will synchronously shut down the backend while making sure that all pending
|
||||||
|
// events are delivered.
|
||||||
|
Shutdown()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,3 +49,9 @@ func (u union) Run(stopCh <-chan struct{}) error {
|
||||||
}
|
}
|
||||||
return errors.AggregateGoroutines(funcs...)
|
return errors.AggregateGoroutines(funcs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u union) Shutdown() {
|
||||||
|
for _, backend := range u.backends {
|
||||||
|
backend.Shutdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,10 @@ func (f *fakeBackend) Run(stopCh <-chan struct{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *fakeBackend) Shutdown() {
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
func TestUnion(t *testing.T) {
|
func TestUnion(t *testing.T) {
|
||||||
backends := []Backend{
|
backends := []Backend{
|
||||||
new(fakeBackend),
|
new(fakeBackend),
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,14 @@ go_library(
|
||||||
"hooks.go",
|
"hooks.go",
|
||||||
"plugins.go",
|
"plugins.go",
|
||||||
"serve.go",
|
"serve.go",
|
||||||
],
|
"signal.go",
|
||||||
|
"signal_posix.go",
|
||||||
|
] + select({
|
||||||
|
"@io_bazel_rules_go//go/platform:windows_amd64": [
|
||||||
|
"signal_windows.go",
|
||||||
|
],
|
||||||
|
"//conditions:default": [],
|
||||||
|
}),
|
||||||
deps = [
|
deps = [
|
||||||
"//vendor/github.com/coreos/go-systemd/daemon:go_default_library",
|
"//vendor/github.com/coreos/go-systemd/daemon:go_default_library",
|
||||||
"//vendor/github.com/emicklei/go-restful:go_default_library",
|
"//vendor/github.com/emicklei/go-restful:go_default_library",
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,11 @@ func (s preparedGenericAPIServer) Run(stopCh <-chan struct{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
<-stopCh
|
<-stopCh
|
||||||
|
|
||||||
|
if s.GenericAPIServer.AuditBackend != nil {
|
||||||
|
s.GenericAPIServer.AuditBackend.Shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
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 server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var onlyOneSignalHandler = make(chan struct{})
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func SetupSignalHandler() (stopCh <-chan struct{}) {
|
||||||
|
close(onlyOneSignalHandler) // panics when called twice
|
||||||
|
|
||||||
|
stop := make(chan struct{})
|
||||||
|
c := make(chan os.Signal, 2)
|
||||||
|
signal.Notify(c, shutdownSignals...)
|
||||||
|
go func() {
|
||||||
|
<-c
|
||||||
|
close(stop)
|
||||||
|
<-c
|
||||||
|
os.Exit(1) // second signal. Exit directly.
|
||||||
|
}()
|
||||||
|
|
||||||
|
return stop
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
var shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
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 server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var shutdownSignals = []os.Signal{os.Interrupt}
|
||||||
|
|
@ -85,3 +85,7 @@ func (b *backend) logEvent(ev *auditinternal.Event) {
|
||||||
func (b *backend) Run(stopCh <-chan struct{}) error {
|
func (b *backend) Run(stopCh <-chan struct{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *backend) Shutdown() {
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,10 @@ func (b *blockingBackend) Run(stopCh <-chan struct{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *blockingBackend) Shutdown() {
|
||||||
|
// nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
func (b *blockingBackend) ProcessEvents(ev ...*auditinternal.Event) {
|
func (b *blockingBackend) ProcessEvents(ev ...*auditinternal.Event) {
|
||||||
if err := b.processEvents(ev...); err != nil {
|
if err := b.processEvents(ev...); err != nil {
|
||||||
audit.HandlePluginError(pluginName, err, ev...)
|
audit.HandlePluginError(pluginName, err, ev...)
|
||||||
|
|
@ -203,6 +207,10 @@ func (b *batchBackend) Run(stopCh <-chan struct{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *batchBackend) Shutdown() {
|
||||||
|
// TODO: send out batched events
|
||||||
|
}
|
||||||
|
|
||||||
// sendBatchEvents attempts to batch some number of events to the backend. It POSTs events
|
// sendBatchEvents attempts to batch some number of events to the backend. It POSTs events
|
||||||
// in a goroutine and logging any error encountered during the POST.
|
// in a goroutine and logging any error encountered during the POST.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue