Skip to content

Commit 51c3a0c

Browse files
authored
fix(host-preflights): buildtin kernel modules file from wrong path (#1741)
* fix(host-preflights): buildtin kernel modules file from wrong path * f * f * f * f
1 parent f3b3085 commit 51c3a0c

File tree

3 files changed

+164
-26
lines changed

3 files changed

+164
-26
lines changed

pkg/collect/host_collector.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ func GetHostCollector(collector *troubleshootv1beta2.HostCollect, bundlePath str
6969
hostCollector: collector.KernelModules,
7070
BundlePath: bundlePath,
7171
loadable: kernelModulesLoadable{},
72-
loaded: kernelModulesLoaded{},
72+
loaded: kernelModulesLoaded{
73+
fs: os.DirFS("/"),
74+
},
7375
}, true
7476
case collector.TCPConnect != nil:
7577
return &CollectHostTCPConnect{collector.TCPConnect, bundlePath}, true

pkg/collect/host_kernel_modules.go

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/json"
77
"fmt"
88
"io"
9+
"io/fs"
910
"os"
1011
"os/exec"
1112
"path/filepath"
@@ -38,7 +39,7 @@ const HostKernelModulesPath = `host-collectors/system/kernel_modules.json`
3839
// kernelModuleCollector defines the interface used to collect modules from the
3940
// underlying host.
4041
type kernelModuleCollector interface {
41-
collect() (map[string]KernelModuleInfo, error)
42+
collect(kernelRelease string) (map[string]KernelModuleInfo, error)
4243
}
4344

4445
// CollectHostKernelModules is responsible for collecting kernel module status
@@ -79,14 +80,20 @@ func (c *CollectHostKernelModules) IsExcluded() (bool, error) {
7980
// a module is loaded, it may have one or more instances. The size represents
8081
// the amount of memory (in bytes) that the module is using.
8182
func (c *CollectHostKernelModules) Collect(progressChan chan<- interface{}) (map[string][]byte, error) {
82-
modules, err := c.loadable.collect()
83+
out, err := exec.Command("uname", "-r").Output()
84+
if err != nil {
85+
return nil, errors.Wrap(err, "failed to determine kernel release")
86+
}
87+
kernelRelease := strings.TrimSpace(string(out))
88+
89+
modules, err := c.loadable.collect(kernelRelease)
8390
if err != nil {
8491
return nil, errors.Wrap(err, "failed to read loadable kernel modules")
8592
}
8693
if modules == nil {
8794
modules = map[string]KernelModuleInfo{}
8895
}
89-
loaded, err := c.loaded.collect()
96+
loaded, err := c.loaded.collect(kernelRelease)
9097
if err != nil {
9198
return nil, errors.Wrap(err, "failed to read loaded kernel modules")
9299
}
@@ -114,20 +121,17 @@ func (c *CollectHostKernelModules) Collect(progressChan chan<- interface{}) (map
114121
type kernelModulesLoadable struct{}
115122

116123
// collect the list of modules that can be loaded by the kernel.
117-
func (l kernelModulesLoadable) collect() (map[string]KernelModuleInfo, error) {
124+
func (l kernelModulesLoadable) collect(kernelRelease string) (map[string]KernelModuleInfo, error) {
118125
modules := make(map[string]KernelModuleInfo)
119126

120-
out, err := exec.Command("uname", "-r").Output()
121-
if err != nil {
122-
return nil, errors.Wrap(err, "failed to determine kernel release")
123-
}
124-
kernel := strings.TrimSpace(string(out))
125-
126-
kernelPath := "/lib/modules/" + kernel
127-
127+
kernelPath := filepath.Join("/lib/modules", kernelRelease)
128128
if _, err := os.Stat(kernelPath); os.IsNotExist(err) {
129-
klog.V(2).Infof("modules are not loadable because kernel path %q does not exist, assuming we are in a container", kernelPath)
130-
return modules, nil
129+
kernelPath = filepath.Join("/usr/lib/modules", kernelRelease)
130+
if _, err := os.Stat(kernelPath); os.IsNotExist(err) {
131+
kernelPath = filepath.Join("/lib/modules", kernelRelease)
132+
klog.V(2).Infof("kernel modules are not loadable because path %q does not exist, assuming we are in a container", kernelPath)
133+
return modules, nil
134+
}
131135
}
132136

133137
cmd := exec.Command("/usr/bin/find", kernelPath, "-type", "f", "-name", "*.ko*")
@@ -155,16 +159,18 @@ func (l kernelModulesLoadable) collect() (map[string]KernelModuleInfo, error) {
155159

156160
// kernelModulesLoaded retrieves the list of modules that the kernel is aware of. The
157161
// modules will either be in loaded, loading or unloading state.
158-
type kernelModulesLoaded struct{}
162+
type kernelModulesLoaded struct {
163+
fs fs.FS
164+
}
159165

160166
// collect the list of modules that the kernel is aware of.
161-
func (l kernelModulesLoaded) collect() (map[string]KernelModuleInfo, error) {
167+
func (l kernelModulesLoaded) collect(kernelRelease string) (map[string]KernelModuleInfo, error) {
162168
modules, err := l.collectProc()
163169
if err != nil {
164170
return nil, fmt.Errorf("proc: %w", err)
165171
}
166172

167-
builtin, err := l.collectBuiltin()
173+
builtin, err := l.collectBuiltin(kernelRelease)
168174
if err != nil {
169175
return nil, fmt.Errorf("builtin: %w", err)
170176
}
@@ -181,7 +187,7 @@ func (l kernelModulesLoaded) collect() (map[string]KernelModuleInfo, error) {
181187
func (l kernelModulesLoaded) collectProc() (map[string]KernelModuleInfo, error) {
182188
modules := make(map[string]KernelModuleInfo)
183189

184-
file, err := os.Open("/proc/modules")
190+
file, err := l.fs.Open("proc/modules")
185191
if err != nil {
186192
return nil, err
187193
}
@@ -221,14 +227,18 @@ func (l kernelModulesLoaded) collectProc() (map[string]KernelModuleInfo, error)
221227
return modules, nil
222228
}
223229

224-
func (l kernelModulesLoaded) collectBuiltin() (map[string]KernelModuleInfo, error) {
225-
out, err := exec.Command("uname", "-r").Output()
226-
if err != nil {
227-
return nil, errors.Wrap(err, "failed to determine kernel release")
230+
func (l kernelModulesLoaded) collectBuiltin(kernelRelease string) (map[string]KernelModuleInfo, error) {
231+
builtinPath := filepath.Join("lib/modules", kernelRelease, "modules.builtin")
232+
if _, err := fs.Stat(l.fs, builtinPath); os.IsNotExist(err) {
233+
builtinPath = filepath.Join("usr/lib/modules", kernelRelease, "modules.builtin")
234+
if _, err := fs.Stat(l.fs, builtinPath); os.IsNotExist(err) {
235+
builtinPath = filepath.Join("lib/modules", kernelRelease, "modules.builtin")
236+
klog.V(2).Infof("kernel builtin modules path %q does not exist, assuming we are in a container", builtinPath)
237+
return nil, nil
238+
}
228239
}
229-
kernel := strings.TrimSpace(string(out))
230240

231-
file, err := os.Open(fmt.Sprintf("/usr/lib/modules/%s/modules.builtin", kernel))
241+
file, err := l.fs.Open(builtinPath)
232242
if err != nil {
233243
if os.IsNotExist(err) {
234244
return nil, nil

pkg/collect/host_kernel_modules_test.go

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package collect
22

33
import (
4+
"io/fs"
45
"reflect"
56
"strings"
67
"testing"
8+
"testing/fstest"
79

810
"github.com/pkg/errors"
911
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
@@ -14,7 +16,7 @@ type mockKernelModulesCollector struct {
1416
err error
1517
}
1618

17-
func (m mockKernelModulesCollector) collect() (map[string]KernelModuleInfo, error) {
19+
func (m mockKernelModulesCollector) collect(kernelRelease string) (map[string]KernelModuleInfo, error) {
1820
if m.err != nil {
1921
return nil, m.err
2022
}
@@ -213,3 +215,127 @@ kernel/arch/x86/events/intel/intel-cstate.ko`,
213215
})
214216
}
215217
}
218+
219+
func Test_kernelModulesLoaded_collect(t *testing.T) {
220+
tests := []struct {
221+
name string
222+
fs fs.FS
223+
kernelRelease string
224+
want map[string]KernelModuleInfo
225+
wantErr bool
226+
}{
227+
{
228+
name: "lib modules path",
229+
fs: &fstest.MapFS{
230+
"proc/modules": &fstest.MapFile{
231+
Data: []byte(`module1 1000 2 - Live 0x0000000000000000
232+
module2 2000 1 - Loading 0x0000000000000000
233+
`),
234+
Mode: 0444,
235+
},
236+
"lib/modules/5.4.0/modules.builtin": &fstest.MapFile{
237+
Data: []byte(`kernel/builtin1.ko
238+
kernel/builtin2.ko
239+
`),
240+
Mode: 0644,
241+
},
242+
},
243+
kernelRelease: "5.4.0",
244+
want: map[string]KernelModuleInfo{
245+
"module1": {
246+
Size: 1000,
247+
Instances: 2,
248+
Status: KernelModuleLoaded,
249+
},
250+
"module2": {
251+
Size: 2000,
252+
Instances: 1,
253+
Status: KernelModuleLoading,
254+
},
255+
"builtin1": {
256+
Status: KernelModuleLoaded,
257+
},
258+
"builtin2": {
259+
Status: KernelModuleLoaded,
260+
},
261+
},
262+
},
263+
{
264+
name: "usr lib modules path",
265+
fs: &fstest.MapFS{
266+
"proc/modules": &fstest.MapFile{
267+
Data: []byte(`module1 1000 2 - Live 0x0000000000000000
268+
`),
269+
Mode: 0444,
270+
},
271+
"usr/lib/modules/5.4.0/modules.builtin": &fstest.MapFile{
272+
Data: []byte(`kernel/builtin1.ko
273+
kernel/builtin2.ko
274+
`),
275+
Mode: 0644,
276+
},
277+
},
278+
kernelRelease: "5.4.0",
279+
want: map[string]KernelModuleInfo{
280+
"module1": {
281+
Size: 1000,
282+
Instances: 2,
283+
Status: KernelModuleLoaded,
284+
},
285+
"builtin1": {
286+
Status: KernelModuleLoaded,
287+
},
288+
"builtin2": {
289+
Status: KernelModuleLoaded,
290+
},
291+
},
292+
},
293+
{
294+
name: "no builtin modules file",
295+
fs: &fstest.MapFS{
296+
"proc/modules": &fstest.MapFile{
297+
Data: []byte(`module1 1000 2 - Live 0x0000000000000000
298+
`),
299+
Mode: 0444,
300+
},
301+
},
302+
kernelRelease: "5.4.0",
303+
want: map[string]KernelModuleInfo{
304+
"module1": {
305+
Size: 1000,
306+
Instances: 2,
307+
Status: KernelModuleLoaded,
308+
},
309+
},
310+
},
311+
{
312+
name: "no proc modules file should error",
313+
fs: &fstest.MapFS{
314+
"lib/modules/5.4.0/modules.builtin": &fstest.MapFile{
315+
Data: []byte(`kernel/builtin1.ko
316+
kernel/builtin2.ko
317+
`),
318+
Mode: 0644,
319+
},
320+
},
321+
kernelRelease: "5.4.0",
322+
wantErr: true,
323+
},
324+
}
325+
326+
for _, tt := range tests {
327+
t.Run(tt.name, func(t *testing.T) {
328+
l := kernelModulesLoaded{
329+
fs: tt.fs,
330+
}
331+
got, err := l.collect(tt.kernelRelease)
332+
if (err != nil) != tt.wantErr {
333+
t.Errorf("kernelModulesLoaded.collect() error = %v, wantErr %v", err, tt.wantErr)
334+
return
335+
}
336+
if !reflect.DeepEqual(got, tt.want) {
337+
t.Errorf("kernelModulesLoaded.collect() = %v, want %v", got, tt.want)
338+
}
339+
})
340+
}
341+
}

0 commit comments

Comments
 (0)