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