Skip to content

Commit

Permalink
Next round - a lot of clean-up and removed some hacks
Browse files Browse the repository at this point in the history
Signed-off-by: Doug Davis <[email protected]>
  • Loading branch information
Doug Davis committed Jan 22, 2016
1 parent 25b23ff commit d1fd70d
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 84 deletions.
27 changes: 2 additions & 25 deletions container.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,33 +34,10 @@ func createContainer(context *cli.Context, spec *specs.LinuxSpec, rspec *specs.L
return nil, err
}

//

process := newProcess(spec.Process)

/*
rootuid, err := container.Config().HostUID()
if err != nil {
return nil, err
}
tty, err := newTty(spec.Process.Terminal, process, rootuid, "")
if err != nil {
return nil, err
}
handler := newSignalHandler(tty)
defer handler.Close()
*/

if err := container.Create(process); err != nil {
if err := container.Create(newProcess(spec.Process)); err != nil {
return nil, err
}
/*
rc, err := handler.forward(process)
if rc != 0 || err != nil {
return nil, err
}
*/

return container, nil
}

Expand Down
97 changes: 65 additions & 32 deletions libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,19 +172,19 @@ func (c *linuxContainer) Set(config configs.Config) error {
}

// Create will initialize(create) a new container by
// creating the namespaces associated with it
// creating the namespaces associated with it.
func (c *linuxContainer) Create(process *Process) error {
// Our hacking trigger for init routine
process.Args = []string{"createC"}

c.m.Lock()
defer c.m.Unlock()
status, err := c.currentStatus()
if err != nil {
return err
}
doInit := status == Created
parent, err := c.newParentProcess(process, doInit)

/*
status, err := c.currentStatus()
if err != nil {
return err
}
*/

parent, err := c.newParentProcess(process, initCreate)
if err != nil {
return newSystemError(err)
}
Expand All @@ -195,19 +195,15 @@ func (c *linuxContainer) Create(process *Process) error {
}
return newSystemError(err)
}
if doInit {
if err := c.updateState(parent); err != nil {
return err
}
_, err := parent.wait()
if err != nil {
return err
}
} else {
panic("should not be here")
c.state.transition(&runningState{
c: c,
})

if err := c.updateState(parent); err != nil {
return err
}

// Wait for process to end
_, err = parent.wait()
if err != nil {
return err
}

return nil
Expand All @@ -220,14 +216,17 @@ func (c *linuxContainer) Start(process *Process) error {
if err != nil {
return err
}
// doInit := status == Destroyed

// doInit will be true if we're creating the main proc of the container.
// Otherwise we're just joining the namespaces of the existing proc.
doInit := status == Created

// fmt.Printf("state: %#v\n", c.state)
// fmt.Printf("status: %#v\n", status)
// fmt.Printf("status: %q\n", status)
// fmt.Printf("doInit: %v\n", doInit)
parent, err := c.newParentProcess(process, doInit)
it := initStandard
if !doInit {
it = initSetns
}

parent, err := c.newParentProcess(process, it)
if err != nil {
return newSystemError(err)
}
Expand Down Expand Up @@ -273,7 +272,7 @@ func (c *linuxContainer) Signal(s os.Signal) error {
return nil
}

func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProcess, error) {
func (c *linuxContainer) newParentProcess(p *Process, it initType) (parentProcess, error) {
parentPipe, childPipe, err := newPipe()
if err != nil {
return nil, newSystemError(err)
Expand All @@ -282,10 +281,15 @@ func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProces
if err != nil {
return nil, newSystemError(err)
}
if !doInit {
switch it {
case initCreate:
return c.newCreateProcess(p, cmd, parentPipe, childPipe)
case initSetns:
return c.newSetnsProcess(p, cmd, parentPipe, childPipe)
case initStandard:
return c.newInitProcess(p, cmd, parentPipe, childPipe)
}
return c.newInitProcess(p, cmd, parentPipe, childPipe)
panic(fmt.Sprintf("should not get here - it: %v", it))
}

func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec.Cmd, error) {
Expand All @@ -311,6 +315,35 @@ func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec.
return cmd, nil
}

// newCreateProcess is the same as newInitProcess except the INITTYPE value
// will differ.
func (c *linuxContainer) newCreateProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) (*initProcess, error) {
t := "_LIBCONTAINER_INITTYPE=" + string(initCreate)
cloneFlags := c.config.Namespaces.CloneFlags()
if cloneFlags&syscall.CLONE_NEWUSER != 0 {
if err := c.addUidGidMappings(cmd.SysProcAttr); err != nil {
// user mappings are not supported
return nil, err
}
enableSetgroups(cmd.SysProcAttr)
// Default to root user when user namespaces are enabled.
if cmd.SysProcAttr.Credential == nil {
cmd.SysProcAttr.Credential = &syscall.Credential{}
}
}
cmd.Env = append(cmd.Env, t)
cmd.SysProcAttr.Cloneflags = cloneFlags
return &initProcess{
cmd: cmd,
childPipe: childPipe,
parentPipe: parentPipe,
manager: c.cgroupManager,
config: c.newInitConfig(p),
container: c,
process: p,
}, nil
}

func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) (*initProcess, error) {
t := "_LIBCONTAINER_INITTYPE=" + string(initStandard)
cloneFlags := c.config.Namespaces.CloneFlags()
Expand Down
122 changes: 122 additions & 0 deletions libcontainer/create_init_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// +build linux

package libcontainer

import (
"io"
"os"
"syscall"

"github.com/opencontainers/runc/libcontainer/apparmor"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/label"
"github.com/opencontainers/runc/libcontainer/seccomp"
"github.com/opencontainers/runc/libcontainer/system"
)

type linuxCreateInit struct {
pipe io.ReadWriter
parentPid int
config *initConfig
}

func (l *linuxCreateInit) Init() error {
// join any namespaces via a path to the namespace fd if provided
if err := joinExistingNamespaces(l.config.Config.Namespaces); err != nil {
return err
}
var console *linuxConsole
if l.config.Console != "" {
console = newConsoleFromPath(l.config.Console)
if err := console.dupStdio(); err != nil {
return err
}
}
if _, err := syscall.Setsid(); err != nil {
return err
}
if console != nil {
if err := system.Setctty(); err != nil {
return err
}
}
if err := setupNetwork(l.config); err != nil {
return err
}
if err := setupRoute(l.config.Config); err != nil {
return err
}
if err := setupRlimits(l.config.Config); err != nil {
return err
}
if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil {
return err
}
label.Init()
// InitializeMountNamespace() can be executed only for a new mount namespace
if l.config.Config.Namespaces.Contains(configs.NEWNS) {
if err := setupRootfs(l.config.Config, console); err != nil {
return err
}
}
if hostname := l.config.Config.Hostname; hostname != "" {
if err := syscall.Sethostname([]byte(hostname)); err != nil {
return err
}
}
if err := apparmor.ApplyProfile(l.config.Config.AppArmorProfile); err != nil {
return err
}
if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil {
return err
}

for key, value := range l.config.Config.Sysctl {
if err := writeSystemProperty(key, value); err != nil {
return err
}
}
for _, path := range l.config.Config.ReadonlyPaths {
if err := remountReadonly(path); err != nil {
return err
}
}
for _, path := range l.config.Config.MaskPaths {
if err := maskFile(path); err != nil {
return err
}
}
pdeath, err := system.GetParentDeathSignal()
if err != nil {
return err
}

// Tell our parent that we're ready to Execv. This must be done before the
// Seccomp rules have been applied, because we need to be able to read and
// write to a socket.
if err := syncParentReady(l.pipe); err != nil {
return err
}
if l.config.Config.Seccomp != nil {
if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil {
return err
}
}
if err := finalizeNamespace(l.config); err != nil {
return err
}
// finalizeNamespace can change user/group which clears the parent death
// signal, so we restore it here.
if err := pdeath.Restore(); err != nil {
return err
}
// compare the parent from the inital start of the init process and make sure that it did not change.
// if the parent changes that means it died and we were reparened to something else so we should
// just kill ourself and not cause problems for someone else.
if syscall.Getppid() != l.parentPid {
return syscall.Kill(syscall.Getpid(), syscall.SIGKILL)
}

os.Exit(0)
return nil
}
12 changes: 10 additions & 2 deletions libcontainer/init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ import (
"github.com/vishvananda/netlink"
)

// initType is the reason we're being called - the action should we take
type initType string

const (
initSetns initType = "setns"
initStandard initType = "standard"
initCreate initType = "create" // Just setting up the namespaces
initSetns initType = "setns" // Joining and existing container
initStandard initType = "standard" // Starting the main proces
)

type pid struct {
Expand Down Expand Up @@ -68,6 +70,12 @@ func newContainerInit(t initType, pipe *os.File) (initer, error) {
return nil, err
}
switch t {
case initCreate:
return &linuxCreateInit{
pipe: pipe,
parentPid: syscall.Getppid(),
config: config,
}, nil
case initSetns:
return &linuxSetnsInit{
config: config,
Expand Down
2 changes: 1 addition & 1 deletion libcontainer/nsenter/nsexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ void nsexec()

// if we dont have INITTYPE or this is the init process, skip the bootstrap process
val = getenv("_LIBCONTAINER_INITTYPE");
if (val == NULL || strcmp(val, "standard") == 0) {
if (val == NULL || strcmp(val, "standard") == 0 || strcmp(val, "create") == 0) {
return;
}
if (strcmp(val, "setns") != 0) {
Expand Down
Loading

0 comments on commit d1fd70d

Please sign in to comment.