Skip to content

Commit 5d470ee

Browse files
s-vitaliyCopilot
andauthored
Implement health probe and configuration (#199)
* Implement health probes without configuration * Development fix * Update services/health/probes_service.go Co-authored-by: Copilot <[email protected]> * Fix incorrect listenAndServe behavior * Add coverage exclusions * One more fix * Implement configuration subsystem * Finalize the implementation * Finalize the implementation * Final fixes --------- Co-authored-by: Copilot <[email protected]>
1 parent 8ceb0d4 commit 5d470ee

File tree

13 files changed

+250
-57
lines changed

13 files changed

+250
-57
lines changed

.container/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.25-bookworm AS build-stage
1+
FROM --platform=$BUILDPLATFORM golang:1.25-bookworm AS build-stage
22

33
ARG TARGETOS
44
ARG TARGETARCH
@@ -26,7 +26,7 @@ WORKDIR /app
2626

2727
COPY --from=build-stage /app /app
2828

29-
COPY .container/appconfig.yaml /app/appconfig.yaml
29+
COPY appconfig.yaml /app/appconfig.yaml
3030

3131
USER nonroot:nonroot
3232

.container/appconfig.yaml

Lines changed: 0 additions & 21 deletions
This file was deleted.

.helm/templates/deployment.yaml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ spec:
4646
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
4747
livenessProbe:
4848
httpGet:
49-
port: 8080
49+
port: {{ .Values.settings.probes.port }}
5050
path: /health
5151
initialDelaySeconds: 10
5252
timeoutSeconds: 5
@@ -55,8 +55,8 @@ spec:
5555
failureThreshold: 10
5656
readinessProbe:
5757
httpGet:
58-
port: 8080
59-
path: /health
58+
port: {{ .Values.settings.probes.port }}
59+
path: /health/ready
6060
initialDelaySeconds: 10
6161
timeoutSeconds: 5
6262
periodSeconds: 30
@@ -67,6 +67,14 @@ spec:
6767
value: {{ .Values.environment }}
6868
- name: APPLICATION_VERSION
6969
value: "{{ (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) }}"
70+
- name: ARCANE_OPERATOR__PROBES__ADDR
71+
value: {{ .Values.settings.probes.listenAddrOverride | default (printf "0.0.0.0:%v" .Values.settings.probes.port) }}
72+
- name: ARCANE_OPERATOR__PROBES__WRITE_TIMEOUT
73+
value: {{ .Values.settings.probes.writeTimeout | default "15s"}}
74+
- name: ARCANE_OPERATOR__PROBES__READ_TIMEOUT
75+
value: {{ .Values.settings.probes.writeTimeout | default "15s"}}
76+
- name: ARCANE_OPERATOR__PROBES__SHUTDOWN_TIMEOUT
77+
value: {{ .Values.settings.probes.writeTimeout | default "5s"}}
7078
{{- with .Values.extraEnv }}
7179
{{- toYaml . | nindent 12 }}
7280
{{- end }}

.helm/values.yaml

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -184,32 +184,25 @@ securityContext:
184184
type: RuntimeDefault
185185

186186
settings:
187-
# Settings for the streaming Job Maintenance controller
188-
jobMaintenanceController:
189-
190-
# The namespace where the streaming jobs are created and maintained
191-
# Defaults to the namespace where the operator is deployed
192-
jobNamespace: ""
193-
194-
# The maximum number of streaming job events in the Akka event buffer
195-
# If the number of events exceeds this value, the service throws an exception
196-
# and will be restarted by the Deployment controller
197-
maxEventBufferCapacity: 10000
198-
199-
# Settings for the StreamClass controller
200-
streamClassController:
201-
202-
# The namespace where the streaming jobs are created and maintained
203-
# Defaults to the namespace where the operator is deployed
204-
streamClassesNamespace: ""
205-
206-
# The maximum number of streaming job events in the Akka event buffer
207-
# If the number of events exceeds this value, the service throws an exception
208-
# and will be restarted by the Deployment controller
209-
maxEventBufferCapacity: 10000
210187

211-
# Custom logger configuration
212-
customLoggingProperties: { }
213-
214-
# Custom logger minimum level overrides
215-
customLoggingMinimumLevel: { }
188+
# Configuration for the health probes
189+
probes:
190+
191+
## Address override for the probes to listen on (overrides the port setting or interface binding)
192+
## If not set, defaults to "0.0.0.0:<port>"
193+
listenAddrOverride: ""
194+
195+
## Port for the health probes to listen on
196+
port: 8888
197+
198+
## Timeout for write operations
199+
## If not set, defaults to 15s
200+
writeTimeout: ""
201+
202+
## Timeout for read operations
203+
## If not set, defaults to 15s
204+
readTimeout: ""
205+
206+
## Timeout for server shutdown
207+
## If not set, defaults to 5s
208+
shutdownTimeout: ""

appconfig.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
probes:
2+
addr: ":8888"
3+
write-timeout: 15s
4+
read-timeout: 15s
5+
shutdown-timeout: 5s

config/configuration.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package config
2+
3+
import "github.com/SneaksAndData/arcane-operator/services/health"
4+
5+
// AppConfig holds the application configuration settings.
6+
type AppConfig struct {
7+
8+
// ProbesConfiguration holds the configuration for health probes.
9+
ProbesConfiguration health.ProbesConfig `mapstructure:"probes,omitempty"`
10+
}

config/management.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package config
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/spf13/viper"
7+
"k8s.io/klog/v2"
8+
"os"
9+
"strings"
10+
)
11+
12+
const (
13+
EnvPrefix = "ARCANE_OPERATOR_" // var names will be ARCANE_OPERATOR__MY_ENV_VAR or ARCANE_OPERATOR__SECTION1__SECTION2__MY_ENV_VAR
14+
)
15+
16+
func configExists(configPath string) (bool, error) { // coverage-ignore (this should be covered in integration tests)
17+
if _, err := os.Stat(configPath); os.IsNotExist(err) {
18+
return false, nil
19+
} else if err != nil { // coverage-ignore
20+
return false, err
21+
} else {
22+
return true, nil
23+
}
24+
}
25+
26+
func LoadConfig[T any](ctx context.Context) (*T, error) { // coverage-ignore (this should be covered in integration tests)
27+
logger := klog.FromContext(ctx)
28+
customViper := viper.NewWithOptions(viper.KeyDelimiter("__"))
29+
customViper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
30+
31+
localConfig := fmt.Sprintf("appconfig.%s.yaml", strings.ToLower(os.Getenv("APPLICATION_ENVIRONMENT")))
32+
33+
exists, err := configExists(localConfig)
34+
if err != nil {
35+
return nil, fmt.Errorf("error checking config for existance: %w", err)
36+
}
37+
38+
if exists {
39+
customViper.SetConfigFile(fmt.Sprintf("appconfig.%s.yaml", strings.ToLower(os.Getenv("APPLICATION_ENVIRONMENT"))))
40+
} else {
41+
logger.Info("no environment specific config found, loading default appconfig.yaml")
42+
customViper.SetConfigFile("appconfig.yaml")
43+
}
44+
45+
customViper.SetEnvPrefix(EnvPrefix)
46+
customViper.AllowEmptyEnv(true)
47+
customViper.AutomaticEnv()
48+
49+
err = customViper.ReadInConfig()
50+
if err != nil { // coverage-ignore
51+
return nil, fmt.Errorf("error reading config file: %w", err)
52+
}
53+
54+
var appConfig T
55+
err = customViper.Unmarshal(&appConfig)
56+
57+
if err != nil { // coverage-ignore
58+
return nil, fmt.Errorf("error unmarshalling config: %w", err)
59+
}
60+
61+
return &appConfig, nil
62+
}

