Skip to content

Commit

Permalink
move chwrap common functionality to internal package (#1723)
Browse files Browse the repository at this point in the history
* move chwrap common functionality to osutils and make example call from nodeprep

* moved chwrap common functions to internal/chwrap

* fix root path

* renamed and added constant

* fix linter issue

* gofumpt it

* review comments inject only findBinary and remove unnecessary interface

* chwrap not windows

* change string type to alias

* add windows stub
  • Loading branch information
brownaaron authored Sep 19, 2024
1 parent 6d55b38 commit 397c153
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 44 deletions.
46 changes: 6 additions & 40 deletions chwrap/chwrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,9 @@ import (
"strings"

"golang.org/x/sys/unix"
)

func validBinary(path string) bool {
var stat unix.Stat_t
if err := unix.Stat(path, &stat); nil != err {
// Can't stat file
return false
}
if (stat.Mode&unix.S_IFMT) != unix.S_IFREG && (stat.Mode&unix.S_IFMT) != unix.S_IFLNK {
// Not a regular file or symlink
return false
}
if 0 == stat.Mode&unix.S_IRUSR || 0 == stat.Mode&unix.S_IXUSR {
// Not readable or not executable
return false
}
return true
}

func findBinary(prefix, binary string) string {
for _, part1 := range []string{"usr/local/", "usr/", ""} {
for _, part2 := range []string{"sbin", "bin"} {
path := "/" + part1 + part2 + "/" + binary
if validBinary(prefix + path) {
return path
}
}
}
return ""
}
"github.com/netapp/trident/internal/chwrap"
)

