diff --git a/internal/pkg/sysinfo/host_linux.go b/internal/pkg/sysinfo/host_linux.go index 96520b786a5d..d5a3c741d220 100644 --- a/internal/pkg/sysinfo/host_linux.go +++ b/internal/pkg/sysinfo/host_linux.go @@ -38,11 +38,15 @@ func (s *K0sSysinfoSpec) addHostSpecificProbes(p probes.Probes) { return "" }) - s.addKernelConfigs(linux) + linux.AssertProcessMaxFileDescriptors(65536) if s.WorkerRoleEnabled { + probes.AssertExecutablesInPath(linux, "modprobe") + linux.RequireProcFS() addCgroups(linux) } + + s.addKernelConfigs(linux) } func (s *K0sSysinfoSpec) addKernelConfigs(linux *linux.LinuxProbes) { diff --git a/internal/pkg/sysinfo/probes/executables.go b/internal/pkg/sysinfo/probes/executables.go new file mode 100644 index 000000000000..2422e9e5609b --- /dev/null +++ b/internal/pkg/sysinfo/probes/executables.go @@ -0,0 +1,38 @@ +/* +Copyright 2022 k0s 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 probes + +import ( + "fmt" + "os/exec" +) + +func AssertExecutablesInPath(p Probes, executables ...string) { + for _, executable := range executables { + p.Set(fmt.Sprintf("executableInPath:%s", executable), func(path ProbePath, _ Probe) Probe { + return ProbeFn(func(r Reporter) error { + desc := NewProbeDesc(fmt.Sprintf("Executable in path: %s", executable), path) + path, err := exec.LookPath(executable) + if err != nil { + return r.Warn(desc, ErrorProp(err), "") + } + + return r.Pass(desc, StringProp(path)) + }) + }) + } +} diff --git a/internal/pkg/sysinfo/probes/linux/procfs.go b/internal/pkg/sysinfo/probes/linux/procfs.go new file mode 100644 index 000000000000..16ad40bd01bd --- /dev/null +++ b/internal/pkg/sysinfo/probes/linux/procfs.go @@ -0,0 +1,60 @@ +//go:build linux +// +build linux + +/* +Copyright 2022 k0s 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 linux + +import ( + "fmt" + "os" + "syscall" + + "golang.org/x/sys/unix" + + "github.com/k0sproject/k0s/internal/pkg/sysinfo/probes" +) + +func (l *LinuxProbes) RequireProcFS() { + l.Set("procfs", func(path probes.ProbePath, _ probes.Probe) probes.Probe { + return probes.ProbeFn(func(r probes.Reporter) error { + mountPoint := "/proc" + desc := probes.NewProbeDesc(fmt.Sprintf("%s file system", mountPoint), path) + + var st syscall.Statfs_t + if err := syscall.Statfs(mountPoint, &st); err != nil { + if os.IsNotExist(err) { + return r.Reject(desc, probes.ErrorProp(err), "") + } + + return r.Error(desc, fmt.Errorf("failed to statfs %q: %w", mountPoint, err)) + } + + if st.Type != unix.PROC_SUPER_MAGIC { + return r.Reject(desc, procFSType(st.Type), "unexpected file system type") + } + + return r.Pass(desc, procFSType(st.Type)) + }) + }) +} + +type procFSType int64 + +func (t procFSType) String() string { + return fmt.Sprintf("mounted (0x%x)", int64(t)) +} diff --git a/internal/pkg/sysinfo/probes/linux/ulimit.go b/internal/pkg/sysinfo/probes/linux/ulimit.go new file mode 100644 index 000000000000..3850860e1429 --- /dev/null +++ b/internal/pkg/sysinfo/probes/linux/ulimit.go @@ -0,0 +1,47 @@ +//go:build linux +// +build linux + +/* +Copyright 2022 k0s 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 linux + +import ( + "fmt" + "syscall" + + "github.com/k0sproject/k0s/internal/pkg/sysinfo/probes" +) + +func (l *LinuxProbes) AssertProcessMaxFileDescriptors(min uint64) { + l.Set("RLIMIT_NOFILE", func(path probes.ProbePath, _ probes.Probe) probes.Probe { + return probes.ProbeFn(func(r probes.Reporter) error { + desc := probes.NewProbeDesc("Max. file descriptors per process", path) + + var rlimit syscall.Rlimit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil { + return r.Warn(desc, probes.ErrorProp(err), "") + } + + prop := probes.StringProp(fmt.Sprintf("current: %d / max: %d", rlimit.Cur, rlimit.Max)) + if rlimit.Cur < min { + return r.Warn(desc, prop, fmt.Sprintf("< %d", min)) + } + + return r.Pass(desc, prop) + }) + }) +} diff --git a/internal/pkg/sysinfo/probes/probes.go b/internal/pkg/sysinfo/probes/probes.go index 4aad5e0afbb4..5a875783c89f 100644 --- a/internal/pkg/sysinfo/probes/probes.go +++ b/internal/pkg/sysinfo/probes/probes.go @@ -74,6 +74,21 @@ type ProbedProp interface { String() string } +// StringProp is a convenience way of reporting an arbitrary string as a probed property. +type StringProp string + +func (s StringProp) String() string { + return string(s) +} + +// ErrorProp is a convenience way of reporting an arbitrary error as a probed property. +func ErrorProp(err error) interface { + ProbedProp + error +} { + return errorProp{err} +} + // Reporter receives the outcome of probes. type Reporter interface { // Pass informs about a probe that passed. @@ -115,6 +130,16 @@ type probeDesc struct { func (d *probeDesc) Path() ProbePath { return d.path } func (d *probeDesc) DisplayName() string { return d.name } +type errorProp struct{ error } + +func (e errorProp) String() string { + return e.Error() +} + +func (e errorProp) Unwrap() error { + return e.error +} + type probes struct { path ProbePath probes []*containedProbe