go.mod

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
github.com/google/uuid v1.6.0
1111
github.com/samber/slog-datadog/v2 v2.10.2
1212
github.com/samber/slog-multi v1.6.0
13+
github.com/spf13/viper v1.21.0
1314
github.com/stretchr/testify v1.11.1
1415
go.uber.org/mock v0.6.0
1516
golang.org/x/sync v0.18.0
@@ -34,6 +35,7 @@ require (
3435
github.com/go-openapi/jsonpointer v0.21.0 // indirect
3536
github.com/go-openapi/jsonreference v0.20.2 // indirect
3637
github.com/go-openapi/swag v0.23.0 // indirect
38+
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
3739
github.com/goccy/go-json v0.10.2 // indirect
3840
github.com/gogo/protobuf v1.3.2 // indirect
3941
github.com/google/btree v1.1.3 // indirect
@@ -45,14 +47,20 @@ require (
4547
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
4648
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
4749
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
50+
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
4851
github.com/pmezard/go-difflib v1.0.0 // indirect
4952
github.com/prometheus/client_golang v1.22.0 // indirect
5053
github.com/prometheus/client_model v0.6.1 // indirect
5154
github.com/prometheus/common v0.62.0 // indirect
5255
github.com/prometheus/procfs v0.15.1 // indirect
56+
github.com/sagikazarmark/locafero v0.11.0 // indirect
5357
github.com/samber/lo v1.52.0 // indirect
5458
github.com/samber/slog-common v0.19.0 // indirect
59+
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
60+
github.com/spf13/afero v1.15.0 // indirect
61+
github.com/spf13/cast v1.10.0 // indirect
5562
github.com/spf13/pflag v1.0.10 // indirect
63+
github.com/subosito/gotenv v1.6.0 // indirect
5664
github.com/x448/float16 v0.8.4 // indirect
5765
go.yaml.in/yaml/v2 v2.4.3 // indirect
5866
go.yaml.in/yaml/v3 v3.0.4 // indirect

go.sum

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8
2424
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
2525
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
2626
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
27+
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
28+
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
2729
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
2830
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
2931
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
@@ -42,6 +44,8 @@ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+Gr
4244
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
4345
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
4446
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
47+
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
48+
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
4549
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
4650
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
4751
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -91,6 +95,8 @@ github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns
9195
github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
9296
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
9397
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
98+
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
99+
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
94100
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
95101
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
96102
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -105,6 +111,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
105111
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
106112
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
107113
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
114+
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
115+
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
108116
github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw=
109117
github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
110118
github.com/samber/slog-common v0.19.0 h1:fNcZb8B2uOLooeYwFpAlKjkQTUafdjfqKcwcC89G9YI=
@@ -114,8 +122,16 @@ github.com/samber/slog-datadog/v2 v2.10.2/go.mod h1:4OaxK5ESM2j6EhPXyFBEVXjjvWmd
114122
github.com/samber/slog-multi v1.6.0 h1:i1uBY+aaln6ljwdf7Nrt4Sys8Kk6htuYuXDHWJsHtZg=
115123
github.com/samber/slog-multi v1.6.0/go.mod h1:qTqzmKdPpT0h4PFsTN5rYRgLwom1v+fNGuIrl1Xnnts=
116124
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
125+
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
126+
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
127+
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
128+
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
129+
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
130+
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
117131
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
118132
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
133+
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
134+
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
119135
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
120136
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
121137
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -128,6 +144,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
128144
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
129145
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
130146
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
147+
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
148+
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
131149
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
132150
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
133151
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

justfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ mock-stream-plugin:
2727
--namespace default \
2828
--set jobTemplateSettings.podFailurePolicySettings.retryOnExitCodes="{120,121}" \
2929
--set jobTemplateSettings.backoffLimit=1 \
30-
--version v1.0.2
30+
--version v1.0.3

0 commit comments

Comments
 (0)