func modifyEnv(oldEnv []string) []string {
var newEnv []string
Expand All @@ -53,26 +26,19 @@ func modifyEnv(oldEnv []string) []string {
}

func main() {
rootPath := "/host"
// First modify argv0 to strip off any absolute or relative paths
argv := os.Args
binary := argv[0]
idx := strings.LastIndexByte(binary, '/')
if 0 <= idx {
binary = binary[idx+1:]
}
// Now implement the path search logic, but in the host's filesystem
argv0 := findBinary(rootPath, binary)

rootPath, argv0 := chwrap.FindBinary(binary)
if "" == argv0 {
// binary is not found on /host.
argv0 = findBinary("", binary)
if "" == argv0 {
panic(binary + " not found")
} else {
// Binary found locally.
rootPath = "/"
}
panic(binary + " not found")
}

// Chroot in the host's FS
if err := unix.Chroot(rootPath); nil != err {
panic(err)
Expand Down
2 changes: 1 addition & 1 deletion cmd/node_prep/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func main() {
"binary": os.Args[0],
}).Info("Running Trident node preparation.")

nodeprep.PrepareNode(strings.Split(strings.ToLower(*flags.nodePrep), ","))
nodeprep.NewNodePrep().PrepareNode(strings.Split(strings.ToLower(*flags.nodePrep), ","))
}

func initLogging(flags appFlags) {
Expand Down
47 changes: 47 additions & 0 deletions internal/chwrap/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//go:build !windows
// +build !windows

package chwrap

import "golang.org/x/sys/unix"

const (
hostRootPath = "/host"
containerRootPath = "/"
)

func validBinary(path string) bool {
var stat unix.Stat_t
if err := unix.Stat(path, &stat); nil != err {
// Can't stat file
return false
}
if (stat.Mode&unix.S_IFMT) != unix.S_IFREG && (stat.Mode&unix.S_IFMT) != unix.S_IFLNK {
// Not a regular file or symlink
return false
}
if 0 == stat.Mode&unix.S_IRUSR || 0 == stat.Mode&unix.S_IXUSR {
// Not readable or not executable
return false
}
return true
}

func findBinary(prefix, binary string) string {
for _, part1 := range []string{"usr/local/", "usr/", ""} {
for _, part2 := range []string{"sbin", "bin"} {
path := "/" + part1 + part2 + "/" + binary
if validBinary(prefix + path) {
return path
}
}
}
return ""
}

func FindBinary(binary string) (rootPath, fullPath string) {
if fullPath = findBinary(hostRootPath, binary); fullPath != "" {
return hostRootPath, fullPath
}
return containerRootPath, findBinary("", binary)
}
8 changes: 8 additions & 0 deletions internal/chwrap/winutils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//go:build windows
// +build windows

package chwrap

func FindBinary(binary string) (rootPath, fullPath string) {
return "", ""
}
40 changes: 39 additions & 1 deletion internal/nodeprep/nodeprep.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,31 @@
package nodeprep

import (
"github.com/netapp/trident/internal/chwrap"
. "github.com/netapp/trident/logging"
utilserrors "github.com/netapp/trident/utils/errors"
)

func PrepareNode(requestedProtocols []string) (exitCode int) {
type PkgMgr = string

const (
PkgMgrYum PkgMgr = "yum"
PkgMgrApt PkgMgr = "apt"
)

type NodePrep struct {
findBinary func(string) (string, string)
}

func NewNodePrep() *NodePrep {
return NewNodePrepDetailed(chwrap.FindBinary)
}

func NewNodePrepDetailed(findBinary func(string) (string, string)) *NodePrep {
return &NodePrep{findBinary: findBinary}
}

func (n *NodePrep) PrepareNode(requestedProtocols []string) (exitCode int) {
Log().WithField("requestedProtocols", requestedProtocols).Info("Preparing node")
defer func() {
Log().WithField("exitCode", exitCode).Info("Node preparation complete")
Expand All @@ -17,5 +38,22 @@ func PrepareNode(requestedProtocols []string) (exitCode int) {
return 0
}

pkgMgr, err := n.getPkgMgr()
if err != nil {
Log().WithError(err).Error("Failed to determine package manager")
return 1
}
Log().Info("Package manager found: ", pkgMgr)

return 0
}

func (n *NodePrep) getPkgMgr() (PkgMgr, error) {
if _, pkgMgr := n.findBinary(string(PkgMgrYum)); pkgMgr != "" {
return PkgMgrYum, nil
}
if _, pkgMgr := n.findBinary(string(PkgMgrApt)); pkgMgr != "" {
return PkgMgrApt, nil
}
return "", utilserrors.UnsupportedError("a supported package manager was not found")
}
51 changes: 49 additions & 2 deletions internal/nodeprep/nodeprep_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/netapp/trident/internal/nodeprep"
)

func TestPrepareNode(t *testing.T) {
func TestPrepareNodeProtocols(t *testing.T) {
type parameters struct {
protocols []string
expectedExitCode int
Expand All @@ -28,8 +28,55 @@ func TestPrepareNode(t *testing.T) {

for name, params := range tests {
t.Run(name, func(t *testing.T) {
exitCode := nodeprep.PrepareNode(params.protocols)
exitCode := nodeprep.NewNodePrepDetailed(NewFindBinaryMock(nodeprep.PkgMgrYum).FindBinary).PrepareNode(params.protocols)
assert.Equal(t, params.expectedExitCode, exitCode)
})
}
}

func TestPrepareNodePkgMgr(t *testing.T) {
type parameters struct {
findBinaryMock *FindBinaryMock
expectedExitCode int
}
tests := map[string]parameters{
"supported yum": {
findBinaryMock: NewFindBinaryMock(nodeprep.PkgMgrYum),
expectedExitCode: 0,
},
"supported apt": {
findBinaryMock: NewFindBinaryMock(nodeprep.PkgMgrApt),
expectedExitCode: 0,
},
"not supported": {
findBinaryMock: NewFindBinaryMock("other"),
expectedExitCode: 1,
},
"empty": {
findBinaryMock: NewFindBinaryMock(""),
expectedExitCode: 1,
},
}

for name, params := range tests {
t.Run(name, func(t *testing.T) {
exitCode := nodeprep.NewNodePrepDetailed(params.findBinaryMock.FindBinary).PrepareNode([]string{"iscsi"})
assert.Equal(t, params.expectedExitCode, exitCode)
})
}
}

type FindBinaryMock struct {
binary string
}

func NewFindBinaryMock(binary nodeprep.PkgMgr) *FindBinaryMock {
return &FindBinaryMock{binary: string(binary)}
}

func (f *FindBinaryMock) FindBinary(binary string) (string, string) {
if binary == f.binary {
return "/host", "/bin/" + binary
}
return "", ""
}

0 comments on commit 397c153

Please sign in to comment.