Skip to content

Commit a7b947d

Browse files
gkechpooknullhorsdependabot[bot]
authored
K8SPS-418 ensure grace period support (#926)
* K8SPS-418 ensure grace period support * improve volume readability * add more unit tests * more unit tests * process the sigterm signal and fix tests * fix monitoring test * handle SIGTERM in peer-list * remove trap * change gracePeriod for proxy * fix monitoring test * CLOUD-727: Bump golangci/golangci-lint-action from 7 to 8 (#923) Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 7 to 8. - [Release notes](https://github.com/golangci/golangci-lint-action/releases) - [Commits](golangci/golangci-lint-action@v7...v8) --- updated-dependencies: - dependency-name: golangci/golangci-lint-action dependency-version: '8' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Viacheslav Sarzhan <slava.sarzhan@percona.com> * update log message * fix lint * revert gracePeriod changes * Revert "revert gracePeriod changes" This reverts commit 06e09a7. * fix sidecars test --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Andrii Dema <a.dema@jazzserve.com> Co-authored-by: Viacheslav Sarzhan <slava.sarzhan@percona.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1 parent 2f7475b commit a7b947d

File tree

15 files changed

+518
-322
lines changed

15 files changed

+518
-322
lines changed

api/v1alpha1/perconaservermysql_types.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ import (
4242
"github.com/percona/percona-server-mysql-operator/pkg/version"
4343
)
4444

45+
const (
46+
defaultGracePeriodSec int64 = 600
47+
)
48+
4549
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
4650
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
4751

@@ -189,6 +193,16 @@ type PodSpec struct {
189193
ContainerSpec `json:",inline"`
190194
}
191195

196+
// GetTerminationGracePeriodSeconds returns the configured termination grace period for the Pod.
197+
// If not explicitly set, it returns the default grace period.
198+
func (s PodSpec) GetTerminationGracePeriodSeconds() *int64 {
199+
gp := defaultGracePeriodSec
200+
if s.TerminationGracePeriodSeconds != nil {
201+
return s.TerminationGracePeriodSeconds
202+
}
203+
return &gp
204+
}
205+
192206
// Retrieves the initialization image for the pod.
193207
func (s *PodSpec) GetInitImage() string {
194208
return s.InitImage

api/v1alpha1/perconaservermysql_types_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package v1alpha1
22

33
import (
4+
"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
45
"github.com/stretchr/testify/assert"
56
corev1 "k8s.io/api/core/v1"
67
"k8s.io/apimachinery/pkg/api/resource"
@@ -101,3 +102,29 @@ func TestValidateVolume(t *testing.T) {
101102
})
102103
}
103104
}
105+
106+
func TestGetTerminationGracePeriodSeconds(t *testing.T) {
107+
tests := map[string]struct {
108+
input *int64
109+
expected int64
110+
}{
111+
"custom grace period": {
112+
input: to.Ptr(int64(20)),
113+
expected: 20,
114+
},
115+
"nil grace period (default used)": {
116+
input: nil,
117+
expected: 600,
118+
},
119+
}
120+
121+
for name, tc := range tests {
122+
t.Run(name, func(t *testing.T) {
123+
spec := PodSpec{
124+
TerminationGracePeriodSeconds: tc.input,
125+
}
126+
result := spec.GetTerminationGracePeriodSeconds()
127+
assert.Equal(t, tc.expected, *result)
128+
})
129+
}
130+
}

cmd/peer-list/main.go

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ limitations under the License.
1818
package main
1919

2020
import (
21+
"context"
2122
"flag"
2223
"fmt"
2324
"log"
@@ -46,9 +47,9 @@ var (
4647
domain = flag.String("domain", "", "The Cluster Domain which is used by the Cluster, if not set it tries to determine it from /etc/resolv.conf file.")
4748
)
4849

49-
func lookup(svcName string) (sets.String, error) {
50-
endpoints := sets.NewString()
51-
_, srvRecords, err := net.LookupSRV("", "", svcName)
50+
func lookup(ctx context.Context, svcName string) (sets.Set[string], error) {
51+
endpoints := sets.New[string]()
52+
_, srvRecords, err := net.DefaultResolver.LookupSRV(ctx, "", "", svcName)
5253
if err != nil {
5354
return endpoints, err
5455
}
@@ -60,23 +61,23 @@ func lookup(svcName string) (sets.String, error) {
6061
return endpoints, nil
6162
}
6263

63-
func shellOut(sendStdin, script string) {
64+
func shellOut(ctx context.Context, sendStdin, script string) {
6465
log.Printf("execing: %v with stdin: %v", script, sendStdin)
6566
// TODO: Switch to sending stdin from go
66-
out, err := exec.Command("bash", "-c", fmt.Sprintf("echo -e '%v' | %v", sendStdin, script)).CombinedOutput()
67+
out, err := exec.CommandContext(ctx, "bash", "-c", fmt.Sprintf("echo -e '%v' | %v", sendStdin, script)).CombinedOutput()
6768
if err != nil {
6869
log.Fatalf("Failed to execute %v: %v, err: %v", script, string(out), err)
6970
}
7071
log.Print(string(out))
7172
}
7273

7374
func main() {
74-
signalChan := make(chan os.Signal, 1)
75-
signal.Notify(signalChan, syscall.SIGUSR1)
76-
go func() {
77-
<-signalChan
78-
os.Exit(0)
79-
}()
75+
if pid := os.Getpid(); pid != 1 {
76+
panic(fmt.Sprintf("pid is %d but should be 1", pid))
77+
}
78+
79+
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
80+
defer cancel()
8081

8182
flag.Parse()
8283

@@ -136,28 +137,39 @@ func main() {
136137
log.Printf("No on-start supplied, on-change %v will be applied on start.", script)
137138
}
138139

139-
for peers := sets.NewString(); script != ""; time.Sleep(pollPeriod) {
140-
newPeers, err := lookup(*svc)
141-
if err != nil {
142-
log.Printf("%v", err)
143-
144-
if lerr, ok := err.(*net.DNSError); ok && lerr.IsNotFound {
145-
// Service not resolved - no endpoints, so reset peers list
146-
peers = sets.NewString()
147-
continue
140+
ticker := time.NewTicker(pollPeriod)
141+
defer ticker.Stop()
142+
143+
peers := sets.New[string]()
144+
145+
for script != "" {
146+
select {
147+
case <-ctx.Done():
148+
log.Println("Termination signal received")
149+
script = ""
150+
case <-ticker.C:
151+
newPeers, err := lookup(ctx, *svc)
152+
if err != nil {
153+
log.Printf("%v", err)
154+
155+
if lerr, ok := err.(*net.DNSError); ok && lerr.IsNotFound {
156+
// Service not resolved - no endpoints, so reset peers list
157+
peers = sets.New[string]()
158+
continue
159+
}
148160
}
149-
}
150161

151-
peerList := newPeers.List()
152-
sort.Strings(peerList)
162+
if strings.Join(sets.List(peers), ":") != strings.Join(sets.List(newPeers), ":") {
163+
log.Printf("Peer list updated\nwas %v\nnow %v", sets.List(peers), sets.List(newPeers))
153164

154-
if strings.Join(peers.List(), ":") != strings.Join(newPeers.List(), ":") {
155-
log.Printf("Peer list updated\nwas %v\nnow %v", peers.List(), newPeers.List())
156-
shellOut(strings.Join(peerList, "\n"), script)
157-
peers = newPeers
165+
peerList := sets.List(newPeers)
166+
sort.Strings(peerList)
167+
shellOut(ctx, strings.Join(peerList, "\n"), script)
168+
peers = newPeers
169+
}
170+
script = *onChange
158171
}
159-
script = *onChange
160172
}
161-
// TODO: Exit if there's no on-change?
173+
162174
log.Printf("Peer finder exiting")
163175
}

deploy/cr.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ spec:
111111
resources:
112112
requests:
113113
storage: 2G
114-
114+
gracePeriod: 600
115115
# configuration: |
116116
# max_connections=250
117117
# innodb_buffer_pool_size={{containerMemoryLimit * 3/4}}
@@ -185,6 +185,8 @@ spec:
185185
# failureThreshold: 3
186186
# successThreshold: 1
187187

188+
gracePeriod: 30
189+
188190
# configuration: |
189191
#
190192
# the actual default configuration file can be found here https://github.com/percona/percona-server-mysql-operator/blob/main/build/haproxy-global.cfg
@@ -293,6 +295,8 @@ spec:
293295
# topologyKey: kubernetes.io/hostname
294296
# whenUnsatisfiable: DoNotSchedule
295297

298+
gracePeriod: 30
299+
296300
# configuration: |
297301
# [default]
298302
# logging_folder=/tmp/router/log
@@ -353,6 +357,8 @@ spec:
353357
# loadBalancerSourceRanges:
354358
# - 10.0.0.0/8
355359

360+
gracePeriod: 30
361+
356362
resources:
357363
requests:
358364
memory: 128M

e2e-tests/tests/limits/01-assert.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ spec:
186186
securityContext:
187187
supplementalGroups:
188188
- 1001
189-
terminationGracePeriodSeconds: 30
189+
terminationGracePeriodSeconds: 600
190190
volumes:
191191
- emptyDir: {}
192192
name: bin

e2e-tests/tests/limits/03-assert.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ spec:
186186
securityContext:
187187
supplementalGroups:
188188
- 1001
189-
terminationGracePeriodSeconds: 30
189+
terminationGracePeriodSeconds: 600
190190
volumes:
191191
- emptyDir: {}
192192
name: bin

e2e-tests/tests/limits/05-assert.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ spec:
184184
securityContext:
185185
supplementalGroups:
186186
- 1001
187-
terminationGracePeriodSeconds: 30
187+
terminationGracePeriodSeconds: 600
188188
volumes:
189189
- emptyDir: {}
190190
name: bin

e2e-tests/tests/sidecars/01-create-cluster.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ commands:
1010
1111
get_cr \
1212
| yq eval '.spec.mysql.clusterType="async"' - \
13+
| yq eval '.spec.mysql.gracePeriod=30' - \
1314
| yq eval '.spec.mysql.sidecars = [{"name": "sidecar1", "image": "busybox", "command": ["sleep", "30d"], "volumeMounts": [{"name": "empty-vol", "mountPath": "/var/app/empty"}]}]' - \
1415
| yq eval '.spec.mysql.sidecars += [{"name": "sidecar2", "image": "busybox", "command": ["sleep", "30d"], "volumeMounts": [{"name": "pvc-vol", "mountPath": "/var/app/pvc"}]}]' - \
1516
| yq eval '.spec.mysql.sidecarVolumes = [{"name": "empty-vol", "emptyDir": {"medium": "Memory"}}]' - \

0 commit comments

Comments
 (0)