Move environment configuration to Process
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
58023ad32f
commit
21bb5ccc4f
|
@ -55,11 +55,6 @@ type Config struct {
|
|||
// WorkingDir will change the processes current working directory inside the container's rootfs
|
||||
WorkingDir string `json:"working_dir,omitempty"`
|
||||
|
||||
// Env will populate the processes environment with the provided values
|
||||
// Any values from the parent processes will be cleared before the values
|
||||
// provided in Env are provided to the process
|
||||
Env []string `json:"environment,omitempty"`
|
||||
|
||||
// Console is the path to the console allocated to the container.
|
||||
Console string `json:"console,omitempty"`
|
||||
|
||||
|
|
|
@ -261,6 +261,7 @@ func TestEnter(t *testing.T) {
|
|||
|
||||
pconfig := libcontainer.Process{
|
||||
Args: []string{"sh", "-c", "cat && readlink /proc/self/ns/pid"},
|
||||
Env: standardEnvironment,
|
||||
Stdin: stdinR,
|
||||
Stdout: &stdout,
|
||||
}
|
||||
|
@ -361,6 +362,7 @@ func TestFreeze(t *testing.T) {
|
|||
|
||||
pconfig := libcontainer.Process{
|
||||
Args: []string{"cat"},
|
||||
Env: standardEnvironment,
|
||||
Stdin: stdinR,
|
||||
}
|
||||
pid, err := container.Start(&pconfig)
|
||||
|
|
|
@ -6,6 +6,13 @@ import (
|
|||
"github.com/docker/libcontainer/configs"
|
||||
)
|
||||
|
||||
var standardEnvironment = []string{
|
||||
"HOME=/root",
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"HOSTNAME=integration",
|
||||
"TERM=xterm",
|
||||
}
|
||||
|
||||
// newTemplateConfig returns a base template for running a container
|
||||
//
|
||||
// it uses a network strategy of just setting a loopback interface
|
||||
|
@ -43,14 +50,8 @@ func newTemplateConfig(rootfs string) *configs.Config {
|
|||
AllowedDevices: configs.DefaultAllowedDevices,
|
||||
},
|
||||
|
||||
Devices: configs.DefaultAutoCreatedDevices,
|
||||
Hostname: "integration",
|
||||
Env: []string{
|
||||
"HOME=/root",
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"HOSTNAME=integration",
|
||||
"TERM=xterm",
|
||||
},
|
||||
Devices: configs.DefaultAutoCreatedDevices,
|
||||
Hostname: "integration",
|
||||
Networks: []*configs.Network{
|
||||
{
|
||||
Type: "loopback",
|
||||
|
|
|
@ -93,6 +93,7 @@ func runContainer(config *configs.Config, console string, args ...string) (buffe
|
|||
|
||||
process := &libcontainer.Process{
|
||||
Args: args,
|
||||
Env: standardEnvironment,
|
||||
Stdin: buffers.Stdin,
|
||||
Stdout: buffers.Stdout,
|
||||
Stderr: buffers.Stderr,
|
||||
|
|
|
@ -18,10 +18,6 @@ import (
|
|||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const (
|
||||
EXIT_SIGNAL_OFFSET = 128
|
||||
)
|
||||
|
||||
type pid struct {
|
||||
Pid int `json:"Pid"`
|
||||
}
|
||||
|
@ -50,8 +46,7 @@ func (c *linuxContainer) Status() (configs.Status, error) {
|
|||
return configs.Destroyed, nil
|
||||
}
|
||||
// return Running if the init process is alive
|
||||
err := syscall.Kill(c.state.InitPid, 0)
|
||||
if err != nil {
|
||||
if err := syscall.Kill(c.state.InitPid, 0); err != nil {
|
||||
if err == syscall.ESRCH {
|
||||
return configs.Destroyed, nil
|
||||
}
|
||||
|
@ -96,10 +91,9 @@ func (c *linuxContainer) Start(process *Process) (int, error) {
|
|||
cmd := c.commandTemplate(process)
|
||||
if status != configs.Destroyed {
|
||||
// TODO: (crosbymichael) check out console use for execin
|
||||
return c.startNewProcess(cmd, process.Args)
|
||||
//return namespaces.ExecIn(process.Args, c.config.Env, "", cmd, c.config, c.state)
|
||||
return c.startNewProcess(cmd, process)
|
||||
}
|
||||
if err := c.startInitialProcess(cmd, process.Args); err != nil {
|
||||
if err := c.startInitialProcess(cmd, process); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return c.state.InitPid, nil
|
||||
|
@ -112,7 +106,7 @@ func (c *linuxContainer) commandTemplate(process *Process) *exec.Cmd {
|
|||
cmd.Stdin = process.Stdin
|
||||
cmd.Stdout = process.Stdout
|
||||
cmd.Stderr = process.Stderr
|
||||
cmd.Env = c.config.Env
|
||||
cmd.Env = process.Env
|
||||
cmd.Dir = c.config.Rootfs
|
||||
if cmd.SysProcAttr == nil {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
|
@ -122,9 +116,9 @@ func (c *linuxContainer) commandTemplate(process *Process) *exec.Cmd {
|
|||
}
|
||||
|
||||
// startNewProcess adds another process to an already running container
|
||||
func (c *linuxContainer) startNewProcess(cmd *exec.Cmd, args []string) (int, error) {
|
||||
func (c *linuxContainer) startNewProcess(cmd *exec.Cmd, process *Process) (int, error) {
|
||||
glog.Info("start new container process")
|
||||
parent, child, err := newInitPipe()
|
||||
parent, child, err := c.newInitPipe()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
@ -169,18 +163,20 @@ func (c *linuxContainer) startNewProcess(cmd *exec.Cmd, args []string) (int, err
|
|||
}
|
||||
if err := json.NewEncoder(parent).Encode(&initConfig{
|
||||
Config: c.config,
|
||||
Args: args,
|
||||
Args: process.Args,
|
||||
Env: process.Env,
|
||||
}); err != nil {
|
||||
return terminate(err)
|
||||
}
|
||||
return pid.Pid, nil
|
||||
}
|
||||
|
||||
func (c *linuxContainer) startInitialProcess(cmd *exec.Cmd, args []string) error {
|
||||
// startInitialProcess starts PID 1 for the container.
|
||||
func (c *linuxContainer) startInitialProcess(cmd *exec.Cmd, process *Process) error {
|
||||
glog.Info("starting container initial process")
|
||||
// create a pipe so that we can syncronize with the namespaced process and
|
||||
// pass the state and configuration to the child process
|
||||
parent, child, err := newInitPipe()
|
||||
parent, child, err := c.newInitPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -239,13 +235,14 @@ func (c *linuxContainer) startInitialProcess(cmd *exec.Cmd, args []string) error
|
|||
return terminate(err)
|
||||
}
|
||||
iconfig := &initConfig{
|
||||
Args: args,
|
||||
Args: process.Args,
|
||||
Config: c.config,
|
||||
Env: process.Env,
|
||||
NetworkState: &networkState,
|
||||
}
|
||||
// Start the setup process to setup the init process
|
||||
if c.config.Namespaces.Contains(configs.NEWUSER) {
|
||||
if err = executeSetupCmd(cmd.Args, cmd.Process.Pid, c.config, iconfig, &networkState); err != nil {
|
||||
if err = c.executeSetupCmd(cmd.Args, cmd.Process.Pid, c.config, iconfig, &networkState); err != nil {
|
||||
return terminate(err)
|
||||
}
|
||||
}
|
||||
|
@ -281,6 +278,7 @@ func (c *linuxContainer) Destroy() error {
|
|||
if status != configs.Destroyed {
|
||||
return newGenericError(nil, ContainerNotStopped)
|
||||
}
|
||||
// TODO: remove cgroups
|
||||
return os.RemoveAll(c.root)
|
||||
}
|
||||
|
||||
|
@ -297,6 +295,7 @@ func (c *linuxContainer) Signal(signal os.Signal) error {
|
|||
panic("not implemented")
|
||||
}
|
||||
|
||||
// TODO: rename to be more descriptive
|
||||
func (c *linuxContainer) OOM() (<-chan struct{}, error) {
|
||||
return NotifyOnOOM(c.state)
|
||||
}
|
||||
|
@ -322,7 +321,7 @@ func (c *linuxContainer) updateStateFile() error {
|
|||
}
|
||||
|
||||
// New returns a newly initialized Pipe for communication between processes
|
||||
func newInitPipe() (parent *os.File, child *os.File, err error) {
|
||||
func (c *linuxContainer) newInitPipe() (parent *os.File, child *os.File, err error) {
|
||||
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -392,9 +391,9 @@ func (c *linuxContainer) initializeNetworking(nspid int, networkState *configs.N
|
|||
return nil
|
||||
}
|
||||
|
||||
func executeSetupCmd(args []string, ppid int, container *configs.Config, process *initConfig, networkState *configs.NetworkState) error {
|
||||
func (c *linuxContainer) executeSetupCmd(args []string, ppid int, container *configs.Config, process *initConfig, networkState *configs.NetworkState) error {
|
||||
command := exec.Command(args[0], args[1:]...)
|
||||
parent, child, err := newInitPipe()
|
||||
parent, child, err := c.newInitPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ const (
|
|||
// Process is used for transferring parameters from Exec() to Init()
|
||||
type initConfig struct {
|
||||
Args []string `json:"args,omitempty"`
|
||||
Env []string `json:"env,omitempty"`
|
||||
Config *configs.Config `json:"config,omitempty"`
|
||||
NetworkState *configs.NetworkState `json:"network_state,omitempty"`
|
||||
}
|
||||
|
@ -43,18 +44,20 @@ func newContainerInit(t initType, pipe *os.File) (initer, error) {
|
|||
if err := json.NewDecoder(pipe).Decode(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := populateProcessEnvironment(config.Config.Env); err != nil {
|
||||
if err := populateProcessEnvironment(config.Env); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch t {
|
||||
case initSetns:
|
||||
return &linuxSetnsInit{
|
||||
args: config.Args,
|
||||
env: config.Env,
|
||||
config: config.Config,
|
||||
}, nil
|
||||
case initUserns:
|
||||
return &linuxUsernsInit{
|
||||
args: config.Args,
|
||||
env: config.Env,
|
||||
config: config.Config,
|
||||
}, nil
|
||||
case initUsernsSideCar:
|
||||
|
@ -65,6 +68,7 @@ func newContainerInit(t initType, pipe *os.File) (initer, error) {
|
|||
case initStandard:
|
||||
return &linuxStandardInit{
|
||||
config: config,
|
||||
env: config.Env,
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown init type %q", t)
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
// inside an existing container.
|
||||
type linuxSetnsInit struct {
|
||||
args []string
|
||||
env []string
|
||||
config *configs.Config
|
||||
}
|
||||
|
||||
|
@ -31,5 +32,5 @@ func (l *linuxSetnsInit) Init() error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
return system.Execv(l.args[0], l.args[0:], l.config.Env)
|
||||
return system.Execv(l.args[0], l.args[0:], l.env)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
|
||||
type linuxStandardInit struct {
|
||||
config *initConfig
|
||||
env []string
|
||||
}
|
||||
|
||||
func (l *linuxStandardInit) Init() error {
|
||||
|
@ -86,5 +87,5 @@ func (l *linuxStandardInit) Init() error {
|
|||
if syscall.Getppid() == 1 {
|
||||
return syscall.Kill(syscall.Getpid(), syscall.SIGKILL)
|
||||
}
|
||||
return system.Execv(l.config.Args[0], l.config.Args[0:], l.config.Config.Env)
|
||||
return system.Execv(l.config.Args[0], l.config.Args[0:], l.env)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
type linuxUsernsInit struct {
|
||||
args []string
|
||||
env []string
|
||||
config *configs.Config
|
||||
}
|
||||
|
||||
|
@ -76,5 +77,5 @@ func (l *linuxUsernsInit) Init() error {
|
|||
if syscall.Getppid() == 1 {
|
||||
return syscall.Kill(syscall.Getpid(), syscall.SIGKILL)
|
||||
}
|
||||
return system.Execv(l.args[0], l.args[0:], l.config.Env)
|
||||
return system.Execv(l.args[0], l.args[0:], l.env)
|
||||
}
|
||||
|
|
10
process.go
10
process.go
|
@ -1,6 +1,9 @@
|
|||
package libcontainer
|
||||
|
||||
import "io"
|
||||
import (
|
||||
"io"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// Process specifies the configuration and IO for a process inside
|
||||
// a container.
|
||||
|
@ -8,6 +11,9 @@ type Process struct {
|
|||
// The command to be run followed by any arguments.
|
||||
Args []string
|
||||
|
||||
// Env specifies the environment variables for the process.
|
||||
Env []string
|
||||
|
||||
// Stdin is a pointer to a reader which provides the standard input stream.
|
||||
Stdin io.Reader
|
||||
|
||||
|
@ -16,4 +22,6 @@ type Process struct {
|
|||
|
||||
// Stderr is a pointer to a writer which receives the standard error stream.
|
||||
Stderr io.Writer
|
||||
|
||||
cmd *exec.Cmd
|
||||
}
|
||||
|
|
|
@ -10,6 +10,10 @@ import (
|
|||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
exitSignalOffset = 128
|
||||
)
|
||||
|
||||
// GenerateRandomName returns a new name joined with a prefix. This size
|
||||
// specified is used to truncate the randomly generated value
|
||||
func GenerateRandomName(prefix string, size int) (string, error) {
|
||||
|
@ -53,3 +57,12 @@ func CloseExecFrom(minFd int) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExitStatus returns the correct exit status for a process based on if it
|
||||
// was signaled or existed cleanly.
|
||||
func ExitStatus(status syscall.WaitStatus) int {
|
||||
if status.Signaled() {
|
||||
return exitSignalOffset + int(status.Signal())
|
||||
}
|
||||
return status.ExitStatus()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue