From 2f70770e0e61c1b8f2a09d6a994d21fb44a70455 Mon Sep 17 00:00:00 2001 From: Ahmet OZER Date: Sat, 29 Jun 2024 02:30:55 +0000 Subject: [PATCH] feat: multi delete and namespace array --- pkg/cmd/clear.go | 8 ++++++-- pkg/cmd/daemon.go | 4 ++-- pkg/cmd/ps.go | 3 ++- pkg/cmd/rm.go | 35 ++++++++++++++++++++++------------- pkg/cmd/run.go | 15 +++++++++------ pkg/config/info.go | 24 +++++++++++------------- pkg/container/exec.go | 6 ++++-- pkg/container/mount.go | 4 ++-- pkg/container/start.go | 28 ++++++++++++---------------- pkg/net/create.go | 2 +- 10 files changed, 71 insertions(+), 58 deletions(-) diff --git a/pkg/cmd/clear.go b/pkg/cmd/clear.go index b4cce66..5692b3a 100644 --- a/pkg/cmd/clear.go +++ b/pkg/cmd/clear.go @@ -1,6 +1,8 @@ package cmd import ( + "log" + "github.com/ahmetozer/sandal/pkg/config" "github.com/ahmetozer/sandal/pkg/container" ) @@ -11,9 +13,11 @@ func clear(args []string) error { if !c.Remove { continue } - if !container.IsRunning(&c) { - deRunContainer(&c) + if container.IsRunning(&c) { + log.Printf("container %s is running, %v", c.Name, c.Remove) + continue } + deRunContainer(&c) } return nil } diff --git a/pkg/cmd/daemon.go b/pkg/cmd/daemon.go index 1a54601..7f5df78 100644 --- a/pkg/cmd/daemon.go +++ b/pkg/cmd/daemon.go @@ -168,9 +168,9 @@ case "$1" in restart) log_daemon_msg "Restarting Sandal" "sandal" || true - start-stop-daemon --stop --background -m --quiet --oknodo --retry 30 --pidfile /run/sandal.pid --exec /bin/sandal + start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile /run/sandal.pid --exec /bin/sandal # shellcheck disable=SC2086 - if start-stop-daemon --start --quiet --oknodo --chuid 0:0 --pidfile /run/sandal.pid --exec /bin/sandal -- $SANDAL_OPTS; then + if start-stop-daemon --start --background -m --quiet --oknodo --chuid 0:0 --pidfile /run/sandal.pid --exec /bin/sandal -- $SANDAL_OPTS; then log_end_msg 0 || true else log_end_msg 1 || true diff --git a/pkg/cmd/ps.go b/pkg/cmd/ps.go index b7da712..1a2c785 100644 --- a/pkg/cmd/ps.go +++ b/pkg/cmd/ps.go @@ -66,5 +66,6 @@ func printDry(c *config.Config, t *tabwriter.Writer) { } func printNamespaces(c *config.Config, t *tabwriter.Writer) { - fmt.Fprintf(t, "%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", c.Name, c.ContPid, c.NS.Cgroup, c.NS.Ipc, c.NS.Mnt, c.NS.Net, c.NS.Pid, c.NS.User, c.NS.Uts) + + fmt.Fprintf(t, "%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", c.Name, c.ContPid, c.NS["cgroup"].Value, c.NS["ipc"].Value, c.NS["mnt"].Value, c.NS["net"].Value, c.NS["pid"].Value, c.NS["user"].Value, c.NS["uts"].Value) } diff --git a/pkg/cmd/rm.go b/pkg/cmd/rm.go index 09c3039..986a1d9 100644 --- a/pkg/cmd/rm.go +++ b/pkg/cmd/rm.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "flag" "fmt" @@ -22,20 +23,28 @@ func rm(args []string) error { flags.Parse(thisFlags) conts, _ := config.AllContainers() - for _, c := range conts { - if c.Name == args[0] { - err := container.CheckExistence(&c) - if err != nil { - return fmt.Errorf("unable to check existence of '%s' container: %v", c.Name, err) - } - if c.Status == container.ContainerStatusRunning { - return fmt.Errorf("container %s is running, please stop it first", c.Name) - } - - c.Remove = true - deRunContainer(&c) + var errs []error +RequestedContainers: + for _, name := range args { + for _, c := range conts { + if c.Name == name { + err := container.CheckExistence(&c) + if err != nil { + errs = append(errs, fmt.Errorf("unable to check existence of '%s' container: %v", c.Name, err)) + } + if c.Status == container.ContainerStatusRunning { + errs = append(errs, fmt.Errorf("container %s is running, please stop it first", c.Name)) + } + c.Remove = true + deRunContainer(&c) + continue RequestedContainers + } } + errs = append(errs, fmt.Errorf("container %s is not found", name)) + } + if len(errs) > 0 { + return errors.Join(errs...) } - return fmt.Errorf("container %s is not found", args[0]) + return nil } diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go index f8dc405..f2955ba 100644 --- a/pkg/cmd/run.go +++ b/pkg/cmd/run.go @@ -54,10 +54,13 @@ func run(args []string) error { f.StringVar(&c.Resolv, "resolv", "cp", "cp (copy), cp-n (copy if not exist), image (use image), 1.1.1.1;2606:4700:4700::1111 (provide nameservers)") f.StringVar(&c.Hosts, "hosts", "cp", "cp (copy), cp-n (copy if not exist), image(use image)") - f.StringVar(&c.NS.Net, "ns-net", "", "net namespace or host") - f.StringVar(&c.NS.Pid, "ns-pid", "", "pid namespace or host") - f.StringVar(&c.NS.Uts, "ns-uts", "", "uts namespace or host") - f.StringVar(&c.NS.User, "ns-user", "host", "user namespace or host") + for _, k := range config.Namespaces { + defaultValue := "" + if k == "user" { + defaultValue = "host" + } + f.StringVar(&c.NS[k].Value, "ns-"+k, defaultValue, fmt.Sprintf("%s namespace or host", k)) + } f.StringVar(&c.ChangeDir, "chd", "", "changes save location default /var/lib/sandal/containers//changes") @@ -115,7 +118,7 @@ func run(args []string) error { func Start(c *config.Config, HostIface, PodIface config.NetIface) error { // Starting container var err error - if c.NS.Net != "host" { + if c.NS["net"].Value != "host" { if HostIface.Type == "bridge" { err = net.CreateIface(c, &HostIface) @@ -159,7 +162,7 @@ func deRunContainer(c *config.Config) { slog.Debug("umount", slog.String("err", e.Error())) } } - if c.NS.Net != "host" { + if c.NS["net"].Value != "host" { net.Clear(c) } diff --git a/pkg/config/info.go b/pkg/config/info.go index 22e5049..fd0e01a 100644 --- a/pkg/config/info.go +++ b/pkg/config/info.go @@ -8,18 +8,6 @@ import ( "time" ) -type NS struct { - Net string - Pid string - Uts string - User string - Ipc string - Cgroup string - NS string - Mnt string - Time string -} - type ALocFor uint8 const ( @@ -50,6 +38,10 @@ func (f *StringFlags) Set(value string) error { return nil } +type StringWrapper struct { + Value string +} + type Config struct { Name string @@ -66,7 +58,7 @@ type Config struct { EnvAll bool Background bool Startup bool - NS NS + NS map[string]*StringWrapper ChangeDir string Exec string Devtmpfs string @@ -89,11 +81,17 @@ var ( TypeUint uint ) +var Namespaces []string = []string{"pid", "net", "user", "uts", "ipc", "cgroup", "mnt", "time", "ns"} + func NewContainer() Config { Config := Config{} Config.HostPid = os.Getpid() Config.Created = time.Now().UTC().Unix() Config.Ifaces = []NetIface{{ALocFor: ALocForHost}} + Config.NS = make(map[string]*StringWrapper, len(Namespaces)) + for _, ns := range Namespaces { + Config.NS[ns] = &StringWrapper{Value: ""} + } return Config } diff --git a/pkg/container/exec.go b/pkg/container/exec.go index fd14025..1543aa4 100644 --- a/pkg/container/exec.go +++ b/pkg/container/exec.go @@ -26,7 +26,9 @@ func Exec() { log.Fatalf("unable to set hostname %s", err) } - configureIfaces(&c) + if c.NS["net"].Value != "host" { + configureIfaces(&c) + } childSysMounts(&c) childSysNodes(&c) @@ -43,7 +45,7 @@ func Exec() { func loadConfig() (config.Config, error) { - config := config.Config{} + config := config.NewContainer() confFileLoc := os.Getenv(CHILD_CONFIG_ENV_NAME) if confFileLoc == "" { return config, fmt.Errorf("config file location not present in env") diff --git a/pkg/container/mount.go b/pkg/container/mount.go index 579d38c..99f2520 100644 --- a/pkg/container/mount.go +++ b/pkg/container/mount.go @@ -42,8 +42,6 @@ func childSysMounts(c *config.Config) { mount("proc", "/proc", "proc", unix.MS_NOSUID|unix.MS_NODEV|unix.MS_NOEXEC|unix.MS_RELATIME, "") - mount("cgroup", "/sys/fs/cgroup", "cgroup2", unix.MS_NOSUID|unix.MS_NODEV|unix.MS_NOEXEC|unix.MS_RELATIME, "nsdelegate,memory_recursiveprot") - if c.Devtmpfs != "/dev" { mount("tmpfs", "/dev", "tmpfs", unix.MS_RELATIME, "size=65536k,mode=755") } @@ -53,6 +51,8 @@ func childSysMounts(c *config.Config) { mount("sysfs", "/sys", "sysfs", unix.MS_NODEV|unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_RELATIME, "ro") + mount("cgroup2", "/sys/fs/cgroup", "cgroup2", unix.MS_NOSUID|unix.MS_NODEV|unix.MS_NOEXEC|unix.MS_RELATIME, "nsdelegate,memory_recursiveprot") + mount("devpts", "/dev/pts", "devpts", unix.MS_NOSUID|unix.MS_NOEXEC|unix.MS_RELATIME, "gid=5,mode=620,ptmxmode=666") mount("shm", "/dev/shm", "tmpfs", unix.MS_NOSUID|unix.MS_NODEV|unix.MS_NOEXEC|unix.MS_RELATIME, "size=64000k") diff --git a/pkg/container/start.go b/pkg/container/start.go index 23a4776..ab586e1 100644 --- a/pkg/container/start.go +++ b/pkg/container/start.go @@ -48,16 +48,16 @@ func Start(c *config.Config, args []string) (int, error) { var cmdFlags uintptr = syscall.CLONE_NEWNS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWCGROUP - if c.NS.Pid != "host" { + if c.NS["pid"].Value != "host" { cmdFlags |= syscall.CLONE_NEWPID } - if c.NS.Net != "host" { + if c.NS["net"].Value != "host" { cmdFlags |= syscall.CLONE_NEWNET } - if c.NS.User != "host" { + if c.NS["user"].Value != "host" { cmdFlags |= syscall.CLONE_NEWUSER } - if c.NS.Uts != "host" { + if c.NS["uts"].Value != "host" { cmdFlags |= syscall.CLONE_NEWUTS } @@ -65,7 +65,7 @@ func Start(c *config.Config, args []string) (int, error) { Cloneflags: cmdFlags, } - if c.NS.User != "host" && c.NS.Pid != "host" { + if c.NS["user"].Value != "host" && c.NS["pid"].Value != "host" { cmd.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: cmdFlags, UidMappings: []syscall.SysProcIDMap{ @@ -80,6 +80,7 @@ func Start(c *config.Config, args []string) (int, error) { c.SaveConftoDisk() err := cmd.Start() + if err != nil { return 0, fmt.Errorf("starting container: %v", err) } @@ -146,16 +147,12 @@ func childArgs(args []string) (string, []string) { } func loadNamespaceIDs(c *config.Config) { - - c.NS.Pid = readNamespace(fmt.Sprintf("/proc/%d/ns/pid", c.ContPid)) - c.NS.Net = readNamespace(fmt.Sprintf("/proc/%d/ns/net", c.ContPid)) - c.NS.User = readNamespace(fmt.Sprintf("/proc/%d/ns/user", c.ContPid)) - c.NS.Uts = readNamespace(fmt.Sprintf("/proc/%d/ns/uts", c.ContPid)) - c.NS.Ipc = readNamespace(fmt.Sprintf("/proc/%d/ns/ipc", c.ContPid)) - c.NS.Cgroup = readNamespace(fmt.Sprintf("/proc/%d/ns/cgroup", c.ContPid)) - c.NS.Mnt = readNamespace(fmt.Sprintf("/proc/%d/ns/mnt", c.ContPid)) - c.NS.Time = readNamespace(fmt.Sprintf("/proc/%d/ns/time", c.ContPid)) - c.NS.NS = readNamespace(fmt.Sprintf("/proc/%d/ns/ns", c.ContPid)) + for _, ns := range config.Namespaces { + if c.NS[ns].Value == "host" { + continue + } + c.NS[ns].Value = readNamespace(fmt.Sprintf("/proc/%d/ns/%s", c.ContPid, ns)) + } } func readNamespace(f string) string { @@ -181,7 +178,6 @@ func parseNamspaceInfo(s string) string { func AttachContainerToPID(c *config.Config, masterPid int) error { if err := syscall.Setpgid(c.ContPid, masterPid); err != nil { return fmt.Errorf("error setting %d process group id: %s", c.ContPid, err) - } if pgid, err := syscall.Getpgid(c.ContPid); err != nil || pgid != masterPid { diff --git a/pkg/net/create.go b/pkg/net/create.go index e237e0e..50de34b 100644 --- a/pkg/net/create.go +++ b/pkg/net/create.go @@ -10,7 +10,7 @@ import ( func CreateIface(c *config.Config, iface *config.NetIface) error { ifaceLink := netlink.Link(nil) err := error(nil) - if c.NS.Net == "host" { + if c.NS["net"].Value == "host" { return nil }