mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 14:13:58 +08:00
94fb37f557
Currently we have a problem when buffers are used for std file descriptors. These buffers are filled from goroutines (Cmd.goroutine), and we need to wait them to be sure that all data have been copied. Signed-off-by: Andrew Vagin <avagin@openvz.org>
118 lines
2.6 KiB
Go
118 lines
2.6 KiB
Go
package integration
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/docker/libcontainer"
|
|
"github.com/docker/libcontainer/configs"
|
|
)
|
|
|
|
func newStdBuffers() *stdBuffers {
|
|
return &stdBuffers{
|
|
Stdin: bytes.NewBuffer(nil),
|
|
Stdout: bytes.NewBuffer(nil),
|
|
Stderr: bytes.NewBuffer(nil),
|
|
}
|
|
}
|
|
|
|
type stdBuffers struct {
|
|
Stdin *bytes.Buffer
|
|
Stdout *bytes.Buffer
|
|
Stderr *bytes.Buffer
|
|
}
|
|
|
|
func (b *stdBuffers) String() string {
|
|
s := []string{}
|
|
if b.Stderr != nil {
|
|
s = append(s, b.Stderr.String())
|
|
}
|
|
if b.Stdout != nil {
|
|
s = append(s, b.Stdout.String())
|
|
}
|
|
return strings.Join(s, "|")
|
|
}
|
|
|
|
// newRootfs creates a new tmp directory and copies the busybox root filesystem
|
|
func newRootfs() (string, error) {
|
|
dir, err := ioutil.TempDir("", "")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if err := os.MkdirAll(dir, 0700); err != nil {
|
|
return "", err
|
|
}
|
|
if err := copyBusybox(dir); err != nil {
|
|
return "", nil
|
|
}
|
|
return dir, nil
|
|
}
|
|
|
|
func remove(dir string) {
|
|
os.RemoveAll(dir)
|
|
}
|
|
|
|
// copyBusybox copies the rootfs for a busybox container created for the test image
|
|
// into the new directory for the specific test
|
|
func copyBusybox(dest string) error {
|
|
out, err := exec.Command("sh", "-c", fmt.Sprintf("cp -R /busybox/* %s/", dest)).CombinedOutput()
|
|
if err != nil {
|
|
return fmt.Errorf("copy error %q: %q", err, out)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func newContainer(config *configs.Config) (libcontainer.Container, error) {
|
|
factory, err := libcontainer.New(".",
|
|
libcontainer.InitArgs(os.Args[0], "init", "--"),
|
|
libcontainer.Cgroupfs,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return factory.Create("testCT", config)
|
|
}
|
|
|
|
// runContainer runs the container with the specific config and arguments
|
|
//
|
|
// buffers are returned containing the STDOUT and STDERR output for the run
|
|
// along with the exit code and any go error
|
|
func runContainer(config *configs.Config, console string, args ...string) (buffers *stdBuffers, exitCode int, err error) {
|
|
container, err := newContainer(config)
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
defer container.Destroy()
|
|
buffers = newStdBuffers()
|
|
process := &libcontainer.Process{
|
|
Args: args,
|
|
Env: standardEnvironment,
|
|
Stdin: buffers.Stdin,
|
|
Stdout: buffers.Stdout,
|
|
Stderr: buffers.Stderr,
|
|
}
|
|
|
|
err = container.Start(process)
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
ps, err := process.Wait()
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
status := ps.Sys().(syscall.WaitStatus)
|
|
if status.Exited() {
|
|
exitCode = status.ExitStatus()
|
|
} else if status.Signaled() {
|
|
exitCode = -int(status.Signal())
|
|
} else {
|
|
return nil, -1, err
|
|
}
|
|
return
|
|
}
|