Skip to content

Commit 5b18c89

Browse files
committed
Merge remote-tracking branch 'origin/main' into k0s-1-29
2 parents d4b07e4 + 06b0f4b commit 5b18c89

File tree

12 files changed

+322
-32
lines changed

12 files changed

+322
-32
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ K0S_GO_VERSION = v1.29.13+k0s.0
1515
PREVIOUS_K0S_VERSION ?= v1.28.14+k0s.0-ec.0
1616
PREVIOUS_K0S_GO_VERSION ?= v1.28.14+k0s.0
1717
K0S_BINARY_SOURCE_OVERRIDE =
18-
TROUBLESHOOT_VERSION = v0.116.4
18+
TROUBLESHOOT_VERSION = v0.117.0
1919

2020
KOTS_VERSION = v$(shell awk '/^version/{print $$2}' pkg/addons/adminconsole/static/metadata.yaml | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/')
2121
# When updating KOTS_BINARY_URL_OVERRIDE, also update the KOTS_VERSION above or

cmd/installer/cli/install.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,12 @@ func preRunInstall(cmd *cobra.Command, flags *InstallCmdFlags) error {
232232
return fmt.Errorf("unable to write runtime config to disk: %w", err)
233233
}
234234

235+
if err := os.Chmod(runtimeconfig.EmbeddedClusterHomeDirectory(), 0755); err != nil {
236+
// don't fail as there are cases where we can't change the permissions (bind mounts, selinux, etc...),
237+
// and we handle and surface those errors to the user later (host preflights, checking exec errors, etc...)
238+
logrus.Debugf("unable to chmod embedded-cluster home dir: %s", err)
239+
}
240+
235241
return nil
236242
}
237243

@@ -626,9 +632,16 @@ func installAndStartCluster(ctx context.Context, networkInterface string, airgap
626632
if err := k0s.Install(networkInterface); err != nil {
627633
return nil, fmt.Errorf("install cluster: %w", err)
628634
}
635+
629636
loading.Infof("Waiting for %s node to be ready", runtimeconfig.BinaryName())
637+
630638
logrus.Debugf("waiting for k0s to be ready")
631639
if err := waitForK0s(); err != nil {
640+
return nil, fmt.Errorf("wait for k0s: %w", err)
641+
}
642+
643+
logrus.Debugf("waiting for node to be ready")
644+
if err := waitForNode(ctx); err != nil {
632645
return nil, fmt.Errorf("wait for node: %w", err)
633646
}
634647

@@ -947,6 +960,21 @@ func waitForK0s() error {
947960
}
948961
}
949962

