Skip to content

Commit a610144

Browse files
committed
Merge branch 'main' into CLOUD-727-group-k8s
2 parents 7ebde87 + 2c36dca commit a610144

54 files changed

Lines changed: 2343 additions & 440 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/dependabot.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,34 @@ updates:
4545
interval: weekly
4646
day: "monday"
4747
time: "01:00"
48+
- package-ecosystem: gomod
49+
commit-message:
50+
prefix: "CLOUD-727"
51+
directory: /cmd/mongodb-healthcheck/logger/lumberjack
52+
reviewers:
53+
- hors
54+
- egegunes
55+
- gkech
56+
labels:
57+
- "dependencies"
58+
schedule:
59+
interval: weekly
60+
day: "monday"
61+
time: "01:00"
62+
- package-ecosystem: gomod
63+
commit-message:
64+
prefix: "CLOUD-727"
65+
directory: /.github/linters
66+
reviewers:
67+
- hors
68+
- egegunes
69+
- gkech
70+
labels:
71+
- "dependencies"
72+
schedule:
73+
interval: weekly
74+
day: "monday"
75+
time: "01:00"
4876
groups:
4977
k8s-ecosystem:
5078
patterns:

.github/linters/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module linters
22

3-
go 1.23.4
3+
go 1.26.3

.github/workflows/labeler.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@ permissions:
33
contents: read
44
pull-requests: write
55
on:
6-
pull_request:
6+
pull_request_target:
77
types: [opened, synchronize]
88
jobs:
99
label:
1010
runs-on: ubuntu-latest
1111
steps:
12-
- name: Checkout code
13-
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
14-
1512
- name: "Label PR"
1613
uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6
1714
with:

.github/workflows/reviewdog.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
steps:
1010
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
1111
- name: golangci-lint
12-
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9
12+
uses: golangci/golangci-lint-action@82606bf257cbaff209d206a39f5134f0cfbfd2ee # v9
1313
with:
1414
version: latest
1515
only-new-issues: true

.github/workflows/scan.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ jobs:
1919
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
2020

2121
- name: Set up QEMU
22-
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4
22+
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4
2323

2424
- name: Set up Docker Buildx
25-
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
25+
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
2626

2727
- name: Build an image from Dockerfile (linux/arm64)
2828
run: |

.github/workflows/stale.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
pull-requests: write
1111
runs-on: ubuntu-latest
1212
steps:
13-
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10
13+
- uses: actions/stale@eb5cf3af3ac0a1aa4c9c45633dd1ae542a27a899 # v10
1414
with:
1515
any-of-labels: 'community'
1616
exempt-all-pr-milestones: true

Jenkinsfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ pipeline {
524524
-v $WORKSPACE/src/github.com/percona/percona-server-mongodb-operator:/go/src/github.com/percona/percona-server-mongodb-operator \
525525
-w /go/src/github.com/percona/percona-server-mongodb-operator \
526526
-e GOFLAGS='-buildvcs=false' \
527-
golang:1.25 sh -c '
527+
golang:1.26 sh -c '
528528
go install github.com/google/go-licenses@v1.6.0;
529529
/go/bin/go-licenses csv github.com/percona/percona-server-mongodb-operator/cmd/manager \
530530
| cut -d , -f 3 \
@@ -552,7 +552,7 @@ pipeline {
552552
-v $WORKSPACE/src/github.com/percona/percona-server-mongodb-operator:/go/src/github.com/percona/percona-server-mongodb-operator \
553553
-w /go/src/github.com/percona/percona-server-mongodb-operator \
554554
-e GOFLAGS='-buildvcs=false' \
555-
golang:1.25 sh -c 'go build -v -o percona-server-mongodb-operator github.com/percona/percona-server-mongodb-operator/cmd/manager'
555+
golang:1.26 sh -c 'go build -v -o percona-server-mongodb-operator github.com/percona/percona-server-mongodb-operator/cmd/manager'
556556
"
557557
'''
558558

build/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
ARG BASE_IMAGE=ubi10
22

3-
FROM --platform=${BUILDPLATFORM} golang:1.25 AS go_builder
3+
FROM --platform=${BUILDPLATFORM} golang:1.26 AS go_builder
44
WORKDIR /go/src/github.com/percona/percona-server-mongodb-operator
55

66
COPY go.mod go.sum ./
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
// Copyright 2018 Percona LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package healthcheck
16+
17+
import (
18+
"testing"
19+
20+
"github.com/percona/percona-server-mongodb-operator/pkg/psmdb/mongo"
21+
"github.com/stretchr/testify/require"
22+
)
23+
24+
func statusWithSelf(state mongo.MemberState, uptime int64, initialSync any) mongo.Status {
25+
return mongo.Status{
26+
MyState: state,
27+
InitialSyncStatus: initialSync,
28+
Members: []*mongo.Member{
29+
{Id: 0, Name: "other:27017", State: state, Uptime: uptime},
30+
{Id: 1, Name: "self:27017", State: state, Uptime: uptime, Self: true},
31+
},
32+
}
33+
}
34+
35+
func TestCheckStateForLiveness(t *testing.T) {
36+
tests := []struct {
37+
name string
38+
rs mongo.Status
39+
oplogSize int64
40+
wantErr bool
41+
}{
42+
{
43+
name: "no self member",
44+
rs: mongo.Status{MyState: mongo.MemberStatePrimary},
45+
wantErr: true,
46+
},
47+
{
48+
name: "primary",
49+
rs: statusWithSelf(mongo.MemberStatePrimary, 1000, nil),
50+
},
51+
{
52+
name: "secondary",
53+
rs: statusWithSelf(mongo.MemberStateSecondary, 1000, nil),
54+
},
55+
{
56+
name: "arbiter",
57+
rs: statusWithSelf(mongo.MemberStateArbiter, 1000, nil),
58+
},
59+
{
60+
name: "startup, no initial sync, uptime within budget",
61+
rs: statusWithSelf(mongo.MemberStateStartup, 30, nil),
62+
},
63+
{
64+
name: "startup, no initial sync, uptime exceeds budget",
65+
rs: statusWithSelf(mongo.MemberStateStartup, 31, nil),
66+
wantErr: true,
67+
},
68+
{
69+
name: "startup2, no initial sync, uptime within oplog-scaled budget",
70+
rs: statusWithSelf(mongo.MemberStateStartup2, 150, nil),
71+
oplogSize: 2, // budget = 30 + 2*60 = 150
72+
},
73+
{
74+
name: "startup2, no initial sync, uptime exceeds oplog-scaled budget",
75+
rs: statusWithSelf(mongo.MemberStateStartup2, 151, nil),
76+
oplogSize: 2,
77+
wantErr: true,
78+
},
79+
{
80+
name: "startup with initial sync ignores uptime",
81+
rs: statusWithSelf(mongo.MemberStateStartup, 99999, map[string]any{"syncSourceHost": "src:27017"}),
82+
},
83+
{
84+
name: "startup2 with initial sync ignores uptime",
85+
rs: statusWithSelf(mongo.MemberStateStartup2, 99999, map[string]any{"syncSourceHost": "src:27017"}),
86+
},
87+
{
88+
name: "recovering does not error",
89+
rs: statusWithSelf(mongo.MemberStateRecovering, 99999, nil),
90+
},
91+
{
92+
name: "rollback does not error",
93+
rs: statusWithSelf(mongo.MemberStateRollback, 99999, nil),
94+
},
95+
{
96+
name: "unknown state",
97+
rs: statusWithSelf(mongo.MemberStateUnknown, 1, nil),
98+
wantErr: true,
99+
},
100+
{
101+
name: "down state",
102+
rs: statusWithSelf(mongo.MemberStateDown, 1, nil),
103+
wantErr: true,
104+
},
105+
{
106+
name: "removed state",
107+
rs: statusWithSelf(mongo.MemberStateRemoved, 1, nil),
108+
wantErr: true,
109+
},
110+
{
111+
name: "out-of-range state",
112+
rs: statusWithSelf(mongo.MemberState(99), 1, nil),
113+
wantErr: true,
114+
},
115+
}
116+
117+
for _, tt := range tests {
118+
t.Run(tt.name, func(t *testing.T) {
119+
err := CheckStateForLiveness(t.Context(), tt.rs, tt.oplogSize)
120+
if tt.wantErr {
121+
require.Error(t, err)
122+
} else {
123+
require.NoError(t, err)
124+
}
125+
})
126+
}
127+
}
128+
129+
func TestCheckStateForReadiness(t *testing.T) {
130+
tests := []struct {
131+
name string
132+
rs mongo.Status
133+
wantErr bool
134+
}{
135+
{
136+
name: "no self member",
137+
rs: mongo.Status{MyState: mongo.MemberStatePrimary},
138+
wantErr: true,
139+
},
140+
{
141+
name: "primary is ready",
142+
rs: statusWithSelf(mongo.MemberStatePrimary, 100, nil),
143+
},
144+
{
145+
name: "secondary is ready",
146+
rs: statusWithSelf(mongo.MemberStateSecondary, 100, nil),
147+
},
148+
{
149+
name: "arbiter is ready",
150+
rs: statusWithSelf(mongo.MemberStateArbiter, 100, nil),
151+
},
152+
{
153+
name: "startup is not ready",
154+
rs: statusWithSelf(mongo.MemberStateStartup, 1, nil),
155+
wantErr: true,
156+
},
157+
{
158+
name: "startup2 is not ready",
159+
rs: statusWithSelf(mongo.MemberStateStartup2, 1, nil),
160+
wantErr: true,
161+
},
162+
{
163+
name: "recovering is not ready",
164+
rs: statusWithSelf(mongo.MemberStateRecovering, 1, nil),
165+
wantErr: true,
166+
},
167+
{
168+
name: "rollback is not ready",
169+
rs: statusWithSelf(mongo.MemberStateRollback, 1, nil),
170+
wantErr: true,
171+
},
172+
{
173+
name: "unknown state",
174+
rs: statusWithSelf(mongo.MemberStateUnknown, 1, nil),
175+
wantErr: true,
176+
},
177+
{
178+
name: "down state",
179+
rs: statusWithSelf(mongo.MemberStateDown, 1, nil),
180+
wantErr: true,
181+
},
182+
{
183+
name: "removed state",
184+
rs: statusWithSelf(mongo.MemberStateRemoved, 1, nil),
185+
wantErr: true,
186+
},
187+
{
188+
name: "out-of-range state",
189+
rs: statusWithSelf(mongo.MemberState(99), 1, nil),
190+
wantErr: true,
191+
},
192+
}
193+
194+
for _, tt := range tests {
195+
t.Run(tt.name, func(t *testing.T) {
196+
err := CheckStateForReadiness(tt.rs)
197+
if tt.wantErr {
198+
require.Error(t, err)
199+
} else {
200+
require.NoError(t, err)
201+
}
202+
})
203+
}
204+
}

cmd/mongodb-healthcheck/healthcheck/health.go renamed to cmd/mongodb-healthcheck/healthcheck/liveness.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func HealthCheckMongosLiveness(ctx context.Context, cnf *db.Config) (err error)
5454
return nil
5555
}
5656

57-
func HealthCheckMongodLiveness(ctx context.Context, cnf *db.Config, startupDelaySeconds int64) (_ *mongo.MemberState, err error) {
57+
func HealthCheckMongodLiveness(ctx context.Context, cnf *db.Config) (_ *mongo.MemberState, err error) {
5858
log := logf.FromContext(ctx).WithName("HealthCheckMongodLiveness")
5959
ctx = logf.IntoContext(ctx, log)
6060

@@ -107,7 +107,7 @@ func HealthCheckMongodLiveness(ctx context.Context, cnf *db.Config, startupDelay
107107
}
108108

109109
log.V(1).Info("Checking state", "state", rsStatus.MyState, "storage size", storageSize)
110-
if err := CheckState(rsStatus, startupDelaySeconds, storageSize); err != nil {
110+
if err := CheckStateForLiveness(ctx, rsStatus, storageSize); err != nil {
111111
return &rsStatus.MyState, err
112112
}
113113

@@ -119,27 +119,29 @@ type OplogRs struct {
119119
StorageSize int64 `bson:"storageSize" json:"storageSize"`
120120
}
121121

122-
func CheckState(rs mongo.Status, startupDelaySeconds int64, oplogSize int64) error {
122+
func CheckStateForLiveness(ctx context.Context, rs mongo.Status, oplogSize int64) error {
123123
self := rs.GetSelf()
124124
if self == nil {
125125
return errors.New("self member is not found")
126126
}
127-
uptime := self.Uptime
127+
128+
log := logf.FromContext(ctx)
128129

129130
switch rs.MyState {
130131
case mongo.MemberStatePrimary, mongo.MemberStateSecondary, mongo.MemberStateArbiter:
131132
return nil
132133
case mongo.MemberStateStartup, mongo.MemberStateStartup2:
133-
if (rs.InitialSyncStatus == nil && uptime > 30+oplogSize*60) || // give 60 seconds to each 1Gb of oplog
134-
(rs.InitialSyncStatus != nil && uptime > startupDelaySeconds) {
135-
return errors.Errorf("state is %d and uptime is %d", rs.MyState, uptime)
134+
// give 60 seconds to each 1Gb of oplog + 30 seconds
135+
if rs.InitialSyncStatus == nil && self.Uptime > 30+oplogSize*60 {
136+
return errors.Errorf("state is %s and uptime is %d", mongo.MemberStateStrings[rs.MyState], self.Uptime)
136137
}
137-
case mongo.MemberStateRecovering:
138-
if uptime > startupDelaySeconds {
139-
return errors.Errorf("state is %d and uptime is %d", rs.MyState, uptime)
138+
if rs.InitialSyncStatus != nil {
139+
log.Info("Initial sync is in progress")
140140
}
141-
case mongo.MemberStateUnknown, mongo.MemberStateDown, mongo.MemberStateRollback, mongo.MemberStateRemoved:
142-
return errors.Errorf("invalid state %d", rs.MyState)
141+
case mongo.MemberStateRollback, mongo.MemberStateRecovering:
142+
log.Info("Member state is " + mongo.MemberStateStrings[rs.MyState])
143+
case mongo.MemberStateUnknown, mongo.MemberStateDown, mongo.MemberStateRemoved:
144+
return errors.Errorf("unhealthy state %s", mongo.MemberStateStrings[rs.MyState])
143145
default:
144146
return errors.Errorf("state is unknown %d", rs.MyState)
145147
}

0 commit comments

Comments
 (0)