From 0b6dfc5396d3fad3bceecee908b4fca148af498e Mon Sep 17 00:00:00 2001 From: Vicente Cheng Date: Mon, 29 Jan 2024 00:24:43 +0800 Subject: [PATCH 1/3] utils: add process and command funcs - that we can drop some dependency Signed-off-by: Vicente Cheng --- pkg/block/block_device.go | 3 +- pkg/utils/command.go | 83 +++++++++++++++++++++++++++++++++++++++ pkg/utils/process.go | 73 ++++++++++++++++++++++++++++++++++ pkg/utils/utils.go | 9 ++--- 4 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 pkg/utils/command.go create mode 100644 pkg/utils/process.go diff --git a/pkg/block/block_device.go b/pkg/block/block_device.go index e5d9a497..6af6b8d4 100644 --- a/pkg/block/block_device.go +++ b/pkg/block/block_device.go @@ -14,7 +14,6 @@ import ( "github.com/jaypipes/ghw/pkg/linuxpath" "github.com/jaypipes/ghw/pkg/option" "github.com/jaypipes/ghw/pkg/util" - iscsiutil "github.com/longhorn/go-iscsi-helper/util" "github.com/sirupsen/logrus" "golang.org/x/crypto/blake2b" @@ -493,7 +492,7 @@ func partitionInfo(ctx *context.Context, paths *linuxpath.Paths, part string) (s func openProcMounts(ctx *context.Context, paths *linuxpath.Paths) (*os.File, error) { file := paths.ProcMounts if path, ok := ctx.PathOverrides[ndmutils.ProcPath]; ok { - ns := iscsiutil.GetHostNamespacePath(path) + ns := ndmutils.GetHostNamespacePath(path) file = strings.TrimSuffix(ns, "ns/") + "mounts" } return os.Open(file) diff --git a/pkg/utils/command.go b/pkg/utils/command.go new file mode 100644 index 00000000..46378bfd --- /dev/null +++ b/pkg/utils/command.go @@ -0,0 +1,83 @@ +package utils + +import ( + "bytes" + "os/exec" + "path/filepath" + "time" + + "github.com/pkg/errors" +) + +const ( + NSBinary = "nsenter" + cmdTimeoutDefault = 180 * time.Second // 3 minutes by default + cmdTimeoutNone = 0 * time.Second // no timeout +) + +type Executor struct { + namespace string + cmdTimeout time.Duration +} + +func NewExecutor() *Executor { + return &Executor{ + namespace: "", + cmdTimeout: cmdTimeoutDefault, + } +} + +func NewExecutorWithNS(ns string) (*Executor, error) { + exec := NewExecutor() + exec.namespace = ns + + // test if nsenter is available + if _, err := execute(NSBinary, []string{"-V"}, cmdTimeoutNone); err != nil { + return nil, errors.Wrap(err, "cannot find nsenter for namespace switching") + } + return exec, nil +} + +func (exec *Executor) SetTimeout(timeout time.Duration) { + exec.cmdTimeout = timeout +} + +func (exec *Executor) Execute(cmd string, args []string) (string, error) { + command := cmd + cmdArgs := args + if exec.namespace != "" { + cmdArgs = []string{ + "--mount=" + filepath.Join(exec.namespace, "mnt"), + "--net=" + filepath.Join(exec.namespace, "net"), + "--ipc=" + filepath.Join(exec.namespace, "ipc"), + cmd, + } + command = NSBinary + cmdArgs = append(cmdArgs, args...) + } + return execute(command, cmdArgs, exec.cmdTimeout) +} + +func execute(command string, args []string, timeout time.Duration) (string, error) { + cmd := exec.Command(command, args...) + + var output, stderr bytes.Buffer + cmd.Stdout = &output + cmd.Stderr = &stderr + + timer := time.NewTimer(cmdTimeoutNone) + if timeout != cmdTimeoutNone { + // add timer to kill the process if timeout + timer = time.AfterFunc(timeout, func() { + cmd.Process.Kill() + }) + } + defer timer.Stop() + + if err := cmd.Run(); err != nil { + return "", errors.Wrapf(err, "failed to execute: %v %v, output %s, stderr %s", + command, args, output.String(), stderr.String()) + } + + return output.String(), nil +} diff --git a/pkg/utils/process.go b/pkg/utils/process.go new file mode 100644 index 00000000..d5d22b7a --- /dev/null +++ b/pkg/utils/process.go @@ -0,0 +1,73 @@ +package utils + +import ( + "fmt" + + "github.com/prometheus/procfs" +) + +const ( + DockerdProcess = "dockerd" + ContainerdProcess = "containerd" + ContainerdProcessShim = "containerd-shim" +) + +func getPidProc(hostProcPath string, pid int) (*procfs.Proc, error) { + fs, err := procfs.NewFS(hostProcPath) + if err != nil { + return nil, err + } + proc, err := fs.Proc(pid) + if err != nil { + return nil, err + } + return &proc, nil +} + +func getSelfProc(hostProcPath string) (*procfs.Proc, error) { + fs, err := procfs.NewFS(hostProcPath) + if err != nil { + return nil, err + } + proc, err := fs.Self() + if err != nil { + return nil, err + } + return &proc, nil +} + +func findAncestorByName(hostProcPath string, ancestorProcess string) (*procfs.Proc, error) { + proc, err := getSelfProc(hostProcPath) + if err != nil { + return nil, err + } + + for { + st, err := proc.Stat() + if err != nil { + return nil, err + } + if st.Comm == ancestorProcess { + return proc, nil + } + if st.PPID == 0 { + break + } + proc, err = getPidProc(hostProcPath, st.PPID) + if err != nil { + return nil, err + } + } + return nil, fmt.Errorf("failed to find the ancestor process: %s", ancestorProcess) +} + +func GetHostNamespacePath(hostProcPath string) string { + containerNames := []string{DockerdProcess, ContainerdProcess, ContainerdProcessShim} + for _, name := range containerNames { + proc, err := findAncestorByName(hostProcPath, name) + if err == nil { + return fmt.Sprintf("%s/%d/ns/", hostProcPath, proc.PID) + } + } + return fmt.Sprintf("%s/%d/ns/", hostProcPath, 1) +} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 7cd196d0..64c8b7ad 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -8,7 +8,6 @@ import ( "sync" "syscall" - iscsiutil "github.com/longhorn/go-iscsi-helper/util" "github.com/longhorn/longhorn-manager/util" ) @@ -134,8 +133,8 @@ func mountExt4(device, path string, readonly bool) error { // mountExt4OnHostNamespace provides the same functionality as mountExt4 but on host namespace. func mountExt4OnHostNamespace(device, path string, readonly bool) error { - ns := iscsiutil.GetHostNamespacePath(util.HostProcPath) - executor, err := iscsiutil.NewNamespaceExecutor(ns) + ns := GetHostNamespacePath(util.HostProcPath) + executor, err := NewExecutorWithNS(ns) if err != nil { return err } @@ -150,8 +149,8 @@ func mountExt4OnHostNamespace(device, path string, readonly bool) error { } func executeOnHostNamespace(cmd string, args []string) (string, error) { - ns := iscsiutil.GetHostNamespacePath(util.HostProcPath) - executor, err := iscsiutil.NewNamespaceExecutor(ns) + ns := GetHostNamespacePath(util.HostProcPath) + executor, err := NewExecutorWithNS(ns) if err != nil { return "", err } From cc4b92e46bec2ca1836cb60f6e19edd5a8bf2d6c Mon Sep 17 00:00:00 2001 From: Vicente Cheng Date: Mon, 29 Jan 2024 00:26:39 +0800 Subject: [PATCH 2/3] vendor: remove unused packages on go.mod Signed-off-by: Vicente Cheng --- go.mod | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3062a146..6144fa35 100644 --- a/go.mod +++ b/go.mod @@ -36,10 +36,11 @@ require ( github.com/harvester/go-common v0.0.0-20231214093547-3e3f7fdd879a github.com/jaypipes/ghw v0.8.1-0.20210701154532-dd036bd38c40 github.com/kevinburke/ssh_config v1.2.0 - github.com/longhorn/go-iscsi-helper v0.0.0-20231113050545-9df1e6b605c7 github.com/longhorn/longhorn-manager v1.5.3 github.com/melbahja/goph v1.3.0 github.com/pilebones/go-udev v0.0.0-20210126000448-a3c2a7a4afb7 + github.com/pkg/errors v0.9.1 + github.com/prometheus/procfs v0.9.0 github.com/rancher/lasso v0.0.0-20221227210133-6ea88ca2fbcc github.com/rancher/wrangler v1.1.1 github.com/sirupsen/logrus v1.9.3 @@ -84,18 +85,17 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kr/fs v0.1.0 // indirect + github.com/longhorn/go-iscsi-helper v0.0.0-20231113050545-9df1e6b605c7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pkg/sftp v1.13.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.15.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.9.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/mod v0.14.0 // indirect From 43174e618d196de62212157d320eb1519ea69f1d Mon Sep 17 00:00:00 2001 From: Vicente Cheng Date: Tue, 30 Jan 2024 16:55:33 +0800 Subject: [PATCH 3/3] ci: make sure the upgrade could be tested Signed-off-by: Vicente Cheng --- ci/scripts/upgrade_ndm.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/scripts/upgrade_ndm.sh b/ci/scripts/upgrade_ndm.sh index 84f330e2..cf918c6b 100755 --- a/ci/scripts/upgrade_ndm.sh +++ b/ci/scripts/upgrade_ndm.sh @@ -58,7 +58,7 @@ target_img=$(yq -e .image.repository ndm-override.yaml) echo "upgrade target image: ${target_img}, upgrading ..." $HELM upgrade -f $TOP_DIR/ndm-override.yaml harvester-node-disk-manager harvester-node-disk-manager/ -n harvester-system -sleep 10 # wait 10 seconds for ndm start to respwan pods +sleep 30 # wait 30 seconds for ndm respwan pods wait_ndm_ready # check image