Skip to content

Commit

Permalink
Introducing FileSystemHelper interface (rh-ecosystem-edge#1205)
Browse files Browse the repository at this point in the history
This interface handles filesystem functionality used mainly by worker
In the latter PRs it will be updated to extend the support of various
in-tree removal scenarious. In addition it will allow for better testing
of the functionality related to deleting/verifying/copying files.
  • Loading branch information
yevgeny-shnaidman committed Sep 11, 2024
1 parent da1e656 commit 6a77549
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 48 deletions.
4 changes: 3 additions & 1 deletion cmd/worker/funcs_kmod.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"fmt"

"github.com/rh-ecosystem-edge/kernel-module-management/internal/utils"
"github.com/rh-ecosystem-edge/kernel-module-management/internal/worker"
"github.com/spf13/cobra"
)
Expand All @@ -11,7 +12,8 @@ func rootFuncPreRunE(cmd *cobra.Command, args []string) error {
logger.Info("Starting worker", "version", Version, "git commit", GitCommit)

mr := worker.NewModprobeRunner(logger)
w = worker.NewWorker(mr, logger)
fsh := utils.NewFSHelper(logger)
w = worker.NewWorker(mr, fsh, logger)

return nil
}
Expand Down
51 changes: 51 additions & 0 deletions internal/utils/filesystem_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package utils

import (
"fmt"
"os"
"path/filepath"

"github.com/go-logr/logr"
)

//go:generate mockgen -source=filesystem_helper.go -package=utils -destination=mock_filesystem_helper.go

type FSHelper interface {
RemoveSrcFilesFromDst(srcDir, dstDir string) error
}

type fsHelper struct {
logger logr.Logger
}

func NewFSHelper(logger logr.Logger) FSHelper {
return &fsHelper{
logger: logger,
}
}

func (fh *fsHelper) RemoveSrcFilesFromDst(srcDir, dstDir string) error {
err := filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
relPath, err := filepath.Rel(srcDir, path)
if err != nil {
fh.logger.Info(WarnString("failed to get relative path"), "srcDir", srcDir, "path", path, "error", err)
return nil
}
fileToRemove := filepath.Join(dstDir, relPath)
fh.logger.Info("Removing dst file", "file", fileToRemove)
err = os.Remove(fileToRemove)
if err != nil {
fh.logger.Info(WarnString("failed to delete file"), "file", fileToRemove, "error", err)
}
}
return nil
})
if err != nil {
return fmt.Errorf("failed to remove files %s/* from %s\n", srcDir, dstDir)
}
return nil
}
65 changes: 65 additions & 0 deletions internal/utils/filesystem_helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package utils

