Skip to content

Commit 6d1f214

Browse files
yevgeny-shnaidmank8s-ci-robot
authored andcommitted
support inTree removal scenario for nodes without .ko files
Modprobe will fail with error in case it cannot find an appropriate .ko file when asked to remove a kernel module. With in-tree removal scenario, modporbe search path is /lib/modules on the host, and not the worker image. This PR contains the following: 1) Adding FileExists function that check the presence of a file under a search path based on a regexp 2) in worker flow, in case in-tree removal scenario is requisted, worker will verify if the requested .ko file(s) are present on the host, remove from the request missing files and will proceed with the removal scenario for the rest 3) unit-test
1 parent c188539 commit 6d1f214

File tree

5 files changed

+113
-9
lines changed

5 files changed

+113
-9
lines changed

internal/utils/filesystem_helper.go

+27
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package utils
22

33
import (
44
"fmt"
5+
"io/fs"
56
"os"
67
"path/filepath"
8+
"regexp"
79

810
"github.com/go-logr/logr"
911
)
@@ -12,6 +14,7 @@ import (
1214

1315
type FSHelper interface {
1416
RemoveSrcFilesFromDst(srcDir, dstDir string) error
17+
FileExists(root, fileRegex string) (bool, error)
1518
}
1619

1720
type fsHelper struct {
@@ -49,3 +52,27 @@ func (fh *fsHelper) RemoveSrcFilesFromDst(srcDir, dstDir string) error {
4952
}
5053
return nil
5154
}
55+
56+
func (fh *fsHelper) FileExists(root, fileRegex string) (bool, error) {
57+
regex, err := regexp.Compile(fileRegex)
58+
if err != nil {
59+
return false, fmt.Errorf("failed to compile regex %s: %v", fileRegex, err)
60+
}
61+
62+
found := false
63+
// Walk through the directory
64+
err = filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
65+
if err != nil {
66+
return err
67+
}
68+
69+
// Match file names against the regex
70+
if !d.IsDir() && regex.MatchString(d.Name()) {
71+
found = true
72+
return fs.SkipAll
73+
}
74+
return nil
75+
})
76+
77+
return found, err
78+
}

internal/utils/filesystem_helper_test.go