963+
func waitForNode(ctx context.Context) error {
964+
kcli, err := kubeutils.KubeClient()
965+
if err != nil {
966+
return fmt.Errorf("create kube client: %w", err)
967+
}
968+
hostname, err := os.Hostname()
969+
if err != nil {
970+
return fmt.Errorf("get hostname: %w", err)
971+
}
972+
if err := kubeutils.WaitForControllerNode(ctx, kcli, hostname); err != nil {
973+
return fmt.Errorf("wait for node: %w", err)
974+
}
975+
return nil
976+
}
977+
950978
func recordInstallation(ctx context.Context, kcli client.Client, flags InstallCmdFlags, k0sCfg *k0sv1beta1.ClusterConfig, disasterRecoveryEnabled bool) (*ecv1beta1.Installation, error) {
951979
// ensure that the embedded-cluster namespace exists
952980
if err := createECNamespace(ctx, kcli); err != nil {

cmd/installer/cli/join.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ func runJoin(ctx context.Context, name string, flags JoinCmdFlags, jcmd *kotsadm
206206
return fmt.Errorf("unable to get hostname: %w", err)
207207
}
208208

209-
if err := waitForNode(ctx, kcli, hostname); err != nil {
209+
if err := waitForNodeToJoin(ctx, kcli, hostname); err != nil {
210210
return fmt.Errorf("unable to wait for node: %w", err)
211211
}
212212

@@ -247,6 +247,12 @@ func runJoinVerifyAndPrompt(name string, flags JoinCmdFlags, jcmd *kotsadm.JoinC
247247
return fmt.Errorf("unable to write runtime config: %w", err)
248248
}
249249

250+
if err := os.Chmod(runtimeconfig.EmbeddedClusterHomeDirectory(), 0755); err != nil {
251+
// don't fail as there are cases where we can't change the permissions (bind mounts, selinux, etc...),
252+
// and we handle and surface those errors to the user later (host preflights, checking exec errors, etc...)
253+
logrus.Debugf("unable to chmod embedded-cluster home dir: %s", err)
254+
}
255+
250256
// check to make sure the version returned by the join token is the same as the one we are running
251257
if strings.TrimPrefix(jcmd.EmbeddedClusterVersion, "v") != strings.TrimPrefix(versions.Version, "v") {
252258
return fmt.Errorf("embedded cluster version mismatch - this binary is version %q, but the cluster is running version %q", versions.Version, jcmd.EmbeddedClusterVersion)
@@ -465,7 +471,7 @@ func runK0sInstallCommand(networkInterface string, fullcmd string) error {
465471
return nil
466472
}
467473

468-
func waitForNode(ctx context.Context, kcli client.Client, hostname string) error {
474+
func waitForNodeToJoin(ctx context.Context, kcli client.Client, hostname string) error {
469475
loading := spinner.Start()
470476
defer loading.Close()
471477
loading.Infof("Waiting for node to join the cluster")

e2e/preflights_test.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,17 @@ func TestPreflights(t *testing.T) {
2020
})
2121
defer tc.Cleanup()
2222

23-
_, stderr, err := tc.RunCommandOnNode(0, []string{"apt-get update && apt-get install -y apt-utils netcat-traditional"})
23+
// set up incorrect permissions on data dir and parent dir
24+
_, stderr, err := tc.RunCommandOnNode(0, []string{
25+
"mkdir -p /var/lib/embedded-cluster && " +
26+
"chmod 744 /var/lib/embedded-cluster && " + // remove execute from data dir
27+
"chmod 744 /var/lib", // remove execute from parent dir
28+
})
29+
if err != nil {
30+
t.Fatalf("failed to adjust dir permissions: err=%v, stderr=%s", err, stderr)
31+
}
32+
33+
_, stderr, err = tc.RunCommandOnNode(0, []string{"apt-get update && apt-get install -y apt-utils netcat-traditional"})
2434
if err != nil {
2535
t.Fatalf("failed to install deps: err=%v, stderr=%s", err, stderr)
2636
}
@@ -95,6 +105,7 @@ func TestPreflights(t *testing.T) {
95105
"Kubelet Port Availability": true,
96106
"Calico Communication Port Availability": true,
97107
"Local Artifact Mirror Port Availability": true,
108+
"Data Directory Permissions": true,
98109
// as long as fio ran successfully, we're good
99110
"Filesystem Write Latency": true,
100111
}
@@ -142,6 +153,33 @@ func TestPreflights(t *testing.T) {
142153
}
143154
},
144155
},
156+
{
157+
name: "Should contain data directory permissions failures",
158+
assert: func(t *testing.T, results *types.Output) {
159+
for _, res := range results.Fail {
160+
if res.Title == "Data Directory Permissions" {
161+
// should not contain data dir as we automatically fix it
162+
if strings.Contains(res.Message, "/var/lib/embedded-cluster") {
163+
t.Errorf("failure message should not contain /var/lib/embedded-cluster directory: %s", res.Message)
164+
}
165+
// should contain parent dir as we don't automatically fix it
166+
if !strings.Contains(res.Message, "/var/lib.") {
167+
t.Errorf("failure message should contain /var/lib directory: %s", res.Message)
168+
}
169+
t.Logf("directory permissions check failed as expected: %s", res.Message)
170+
return
171+
}
172+
}
173+
// If we get here, check if it incorrectly passed
174+
for _, res := range results.Pass {
175+
if res.Title == "Data Directory Permissions" {
176+
t.Errorf("directory permissions check passed unexpectedly: %s", res.Message)
177+
return
178+
}
179+
}
180+
t.Errorf("directory permissions check not found in results")
181+
},
182+
},
145183
}
146184
for _, tt := range tests {
147185
t.Run(tt.name, func(t *testing.T) {

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ require (
3232
github.com/replicatedhq/embedded-cluster/kinds v0.0.0
3333
github.com/replicatedhq/embedded-cluster/utils v0.0.0
3434
github.com/replicatedhq/kotskinds v0.0.0-20240814191029-3f677ee409a0
35-
github.com/replicatedhq/troubleshoot v0.116.4
35+
github.com/replicatedhq/troubleshoot v0.117.0
3636
github.com/sirupsen/logrus v1.9.3
3737
github.com/spf13/cobra v1.9.1
3838
github.com/spf13/viper v1.19.0
@@ -134,6 +134,7 @@ require (
134134
github.com/docker/go-metrics v0.0.1 // indirect
135135
github.com/docker/go-units v0.5.0 // indirect
136136
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
137+
github.com/ebitengine/purego v0.8.2 // indirect
137138
github.com/envoyproxy/go-control-plane v0.13.1 // indirect
138139
github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
139140
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
@@ -231,8 +232,7 @@ require (
231232
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
232233
github.com/segmentio/ksuid v1.0.4 // indirect
233234
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
234-
github.com/shirou/gopsutil/v3 v3.24.5 // indirect
235-
github.com/shoenig/go-m1cpu v0.1.6 // indirect
235+
github.com/shirou/gopsutil/v4 v4.25.1 // indirect
236236
github.com/shopspring/decimal v1.4.0 // indirect
237237
github.com/sourcegraph/conc v0.3.0 // indirect
238238
github.com/spf13/afero v1.11.0 // indirect

go.sum

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,8 @@ github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L
867867
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
868868
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
869869
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
870+
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
871+
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
870872
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
871873
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
872874
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -1439,8 +1441,8 @@ github.com/redis/go-redis/v9 v9.5.2/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0
14391441
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
14401442
github.com/replicatedhq/kotskinds v0.0.0-20240814191029-3f677ee409a0 h1:Gi+Fs6583v7GmgQKJyaZuBzcih0z5YXBREDQ8AWY2JM=
14411443
github.com/replicatedhq/kotskinds v0.0.0-20240814191029-3f677ee409a0/go.mod h1:QjhIUu3+OmHZ09u09j3FCoTt8F3BYtQglS+OLmftu9I=
1442-
github.com/replicatedhq/troubleshoot v0.116.4 h1:SDa+bWiXArt4Ypkw3+qjMxl+QUWKZsR0t19A13Mx3G0=
1443-
github.com/replicatedhq/troubleshoot v0.116.4/go.mod h1:OQwNwp78Xkfa/VwzNnDyiTFAAsZK1u3wApYncskHVl0=
1444+
github.com/replicatedhq/troubleshoot v0.117.0 h1:FCw8VodGF/tetL7ZvdOhnjFDOvSDqMq/kce9/dsfHfc=
1445+
github.com/replicatedhq/troubleshoot v0.117.0/go.mod h1:Xt6P84cvEyfyp9J/7EblCqINXHeTc+1zqfJY/KqjOss=
14441446
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
14451447
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
14461448
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
@@ -1468,12 +1470,8 @@ github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c
14681470
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
14691471
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
14701472
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
1471-
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
1472-
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
1473-
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
1474-
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
1475-
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
1476-
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
1473+
github.com/shirou/gopsutil/v4 v4.25.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0ZqmLjXs=
1474+
github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI=
14771475
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
14781476
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
14791477
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=

pkg/addons/openebs/static/metadata.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ images:
1111
kubectl:
1212
repo: proxy.replicated.com/anonymous/replicated/ec-kubectl
1313
tag:
14-
amd64: 1.32.1-r3-amd64@sha256:6e53f43c9fae84996dd175b6a92eab9b908cc6ea9e947f3d672efb0e679126cd
15-
arm64: 1.32.1-r3-arm64@sha256:b64561c028e446c1dace22d3c3f073c2b0f9e5cf519eeafc8f62344b4f86de31
14+
amd64: 1.32.2-r0-amd64@sha256:5baf1c2b9b976c5685bb94d6e56eccff85dcd4f2dcdf0384ec99f3401393f577
15+
arm64: 1.32.2-r0-arm64@sha256:5b666becd4e6e948a0c610c5ff9fccbe2b77be650cdfe36a91ce84218cab7e17
1616
openebs-linux-utils:
1717
repo: proxy.replicated.com/anonymous/replicated/ec-openebs-linux-utils
1818
tag:
19-
amd64: 4.2.0-amd64@sha256:25472f140e897a60f8e3d31b4050c54156dfc129dacad966f3f89c86a4fa67bc
20-
arm64: 4.2.0-arm64@sha256:55e882fc99f63d5ad81c38b8cdae79d31f4c54c7704b7321cc3ec51d3701c8e3
19+
amd64: 4.2.0-amd64@sha256:0baa855632680d21112c919afc1f382afd8667278be779729e9be78c7fb002ec
20+
arm64: 4.2.0-arm64@sha256:a0e8a2533750e7c2e0117fb888582f6a14316161c671e35dfb01bc96a56d92d6
2121
openebs-provisioner-localpv:
2222
repo: proxy.replicated.com/anonymous/replicated/ec-openebs-provisioner-localpv
2323
tag:
24-
amd64: 4.2.0-r1-amd64@sha256:ccfd5ef25bd1d17502d78de9681b96919cccc5a57016b0c786baa69253a6a166
25-
arm64: 4.2.0-r1-arm64@sha256:c39ba145522b82eab9107144ee5a032685ea59718c170690ac26b9c93b158d48
24+
amd64: 4.2.0-r1-amd64@sha256:24e47faf23e8b6e71c2cb54a2ec9f9eed0912930c0397257b384c5b79c38593b
25+
arm64: 4.2.0-r1-arm64@sha256:9023c783a18adb7e2d74097cd274355e15e686aab71127b087bf1bdc0ac0c68b

pkg/addons/velero/static/metadata.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
# $ make buildtools
66
# $ output/bin/buildtools update addon <addon name>
77
#
8-
version: 8.3.0
8+
version: 8.4.0
99
location: oci://proxy.replicated.com/anonymous/registry.replicated.com/ec-charts/velero
1010
images:
1111
kubectl:
1212
repo: proxy.replicated.com/anonymous/replicated/ec-kubectl
1313
tag:
14-
amd64: 1.32.1-r3-amd64@sha256:6e53f43c9fae84996dd175b6a92eab9b908cc6ea9e947f3d672efb0e679126cd
15-
arm64: 1.32.1-r3-arm64@sha256:b64561c028e446c1dace22d3c3f073c2b0f9e5cf519eeafc8f62344b4f86de31
14+
amd64: 1.32.2-r0-amd64@sha256:5baf1c2b9b976c5685bb94d6e56eccff85dcd4f2dcdf0384ec99f3401393f577
15+
arm64: 1.32.2-r0-arm64@sha256:5b666becd4e6e948a0c610c5ff9fccbe2b77be650cdfe36a91ce84218cab7e17
1616
velero:
1717
repo: proxy.replicated.com/anonymous/replicated/ec-velero
1818
tag:

pkg/config/static/metadata.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ images:
1919
calico-node:
2020
repo: proxy.replicated.com/anonymous/replicated/ec-calico-node
2121
tag:
22-
amd64: 3.28.2-r1-amd64@sha256:f6092d79661704765175b4857bdcfdd44c8d1c9b4ec754cc47ad15b402f2f65e
23-
arm64: 3.28.2-r1-arm64@sha256:3d184d439432d453536617b0a39ada4f32a721f2c5931bf7c40ec961634711c7
22+
amd64: 3.28.2-r1-amd64@sha256:40e18779862fffc6b7baf9e25c13fa8076262efc1aee4a861de13c220f897ca8
23+
arm64: 3.28.2-r1-arm64@sha256:88c53fa8c802bbcc85eb9fe6d840dfde25342f6d5ea14c9dd127001fddae2d00
2424
coredns:
2525
repo: proxy.replicated.com/anonymous/replicated/ec-coredns
2626
tag:

pkg/configutils/runtime.go

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"os"
99
"os/exec"
1010
"path/filepath"
11+
"strconv"
1112
"strings"
1213

1314
"github.com/replicatedhq/embedded-cluster/pkg/helpers"
@@ -19,17 +20,45 @@ import (
1920
// purposes.
2021
var sysctlConfigPath = "/etc/sysctl.d/99-embedded-cluster.conf"
2122

22-
var modulesLoadConfigPath = "/etc/modules-load.d/99-embedded-cluster.conf"
23+
// dynamicSysctlConfigPath is the path to the dynamic sysctl config file that is used to configure
24+
// the embedded cluster.
25+
const dynamicSysctlConfigPath = "/etc/sysctl.d/99-dynamic-embedded-cluster.conf"
26+
27+
// modulesLoadConfigPath is the path to the kernel modules config file that is used to configure
28+
// the embedded cluster.
29+
const modulesLoadConfigPath = "/etc/modules-load.d/99-embedded-cluster.conf"
2330

2431
//go:embed static/sysctl.d/99-embedded-cluster.conf
2532
var embeddedClusterSysctlConf []byte
2633

2734
//go:embed static/modules-load.d/99-embedded-cluster.conf
2835
var embeddedClusterModulesConf []byte
2936

30-
// ConfigureSysctl writes the sysctl config file for the embedded cluster and reloads the sysctl
31-
// configuration. This function has a distinct behavior: if the sysctl binary does not exist it
32-
// returns an error but if it fails to lay down the sysctl config on disk it simply returns nil.
37+
// dynamicSysctlConstraints are the constraints that are used to generate the dynamic sysctl
38+
// config file.
39+
var dynamicSysctlConstraints = []sysctlConstraint{
40+
// Increase inotify limits only if they are currently lower,
41+
// ensuring proper operation of applications that monitor filesystem events.
42+
{key: "fs.inotify.max_user_instances", value: 1024, operator: sysctlOperatorMin},
43+
{key: "fs.inotify.max_user_watches", value: 65536, operator: sysctlOperatorMin},
44+
}
45+
46+
type sysctlOperator string
47+
48+
const (
49+
sysctlOperatorMin sysctlOperator = "min"
50+
sysctlOperatorMax sysctlOperator = "max"
51+
)
52+
53+
type sysctlConstraint struct {
54+
key string
55+
value int64
56+
operator sysctlOperator
57+
}
58+
59+
type sysctlValueGetter func(key string) (int64, error)
60+
61+
// ConfigureSysctl writes the sysctl config files for the embedded cluster and reloads the sysctl configuration.
3362
// NOTE: do not run this after the cluster has already been installed as it may revert sysctl
3463
// settings set by k0s and its extensions.
3564
func ConfigureSysctl() error {
@@ -41,6 +70,10 @@ func ConfigureSysctl() error {
4170
return fmt.Errorf("materialize sysctl config: %w", err)
4271
}
4372

73+
if err := dynamicSysctlConfig(); err != nil {
74+
return fmt.Errorf("materialize dynamic sysctl config: %w", err)
75+
}
76+
4477
if _, err := helpers.RunCommand("sysctl", "--system"); err != nil {
4578
return fmt.Errorf("configure sysctl: %w", err)
4679
}
@@ -58,6 +91,63 @@ func sysctlConfig() error {
5891
return nil
5992
}
6093

94+
// dynamicSysctlConfig generates a dynamic sysctl config file based on current system values
95+
// and our constraints.
96+
func dynamicSysctlConfig() error {
97+
return generateDynamicSysctlConfig(getCurrentSysctlValue, dynamicSysctlConfigPath)
98+
}
99+
100+
// generateDynamicSysctlConfig is the testable version of dynamicSysctlConfig that accepts
101+
// a custom sysctl value getter and config path.
102+
func generateDynamicSysctlConfig(getter sysctlValueGetter, configPath string) error {
103+
if err := os.MkdirAll(filepath.Dir(configPath), 0755); err != nil {
104+
return fmt.Errorf("create directory: %w", err)
105+
}
106+
107+
var config strings.Builder
108+
config.WriteString("# Dynamic sysctl configuration for embedded-cluster\n")
109+
config.WriteString("# This file is generated based on system values\n\n")
110+
111+
for _, constraint := range dynamicSysctlConstraints {
112+
currentValue, err := getter(constraint.key)
113+
if err != nil {
114+
return fmt.Errorf("check current value for %s: %w", constraint.key, err)
115+
}
116+
117+
needsUpdate := false
118+
switch constraint.operator {
119+
case sysctlOperatorMin:
120+
needsUpdate = currentValue < constraint.value
121+
case sysctlOperatorMax:
122+
needsUpdate = currentValue > constraint.value
123+
}
124+
125+
if needsUpdate {
126+
config.WriteString(fmt.Sprintf("%s = %d\n", constraint.key, constraint.value))
127+
}
128+
}
129+
130+
if err := os.WriteFile(configPath, []byte(config.String()), 0644); err != nil {
131+
return fmt.Errorf("write dynamic config file: %w", err)
132+
}
133+
return nil
134+
}
135+
136+
// getCurrentSysctlValue reads the current value of a sysctl parameter
137+
func getCurrentSysctlValue(key string) (int64, error) {
138+
out, err := helpers.RunCommand("sysctl", "-n", key)
139+
if err != nil {
140+
return 0, fmt.Errorf("get sysctl value: %w", err)
141+
}
142+
143+
value, err := strconv.ParseInt(strings.TrimSpace(string(out)), 10, 64)
144+
if err != nil {
145+
return 0, fmt.Errorf("parse sysctl value: %w", err)
146+
}
147+
148+
return value, nil
149+
}
150+
61151
// ConfigureKernelModules writes the kernel modules config file and ensures the kernel modules are
62152
// loaded that are listed in the file.
63153
func ConfigureKernelModules() error {

0 commit comments

Comments
 (0)