mirror of
https://github.com/SynologyOpenSource/synology-csi.git
synced 2026-08-19 11:36:33 +00:00
The tool executor is capable of running given tools in chroot either by automatically locating the tools in path using the `env` command or directly if the path is known. This removes the need for the shell script to wrap commands and reduces number of needed external binaries on the node.
100 lines
2.4 KiB
Go
100 lines
2.4 KiB
Go
// Package hostexec automatically wraps commands executed with kubernetes hostexec into
|
|
// chrooted commands
|
|
package hostexec
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"k8s.io/utils/exec"
|
|
)
|
|
|
|
// defaultSearchPath for running commands without absolute paths
|
|
var defaultSearchPath = []string{
|
|
"/usr/local/sbin",
|
|
"/usr/local/bin",
|
|
"/usr/sbin",
|
|
"/usr/bin",
|
|
"/sbin",
|
|
"/bin",
|
|
}
|
|
|
|
// Executor is mostly k8s.io/utils/exec compatible interface for the portions
|
|
// that synology-csi uses.
|
|
type Executor interface {
|
|
Command(string, ...string) exec.Cmd
|
|
CommandContext(context.Context, string, ...string) exec.Cmd
|
|
}
|
|
|
|
type hostexec struct {
|
|
Executor
|
|
commandMap map[string]string
|
|
chrootDir string
|
|
}
|
|
|
|
// New creates an instance of hostexec to execute commands in the given environment
|
|
func New(cmdMap map[string]string, chrootDir string) (Executor, error) {
|
|
// If chroot directory is defined, check that directory exists or return an error
|
|
if chrootDir != "" {
|
|
fileinfo, err := os.Stat(chrootDir)
|
|
if err != nil || !fileinfo.IsDir() {
|
|
return nil, errors.New("chroot directory does not exist or is not a directory")
|
|
}
|
|
}
|
|
|
|
return &hostexec{exec.New(), cmdMap, chrootDir}, nil
|
|
}
|
|
|
|
func (h *hostexec) resolveCmd(cmd string, args ...string) (string, []string) {
|
|
c, ok := h.commandMap[cmd]
|
|
if !ok || c == "" {
|
|
return cmd, args
|
|
}
|
|
|
|
return c, args
|
|
}
|
|
|
|
func (h *hostexec) wrapEnv(cmd string, args ...string) (string, []string) {
|
|
if strings.ContainsAny(cmd, "/") {
|
|
return cmd, args
|
|
}
|
|
|
|
sp := fmt.Sprintf("PATH=%s", strings.Join(defaultSearchPath, ":"))
|
|
args = append([]string{"-i", sp, cmd}, args...)
|
|
cmd = "/usr/bin/env"
|
|
|
|
return cmd, args
|
|
}
|
|
|
|
func (h *hostexec) wrapChroot(cmd string, args ...string) (string, []string) {
|
|
if h.chrootDir == "" {
|
|
return cmd, args
|
|
}
|
|
|
|
args = append([]string{h.chrootDir, cmd}, args...)
|
|
cmd = "/usr/sbin/chroot"
|
|
|
|
return cmd, args
|
|
}
|
|
|
|
func (h *hostexec) wrap(cmd string, args ...string) (string, []string) {
|
|
cmd, args = h.resolveCmd(cmd, args...)
|
|
cmd, args = h.wrapEnv(cmd, args...)
|
|
cmd, args = h.wrapChroot(cmd, args...)
|
|
|
|
return cmd, args
|
|
}
|
|
|
|
func (h *hostexec) Command(cmd string, args ...string) exec.Cmd {
|
|
cmd, args = h.wrap(cmd, args...)
|
|
return h.Executor.Command(cmd, args...)
|
|
}
|
|
|
|
func (h *hostexec) CommandContext(ctx context.Context, cmd string, args ...string) exec.Cmd {
|
|
cmd, args = h.wrap(cmd, args...)
|
|
return h.Executor.CommandContext(ctx, cmd, args...)
|
|
}
|