Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 14 additions & 34 deletions pkg/cmd/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ import (
"os"
"strings"

"github.com/ahmetozer/sandal/pkg/container/config"
"github.com/ahmetozer/sandal/pkg/container/config/wrapper"
"github.com/ahmetozer/sandal/pkg/container/cruntime"
"github.com/ahmetozer/sandal/pkg/container/cruntime/namespace"
"github.com/ahmetozer/sandal/pkg/controller"
"golang.org/x/sys/unix"
)

func ExecOnContainer(args []string) error {

thisFlags, childArgs, splitFlagErr := SplitFlagsArgs(args)

f := flag.NewFlagSet("exec", flag.ExitOnError)

var (
help bool
EnvAll bool
PassEnv config.StringFlags
PassEnv wrapper.StringFlags
Dir string
contName string
)
Expand All @@ -31,9 +31,14 @@ func ExecOnContainer(args []string) error {
f.StringVar(&Dir, "dir", "", "working directory")
f.Var(&PassEnv, "env-pass", "pass only requested enviroment variables to container")

// Allocate variable locations
NS := namespace.ParseFlagSet(f)

if err := f.Parse(thisFlags); err != nil {
return fmt.Errorf("error parsing flags: %v", err)
}
// Execute after parsing flag to prevent nil pointer issues or empty variable
NS.Defaults()

if help {
f.Usage()
Expand All @@ -59,40 +64,15 @@ func ExecOnContainer(args []string) error {
return fmt.Errorf("failed to get container %s: %v", contName, err)
}

var NsConfs []cruntime.NsConf

Cloneflags := unix.CLONE_NEWIPC | unix.CLONE_NEWNS | unix.CLONE_NEWCGROUP
merge := c.NS.SetEmptyToPid(c.ContPid).Merge(NS)

if c.NS["pid"].Value != "host" {
Cloneflags |= unix.CLONE_NEWPID
NsConfs = append(NsConfs, cruntime.NsConf{Nsname: "pid", CloneFlag: unix.CLONE_NEWPID})
}
if c.NS["net"].Value != "host" {
Cloneflags |= unix.CLONE_NEWNET
NsConfs = append(NsConfs, cruntime.NsConf{Nsname: "net", CloneFlag: unix.CLONE_NEWNET})
}
if c.NS["user"].Value != "host" {
Cloneflags |= unix.CLONE_NEWUSER
NsConfs = append(NsConfs, cruntime.NsConf{Nsname: "user", CloneFlag: unix.CLONE_NEWUSER})
if err := merge.Unshare(); err != nil {
return err
}
if c.NS["uts"].Value != "host" {
Cloneflags |= unix.CLONE_NEWUTS
NsConfs = append(NsConfs, cruntime.NsConf{Nsname: "uts", CloneFlag: unix.CLONE_NEWUTS})
}

NsConfs = append(NsConfs, cruntime.NsConf{Nsname: "pid", CloneFlag: unix.CLONE_NEWPID})
NsConfs = append(NsConfs, cruntime.NsConf{Nsname: "cgroup", CloneFlag: unix.CLONE_NEWCGROUP})
NsConfs = append(NsConfs, cruntime.NsConf{Nsname: "mnt", CloneFlag: unix.CLONE_NEWNS})

// Unshare the namespaces
if err := unix.Unshare(Cloneflags); err != nil {
return fmt.Errorf("unshare namespaces: %v", err)
}
// Set the namespaces
for _, nsConf := range NsConfs {
if err := cruntime.SetNs(nsConf.Nsname, c.ContPid, int(nsConf.CloneFlag)); err != nil {
return err
}
err = merge.SetNS()
if err != nil {
return err
}

// Set the hostname
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,5 @@ 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, cruntime.GetNamespaceValue(c, "cgroup"), cruntime.GetNamespaceValue(c, "ipc"), cruntime.GetNamespaceValue(c, "mnt"), cruntime.GetNamespaceValue(c, "net"), cruntime.GetNamespaceValue(c, "pid"), cruntime.GetNamespaceValue(c, "user"), cruntime.GetNamespaceValue(c, "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.Get("cgroup"), c.NS.Get("ipc"), c.NS.Get("mnt"), c.NS.Get("net"), c.NS.Get("pid"), c.NS.Get("user"), c.NS.Get("uts"))
}
12 changes: 4 additions & 8 deletions pkg/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
"strings"

"github.com/ahmetozer/sandal/pkg/container/config"
"github.com/ahmetozer/sandal/pkg/container/config/wrapper"
"github.com/ahmetozer/sandal/pkg/container/cruntime"
"github.com/ahmetozer/sandal/pkg/container/cruntime/namespace"
"github.com/ahmetozer/sandal/pkg/container/cruntime/net"
"github.com/ahmetozer/sandal/pkg/controller"
"github.com/ahmetozer/sandal/pkg/env"
Expand Down Expand Up @@ -49,21 +51,15 @@ func Run(args []string) error {
f.Var(&c.PassEnv, "env-pass", "pass only requested enviroment variables to container")
f.StringVar(&c.Dir, "dir", "", "working directory")

networkInterfacesCmd := config.StringFlags{}
networkInterfacesCmd := wrapper.StringFlags{}
f.Var(&networkInterfacesCmd, "net", "configure network interfaces")

f.UintVar(&c.TmpSize, "tmp", 0, "allocate changes at memory instead of disk. Unit is in MB, when set to 0 (default) which means it's disabled")

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)")

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))
}
c.NS = namespace.ParseFlagSet(f)

f.StringVar(&c.ChangeDir, "chdir", config.Defs(containerId).ChangeDir, "container changes will saved this directory")
f.StringVar(&c.RootfsDir, "rdir", config.Defs(containerId).RootFsDir, "root directory of operating system")
Expand Down
32 changes: 13 additions & 19 deletions pkg/container/config/definations.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import (
"path"
"time"

"github.com/ahmetozer/sandal/pkg/container/config/wrapper"
"github.com/ahmetozer/sandal/pkg/container/cruntime/diskimage"
"github.com/ahmetozer/sandal/pkg/container/cruntime/namespace"
"github.com/ahmetozer/sandal/pkg/env"
)

Expand All @@ -26,26 +28,25 @@ type Config struct {
ChangeDir string
RootfsDir string

ReadOnly bool
Remove bool
EnvAll bool
Background bool
Startup bool
NS map[string]*StringWrapper

ReadOnly bool
Remove bool
EnvAll bool
Background bool
Startup bool
NS namespace.Namespaces
Devtmpfs string
Resolv string
Hosts string
Status string
Dir string
Volumes StringFlags
Volumes wrapper.StringFlags
ImmutableImages diskimage.ImmutableImages
HostArgs []string
ContArgs []string
Lower StringFlags
RunPreExec StringFlags
RunPrePivot StringFlags
PassEnv StringFlags
Lower wrapper.StringFlags
RunPreExec wrapper.StringFlags
RunPrePivot wrapper.StringFlags
PassEnv wrapper.StringFlags
Net any
}

Expand All @@ -55,17 +56,10 @@ 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
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package config
package wrapper

import (
"encoding/json"
Expand All @@ -20,6 +20,5 @@ func (f *StringFlags) Set(value string) error {
}

type StringWrapper struct {
Value string
Custom map[string]interface{}
Value string // set by Cli
}
20 changes: 20 additions & 0 deletions pkg/container/cruntime/arch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cruntime

import "encoding/binary"

const (
bits = 32 << (^uint(0) >> 63)
)

var (
procSize = 65535
)

func init() {
// arange bits based on cpu architecture
if bits == 64 {
bin := binary.BigEndian.AppendUint64([]byte{255, 255, 255, 255}, 0)
procSize = int(binary.BigEndian.Uint32(bin))
}

}
74 changes: 13 additions & 61 deletions pkg/container/cruntime/crun.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cruntime

import (
"encoding/binary"
"fmt"
"log/slog"
"os"
Expand All @@ -16,23 +15,6 @@ import (
"github.com/ahmetozer/sandal/pkg/env"
)

const (
bits = 32 << (^uint(0) >> 63)
)

var (
procSize = 65535
)

func init() {
// fix for cpu architecture
if bits == 64 {
bin := binary.BigEndian.AppendUint64([]byte{255, 255, 255, 255}, 0)
procSize = int(binary.BigEndian.Uint32(bin))
}

}

type containerLog struct {
name string
logType string
Expand Down Expand Up @@ -76,49 +58,18 @@ func crun(c *config.Config) (int, error) {
cmd.Env = childEnv(c)
cmd.Dir = c.RootfsDir

var Ns Namespaces

err = Ns.allocateNs(c, "mnt")
if err != nil {
return 1, err
}

err = Ns.allocateNs(c, "ipc")
if err != nil {
return 1, err
}
err = Ns.allocateNs(c, "time")
if err != nil {
return 1, err
}
err = Ns.allocateNs(c, "cgroup")
if err != nil {
return 1, err
}
err = Ns.allocateNs(c, "pid")
if err != nil {
return 1, err
}
err = Ns.allocateNs(c, "net")
if err != nil {
return 1, err
}
err = Ns.allocateNs(c, "user")
if err != nil {
return 1, err
}
err = Ns.allocateNs(c, "uts")
err = c.NS.Defaults()
if err != nil {
return 1, err
}

cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: Ns.Cloneflags,
Cloneflags: c.NS.Cloneflags(),
}

if c.NS["user"].Value != "host" && c.NS["user"].Value != "" && c.NS["pid"].Value != "host" {
if c.NS.Get("user").IsUserDefined && !c.NS.Get("pid").IsHost {
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: Ns.Cloneflags,
Cloneflags: c.NS.Cloneflags(),
UidMappings: []syscall.SysProcIDMap{
{ContainerID: 0, HostID: 0, Size: procSize},
},
Expand All @@ -130,12 +81,13 @@ func crun(c *config.Config) (int, error) {
}
}

// Set the namespaces
for _, nsConf := range Ns.NsConfs {
if err := SetNs(nsConf.Nsname, nsConf.Pid, int(nsConf.CloneFlag)); err != nil {
return 1, err
}
}
// !Switching custom namespace while container create not supported.
// ?The reason is it will impacted daemon due to proccess based impact
// // Switch custom namespaces before starting new command
// err = c.NS.SetNS()
// if err != nil {
// return 1, err
// }

go cmd.Run()

Expand All @@ -150,11 +102,11 @@ func crun(c *config.Config) (int, error) {

c.ContPid = cmd.Process.Pid

loadNamespaceIDs(c)
// c.NS.LoadNamespaceIDs(c.ContPid)

c.Status = ContainerStatusRunning

if c.NS["net"].Value != "host" {
if !c.NS.Get("net").IsHost {
links, err := net.ToLinks(&c.Net)
if err != nil {
return 1, err
Expand Down
2 changes: 1 addition & 1 deletion pkg/container/cruntime/derun.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func DeRunContainer(c *config.Config) {

Kill(c, 9, 5)

if c.NS["net"].Value != "host" {
if !c.NS.Get("net").IsHost {
ifaces, err := net.ToLinks(&(c.Net))

if err == nil {
Expand Down
6 changes: 3 additions & 3 deletions pkg/container/cruntime/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ func Exec(c []string, chroot string) (exitCode int, err error) {
cmd.Stderr = os.Stderr
cmd.Env = os.Environ()
cmd.SysProcAttr = &unix.SysProcAttr{
Cloneflags: unix.CLONE_NEWUTS,
// Cloneflags: unix.CLONE_NEWUTS,
}

if chroot != "" {
cmd.SysProcAttr = &unix.SysProcAttr{
Cloneflags: unix.CLONE_NEWUTS,
Chroot: chroot,
// Cloneflags: unix.CLONE_NEWUTS,
Chroot: chroot,
}
}

Expand Down
Loading
Loading