+40-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var _ = Describe("RemoveSrcFilesFromDst", func() {
1414
// source
1515
err := os.MkdirAll("./srcDir/level1", 0750)
1616
Expect(err).NotTo(HaveOccurred())
17+
defer os.RemoveAll("./srcDir")
1718
err = os.MkdirAll("./srcDir/level2", 0750)
1819
Expect(err).NotTo(HaveOccurred())
1920
err = os.MkdirAll("./srcDir/level4", 0750)
@@ -25,6 +26,7 @@ var _ = Describe("RemoveSrcFilesFromDst", func() {
2526
// destination
2627
err = os.MkdirAll("./dstDir/level1", 0750)
2728
Expect(err).NotTo(HaveOccurred())
29+
defer os.RemoveAll("./dstDir")
2830
err = os.MkdirAll("./dstDir/level2", 0750)
2931
Expect(err).NotTo(HaveOccurred())
3032
err = os.MkdirAll("./dstDir/level3", 0750)
@@ -42,9 +44,45 @@ var _ = Describe("RemoveSrcFilesFromDst", func() {
4244
verifyFileNotExists("./dstDir/level2/testfile2")
4345

4446
verifyFileExists("./dstDir/level3/testfile3")
47+
})
48+
})
4549

46-
defer os.RemoveAll("./dstDir")
47-
defer os.RemoveAll("./srcDir")
50+
var _ = Describe("FileExists", func() {
51+
It("test files", func() {
52+
err := os.MkdirAll("./testDir/level_1_0", 0750)
53+
Expect(err).NotTo(HaveOccurred())
54+
defer os.RemoveAll("./testDir")
55+
err = os.MkdirAll("./testDir/level_1_1", 0750)
56+
Expect(err).NotTo(HaveOccurred())
57+
err = os.MkdirAll("./testDir/level_2_0", 0750)
58+
Expect(err).NotTo(HaveOccurred())
59+
err = os.MkdirAll("./testDir/level_2_1", 0750)
60+
Expect(err).NotTo(HaveOccurred())
61+
createEmptyFile("./testDir/level_1_1/not_ko_file")
62+
createEmptyFile("./testDir/level_2_1/module1.ko.kz")
63+
createEmptyFile("./testDir/level_1_0/module2.ko")
64+
65+
helper := NewFSHelper(logr.Discard())
66+
67+
By("find existing file by full name")
68+
exists, err := helper.FileExists("testDir", "module2.ko")
69+
Expect(err).NotTo(HaveOccurred())
70+
Expect(exists).To(BeTrue())
71+
72+
By("find existing file by regexp name")
73+
exists, err = helper.FileExists("testDir", `.*\.ko*$`)
74+
Expect(err).NotTo(HaveOccurred())
75+
Expect(exists).To(BeTrue())
76+
77+
By("find existing file by regexp name, comparing prefix")
78+
exists, err = helper.FileExists("testDir", `^module1.ko`)
79+
Expect(err).NotTo(HaveOccurred())
80+
Expect(exists).To(BeTrue())
81+
82+
By("find non-existing file by regexp name")
83+
exists, err = helper.FileExists("testDir", `.*\.koz.*$`)
84+
Expect(err).NotTo(HaveOccurred())
85+
Expect(exists).To(BeFalse())
4886
})
4987
})
5088

internal/utils/mock_filesystem_helper.go

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/worker/worker.go

+19-3
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,26 @@ func (w *worker) LoadKmod(ctx context.Context, cfg *kmmv1beta1.ModuleConfig, fir
4747

4848
if inTreeModulesToRemove != nil {
4949
w.logger.Info("Unloading in-tree modules", "names", inTreeModulesToRemove)
50+
modulesToUnload := make([]string, 0, len(inTreeModulesToRemove))
51+
for _, module := range inTreeModulesToRemove {
52+
exists, err := w.fh.FileExists("/lib/modules", fmt.Sprintf("^%s.ko", module))
53+
if err != nil {
54+
w.logger.Info(utils.WarnString(fmt.Sprintf("failed to check if module file %s present on the host:", module)), "error", err)
55+
continue
56+
}
57+
if !exists {
58+
w.logger.Info("not trying to unload in-tree module, since its file is not present on the host", "module", module)
59+
continue
60+
}
61+
w.logger.Info("adding module to the list of intree modules to be unloadded", "module", module)
62+
modulesToUnload = append(modulesToUnload, module)
63+
}
5064

51-
runArgs := append([]string{"-rv"}, inTreeModulesToRemove...)
52-
if err := w.mr.Run(ctx, runArgs...); err != nil {
53-
return fmt.Errorf("could not remove in-tree modules %s: %v", strings.Join(inTreeModulesToRemove, ""), err)
65+
if len(modulesToUnload) > 0 {
66+
runArgs := append([]string{"-rv"}, modulesToUnload...)
67+
if err := w.mr.Run(ctx, runArgs...); err != nil {
68+
return fmt.Errorf("could not remove in-tree modules %s: %v", strings.Join(modulesToUnload, ""), err)
69+
}
5470
}
5571
}
5672

internal/worker/worker_test.go

+12-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package worker
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
"os"
78
"path/filepath"
89

@@ -15,6 +16,7 @@ import (
1516

1617
var _ = Describe("worker_LoadKmod", func() {
1718
var (
19+
fh *utils.MockFSHelper
1820
mr *MockModprobeRunner
1921
w Worker
2022
imageDir string
@@ -23,8 +25,9 @@ var _ = Describe("worker_LoadKmod", func() {
2325

2426
BeforeEach(func() {
2527
ctrl := gomock.NewController(GinkgoT())
28+
fh = utils.NewMockFSHelper(ctrl)
2629
mr = NewMockModprobeRunner(ctrl)
27-
w = NewWorker(mr, nil, GinkgoLogr)
30+
w = NewWorker(mr, fh, GinkgoLogr)
2831

2932
var err error
3033
imageDir, err = os.MkdirTemp("", "imageDir")
@@ -66,8 +69,8 @@ var _ = Describe("worker_LoadKmod", func() {
6669
)
6770
})
6871

69-
It("should remove the in-tree module if configured", func() {
70-
inTreeModulesToRemove := []string{"intree1", "intree2"}
72+
It("should remove present-on-host in-tree module if configured", func() {
73+
inTreeModulesToRemove := []string{"intree1", "intree2", "intree3", "intree4"}
7174

7275
cfg := v1beta1.ModuleConfig{
7376
ContainerImage: imageName,
@@ -79,7 +82,11 @@ var _ = Describe("worker_LoadKmod", func() {
7982
}
8083

8184
gomock.InOrder(
82-
mr.EXPECT().Run(ctx, "-rv", "intree1", "intree2"),
85+
fh.EXPECT().FileExists("/lib/modules", "^intree1.ko").Return(true, nil),
86+
fh.EXPECT().FileExists("/lib/modules", "^intree2.ko").Return(false, nil),
87+
fh.EXPECT().FileExists("/lib/modules", "^intree3.ko").Return(true, nil),
88+
fh.EXPECT().FileExists("/lib/modules", "^intree4.ko").Return(false, fmt.Errorf("some error")),
89+
mr.EXPECT().Run(ctx, "-rv", "intree1", "intree3"),
8390
mr.EXPECT().Run(ctx, "-vd", filepath.Join(sharedFilesDir, dirName), moduleName),
8491
)
8592

@@ -102,6 +109,7 @@ var _ = Describe("worker_LoadKmod", func() {
102109
}
103110

104111
gomock.InOrder(
112+
fh.EXPECT().FileExists("/lib/modules", "^intreeToRemove.ko").Return(true, nil),
105113
mr.EXPECT().Run(ctx, "-rv", "intreeToRemove"),
106114
mr.EXPECT().Run(ctx, "-vd", filepath.Join(sharedFilesDir, dirName), moduleName),
107115
)

0 commit comments

Comments
 (0)