import (
"os"

"github.com/go-logr/logr"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("RemoveSrcFilesFromDst", func() {

It("test removal", func() {
// source
err := os.MkdirAll("./srcDir/level1", 0750)
Expect(err).NotTo(HaveOccurred())
err = os.MkdirAll("./srcDir/level2", 0750)
Expect(err).NotTo(HaveOccurred())
err = os.MkdirAll("./srcDir/level4", 0750)
Expect(err).NotTo(HaveOccurred())
createEmptyFile("./srcDir/level1/testfile1")
createEmptyFile("./srcDir/level2/testfile2")
createEmptyFile("./srcDir/level4/testfile4")

// destination
err = os.MkdirAll("./dstDir/level1", 0750)
Expect(err).NotTo(HaveOccurred())
err = os.MkdirAll("./dstDir/level2", 0750)
Expect(err).NotTo(HaveOccurred())
err = os.MkdirAll("./dstDir/level3", 0750)
Expect(err).NotTo(HaveOccurred())
createEmptyFile("./dstDir/level1/testfile1")
createEmptyFile("./dstDir/level2/testfile2")
createEmptyFile("./dstDir/level3/testfile3")

helper := NewFSHelper(logr.Discard())

err = helper.RemoveSrcFilesFromDst("./srcDir", "./dstDir")
Expect(err).NotTo(HaveOccurred())

verifyFileNotExists("./dstDir/level1/testfile1")
verifyFileNotExists("./dstDir/level2/testfile2")

verifyFileExists("./dstDir/level3/testfile3")

defer os.RemoveAll("./dstDir")
defer os.RemoveAll("./srcDir")
})
})

func createEmptyFile(filePath string) {
file, err := os.Create(filePath)
Expect(err).NotTo(HaveOccurred())
defer file.Close()
}

func verifyFileExists(filepath string) {
_, err := os.Stat(filepath)
Expect(err).NotTo(HaveOccurred())
}

func verifyFileNotExists(filepath string) {
_, err := os.Stat(filepath)
Expect(err).To(HaveOccurred())
}
52 changes: 52 additions & 0 deletions internal/utils/mock_filesystem_helper.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 4 additions & 20 deletions internal/worker/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ type Worker interface {
type worker struct {
logger logr.Logger
mr ModprobeRunner
fh utils.FSHelper
}

func NewWorker(mr ModprobeRunner, logger logr.Logger) Worker {
func NewWorker(mr ModprobeRunner, fh utils.FSHelper, logger logr.Logger) Worker {
return &worker{
logger: logger,
mr: mr,
fh: fh,
}
}

Expand Down Expand Up @@ -140,25 +142,7 @@ func (w *worker) UnloadKmod(ctx context.Context, cfg *kmmv1beta1.ModuleConfig, f
//remove firmware files only (no directories)
if cfg.Modprobe.FirmwarePath != "" {
imageFirmwarePath := filepath.Join(sharedFilesDir, cfg.Modprobe.FirmwarePath)
err := filepath.Walk(imageFirmwarePath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
relPath, err := filepath.Rel(imageFirmwarePath, path)
if err != nil {
w.logger.Info(utils.WarnString("failed to get relative path"), "imageFirmwarePath", imageFirmwarePath, "path", path, "error", err)
return nil
}
fileToRemove := filepath.Join(firmwareMountPath, relPath)
w.logger.Info("Removing firmware file", "file", fileToRemove)
err = os.Remove(fileToRemove)
if err != nil {
w.logger.Info(utils.WarnString("failed to delete file"), "file", fileToRemove, "error", err)
}
}
return nil
})
err := w.fh.RemoveSrcFilesFromDst(imageFirmwarePath, firmwareMountPath)
if err != nil {
w.logger.Info(utils.WarnString("failed to remove all firmware blobs"), "error", err)
}
Expand Down
34 changes: 7 additions & 27 deletions internal/worker/worker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/rh-ecosystem-edge/kernel-module-management/api/v1beta1"
"github.com/rh-ecosystem-edge/kernel-module-management/internal/utils"
"go.uber.org/mock/gomock"
)

Expand All @@ -23,7 +24,7 @@ var _ = Describe("worker_LoadKmod", func() {
BeforeEach(func() {
ctrl := gomock.NewController(GinkgoT())
mr = NewMockModprobeRunner(ctrl)
w = NewWorker(mr, GinkgoLogr)
w = NewWorker(mr, nil, GinkgoLogr)

var err error
imageDir, err = os.MkdirTemp("", "imageDir")
Expand Down Expand Up @@ -185,7 +186,7 @@ var _ = Describe("worker_LoadKmod", func() {
})

var _ = Describe("worker_SetFirmwareClassPath", func() {
w := NewWorker(nil, GinkgoLogr)
w := NewWorker(nil, nil, GinkgoLogr)

AfterEach(func() {
firmwareClassPathLocation = FirmwareClassPathLocation
Expand Down Expand Up @@ -234,6 +235,7 @@ var _ = Describe("worker_SetFirmwareClassPath", func() {
var _ = Describe("worker_UnloadKmod", func() {
var (
mr *MockModprobeRunner
fh *utils.MockFSHelper
w Worker
imageDir string
hostDir string
Expand All @@ -242,7 +244,8 @@ var _ = Describe("worker_UnloadKmod", func() {
BeforeEach(func() {
ctrl := gomock.NewController(GinkgoT())
mr = NewMockModprobeRunner(ctrl)
w = NewWorker(mr, GinkgoLogr)
fh = utils.NewMockFSHelper(ctrl)
w = NewWorker(mr, fh, GinkgoLogr)
var err error
imageDir, err = os.MkdirTemp("", "imageDir")
Expect(err).Should(BeNil())
Expand Down Expand Up @@ -331,37 +334,14 @@ var _ = Describe("worker_UnloadKmod", func() {
},
}

// prepare the image firmware directories + files
err := os.MkdirAll(imageDir+"/"+"firmwareDir/binDir", 0750)
Expect(err).Should(BeNil())
err = os.WriteFile(imageDir+"/"+"firmwareDir/firmwareFile1", []byte("some data 1"), 0660)
Expect(err).Should(BeNil())
err = os.WriteFile(imageDir+"/"+"firmwareDir/binDir/firmwareFile2", []byte("some data 2"), 0660)
Expect(err).Should(BeNil())

// prepare the mapped host firmware directories + files
err = os.MkdirAll(hostDir+"/binDir", 0750)
Expect(err).Should(BeNil())
err = os.WriteFile(hostDir+"/firmwareFile1", []byte("some data 1"), 0660)
Expect(err).Should(BeNil())
err = os.WriteFile(hostDir+"/binDir/firmwareFile2", []byte("some data 2"), 0660)
Expect(err).Should(BeNil())

mr.EXPECT().Run(ctx, "-rvd", filepath.Join(sharedFilesDir, dirName), moduleName)
fh.EXPECT().RemoveSrcFilesFromDst(filepath.Join(sharedFilesDir, cfg.Modprobe.FirmwarePath), hostDir).Return(nil)

Expect(
w.UnloadKmod(ctx, &cfg, hostDir),
).NotTo(
HaveOccurred(),
)

// check only the files deletion
_, err = os.Stat(hostDir + "/binDir")
Expect(err).Should(BeNil())
_, err = os.Stat(hostDir + "/binDir/firwmwareFile2")
Expect(err).NotTo(BeNil())
_, err = os.Stat(hostDir + "/firwmwareFile1")
Expect(err).NotTo(BeNil())
})
})

Expand Down

0 comments on commit 6a77549

Please sign in to comment.