Decouple shared functions between controllers (#8829)

* Decouple shared functions between controllers

* Apply suggestions from code review

Co-authored-by: Jintao Zhang <tao12345666333@163.com>

* Fix package names and fmt

Co-authored-by: Jintao Zhang <tao12345666333@163.com>
This commit is contained in:
Ricardo Katz 2022-07-20 15:53:44 -03:00 committed by GitHub
parent 8f9df544ea
commit 4c6a7ee158
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 413 additions and 134 deletions

View file

@ -0,0 +1,24 @@
/*
Copyright 2022 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 process
// ProcessController defines a common interface for a process to be controlled,
// like the configurer, the webhook or the proper ingress controller
type ProcessController interface {
Start()
Stop() error
}

View file

@ -0,0 +1,49 @@
/*
Copyright 2022 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 process
import (
"os"
"os/signal"
"syscall"
"time"
klog "k8s.io/klog/v2"
)
type exiter func(code int)
// HandleSigterm receives a ProcessController interface and deals with
// the graceful shutdown
func HandleSigterm(ngx ProcessController, delay int, exit exiter) {
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGTERM)
<-signalChan
klog.InfoS("Received SIGTERM, shutting down")
exitCode := 0
if err := ngx.Stop(); err != nil {
klog.Warningf("Error during shutdown: %v", err)
exitCode = 1
}
klog.Infof("Handled quit, delaying controller exit for %d seconds", delay)
time.Sleep(time.Duration(delay) * time.Second)
klog.InfoS("Exiting", "code", exitCode)
exit(exitCode)
}

View file

@ -0,0 +1,79 @@
/*
Copyright 2022 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 process
import (
"fmt"
"syscall"
"testing"
"time"
)
type FakeProcess struct {
shouldError bool
exitCode int
}
func (f *FakeProcess) Start() {
}
func (f *FakeProcess) Stop() error {
if f.shouldError {
return fmt.Errorf("error")
}
return nil
}
func (f *FakeProcess) exiterFunc(code int) {
f.exitCode = code
}
func sendDelayedSignal(delay time.Duration) {
time.Sleep(delay * time.Second)
syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
}
func TestHandleSigterm(t *testing.T) {
tests := []struct {
name string
shouldError bool
delay int
}{
{
name: "should exit without error",
shouldError: false,
},
{
name: "should exit with error",
shouldError: true,
delay: 2,
},
}
for _, tt := range tests {
process := &FakeProcess{shouldError: tt.shouldError}
t.Run(tt.name, func(t *testing.T) {
go sendDelayedSignal(2) // Send a signal after 2 seconds
HandleSigterm(process, tt.delay, process.exiterFunc)
})
if tt.shouldError && process.exitCode != 1 {
t.Errorf("wrong return, should be 1 and returned %d", process.exitCode)
}
if !tt.shouldError && process.exitCode != 0 {
t.Errorf("wrong return, should be 0 and returned %d", process.exitCode)
}
}
}