Merge pull request #6121 from claudiubelu/integration/enables-windows-tests-part-2
integration: Enable some tests for Windows (part 2)
This commit is contained in:
commit
d0bdb0b65e
@ -238,76 +238,6 @@ func TestShimInCgroup(t *testing.T) {
|
|||||||
<-statusC
|
<-statusC
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDaemonRestart(t *testing.T) {
|
|
||||||
client, err := newClient(t, address)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer client.Close()
|
|
||||||
|
|
||||||
var (
|
|
||||||
image Image
|
|
||||||
ctx, cancel = testContext(t)
|
|
||||||
id = t.Name()
|
|
||||||
)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
image, err = client.GetImage(ctx, testImage)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("sleep", "30")))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer container.Delete(ctx, WithSnapshotCleanup)
|
|
||||||
|
|
||||||
task, err := container.NewTask(ctx, empty())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer task.Delete(ctx)
|
|
||||||
|
|
||||||
statusC, err := task.Wait(ctx)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := task.Start(ctx); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var exitStatus ExitStatus
|
|
||||||
if err := ctrd.Restart(func() {
|
|
||||||
exitStatus = <-statusC
|
|
||||||
}); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if exitStatus.Error() == nil {
|
|
||||||
t.Errorf(`first task.Wait() should have failed with "transport is closing"`)
|
|
||||||
}
|
|
||||||
|
|
||||||
waitCtx, waitCancel := context.WithTimeout(ctx, 2*time.Second)
|
|
||||||
serving, err := client.IsServing(waitCtx)
|
|
||||||
waitCancel()
|
|
||||||
if !serving {
|
|
||||||
t.Fatalf("containerd did not start within 2s: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
statusC, err = task.Wait(ctx)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
<-statusC
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShimDoesNotLeakPipes(t *testing.T) {
|
func TestShimDoesNotLeakPipes(t *testing.T) {
|
||||||
containerdPid := ctrd.cmd.Process.Pid
|
containerdPid := ctrd.cmd.Process.Pid
|
||||||
initialPipes, err := numPipes(containerdPid)
|
initialPipes, err := numPipes(containerdPid)
|
||||||
@ -690,57 +620,6 @@ func TestContainerAttach(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDirectIO(ctx context.Context, terminal bool) (*directIO, error) {
|
|
||||||
fifos, err := cio.NewFIFOSetInDir("", "", terminal)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
dio, err := cio.NewDirectIO(ctx, fifos)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &directIO{DirectIO: *dio}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type directIO struct {
|
|
||||||
cio.DirectIO
|
|
||||||
}
|
|
||||||
|
|
||||||
// ioCreate returns IO available for use with task creation
|
|
||||||
func (f *directIO) IOCreate(id string) (cio.IO, error) {
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ioAttach returns IO available for use with task attachment
|
|
||||||
func (f *directIO) IOAttach(set *cio.FIFOSet) (cio.IO, error) {
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *directIO) Cancel() {
|
|
||||||
// nothing to cancel as all operations are handled externally
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close closes all open fds
|
|
||||||
func (f *directIO) Close() error {
|
|
||||||
err := f.Stdin.Close()
|
|
||||||
if f.Stdout != nil {
|
|
||||||
if err2 := f.Stdout.Close(); err == nil {
|
|
||||||
err = err2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if f.Stderr != nil {
|
|
||||||
if err2 := f.Stderr.Close(); err == nil {
|
|
||||||
err = err2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete removes the underlying directory containing fifos
|
|
||||||
func (f *directIO) Delete() error {
|
|
||||||
return f.DirectIO.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContainerUsername(t *testing.T) {
|
func TestContainerUsername(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@ -1372,85 +1251,10 @@ func TestContainerRuntimeOptionsv2(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initContainerAndCheckChildrenDieOnKill(t *testing.T, opts ...oci.SpecOpts) {
|
|
||||||
client, err := newClient(t, address)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer client.Close()
|
|
||||||
|
|
||||||
var (
|
|
||||||
image Image
|
|
||||||
ctx, cancel = testContext(t)
|
|
||||||
id = t.Name()
|
|
||||||
)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
image, err = client.GetImage(ctx, testImage)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
opts = append(opts, oci.WithImageConfig(image))
|
|
||||||
opts = append(opts, withProcessArgs("sh", "-c", "sleep 42; echo hi"))
|
|
||||||
|
|
||||||
container, err := client.NewContainer(ctx, id,
|
|
||||||
WithNewSnapshot(id, image),
|
|
||||||
WithNewSpec(opts...),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer container.Delete(ctx, WithSnapshotCleanup)
|
|
||||||
|
|
||||||
stdout := bytes.NewBuffer(nil)
|
|
||||||
task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout)))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer task.Delete(ctx)
|
|
||||||
|
|
||||||
statusC, err := task.Wait(ctx)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := task.Start(ctx); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Give the shim time to reap the init process and kill the orphans
|
|
||||||
select {
|
|
||||||
case <-statusC:
|
|
||||||
case <-time.After(100 * time.Millisecond):
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := exec.Command("ps", "ax").CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(string(b), "sleep 42") {
|
|
||||||
t.Fatalf("killing init didn't kill all its children:\n%v", string(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := task.Delete(ctx, WithProcessKill); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContainerKillInitPidHost(t *testing.T) {
|
func TestContainerKillInitPidHost(t *testing.T) {
|
||||||
initContainerAndCheckChildrenDieOnKill(t, oci.WithHostNamespace(specs.PIDNamespace))
|
initContainerAndCheckChildrenDieOnKill(t, oci.WithHostNamespace(specs.PIDNamespace))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContainerKillInitKillsChildWhenNotHostPid(t *testing.T) {
|
|
||||||
initContainerAndCheckChildrenDieOnKill(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserNamespaces(t *testing.T) {
|
func TestUserNamespaces(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
t.Run("WritableRootFS", func(t *testing.T) { testUserNamespaces(t, false) })
|
t.Run("WritableRootFS", func(t *testing.T) { testUserNamespaces(t, false) })
|
||||||
@ -1570,49 +1374,6 @@ func testUserNamespaces(t *testing.T, readonlyRootFS bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTaskResize(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
client, err := newClient(t, address)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer client.Close()
|
|
||||||
|
|
||||||
var (
|
|
||||||
image Image
|
|
||||||
ctx, cancel = testContext(t)
|
|
||||||
id = t.Name()
|
|
||||||
)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
image, err = client.GetImage(ctx, testImage)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer container.Delete(ctx, WithSnapshotCleanup)
|
|
||||||
|
|
||||||
task, err := container.NewTask(ctx, empty())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer task.Delete(ctx)
|
|
||||||
|
|
||||||
statusC, err := task.Wait(ctx)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if err := task.Resize(ctx, 32, 32); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
task.Kill(ctx, syscall.SIGKILL)
|
|
||||||
<-statusC
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUIDNoGID(t *testing.T) {
|
func TestUIDNoGID(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@ -1868,73 +1629,3 @@ func TestShimOOMScore(t *testing.T) {
|
|||||||
|
|
||||||
<-statusC
|
<-statusC
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTaskSpec(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
client, err := newClient(t, address)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer client.Close()
|
|
||||||
|
|
||||||
var (
|
|
||||||
image Image
|
|
||||||
ctx, cancel = testContext(t)
|
|
||||||
id = t.Name()
|
|
||||||
)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
image, err = client.GetImage(ctx, testImage)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer container.Delete(ctx, WithSnapshotCleanup)
|
|
||||||
|
|
||||||
task, err := container.NewTask(ctx, empty())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer task.Delete(ctx)
|
|
||||||
|
|
||||||
statusC, err := task.Wait(ctx)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
spec, err := task.Spec(ctx)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if spec == nil {
|
|
||||||
t.Fatal("spec from task is nil")
|
|
||||||
}
|
|
||||||
direct, err := newDirectIO(ctx, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer direct.Delete()
|
|
||||||
|
|
||||||
lt, err := container.Task(ctx, direct.IOAttach)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
spec, err = lt.Spec(ctx)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if spec == nil {
|
|
||||||
t.Fatal("spec from loaded task is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
<-statusC
|
|
||||||
}
|
|
||||||
|
@ -54,7 +54,7 @@ func empty() cio.Creator {
|
|||||||
// TODO (@mlaventure) windows searches for pipes
|
// TODO (@mlaventure) windows searches for pipes
|
||||||
// when none are provided
|
// when none are provided
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
return cio.NewCreator(cio.WithStdio)
|
return cio.NewCreator(cio.WithStdio, cio.WithTerminal)
|
||||||
}
|
}
|
||||||
return cio.NullIO
|
return cio.NullIO
|
||||||
}
|
}
|
||||||
@ -1941,6 +1941,238 @@ func TestRegressionIssue4769(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDaemonRestart(t *testing.T) {
|
||||||
|
client, err := newClient(t, address)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
var (
|
||||||
|
image Image
|
||||||
|
ctx, cancel = testContext(t)
|
||||||
|
id = t.Name()
|
||||||
|
)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer container.Delete(ctx, WithSnapshotCleanup)
|
||||||
|
|
||||||
|
task, err := container.NewTask(ctx, empty())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer task.Delete(ctx)
|
||||||
|
|
||||||
|
statusC, err := task.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := task.Start(ctx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var exitStatus ExitStatus
|
||||||
|
if err := ctrd.Restart(func() {
|
||||||
|
exitStatus = <-statusC
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if exitStatus.Error() == nil {
|
||||||
|
t.Errorf(`first task.Wait() should have failed with "transport is closing"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
waitCtx, waitCancel := context.WithTimeout(ctx, 2*time.Second)
|
||||||
|
serving, err := client.IsServing(waitCtx)
|
||||||
|
waitCancel()
|
||||||
|
if !serving {
|
||||||
|
t.Fatalf("containerd did not start within 2s: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
statusC, err = task.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
<-statusC
|
||||||
|
}
|
||||||
|
|
||||||
|
type directIO struct {
|
||||||
|
cio.DirectIO
|
||||||
|
}
|
||||||
|
|
||||||
|
// ioCreate returns IO available for use with task creation
|
||||||
|
func (f *directIO) IOCreate(id string) (cio.IO, error) {
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ioAttach returns IO available for use with task attachment
|
||||||
|
func (f *directIO) IOAttach(set *cio.FIFOSet) (cio.IO, error) {
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *directIO) Cancel() {
|
||||||
|
// nothing to cancel as all operations are handled externally
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes all open fds
|
||||||
|
func (f *directIO) Close() error {
|
||||||
|
err := f.Stdin.Close()
|
||||||
|
if f.Stdout != nil {
|
||||||
|
if err2 := f.Stdout.Close(); err == nil {
|
||||||
|
err = err2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if f.Stderr != nil {
|
||||||
|
if err2 := f.Stderr.Close(); err == nil {
|
||||||
|
err = err2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes the underlying directory containing fifos
|
||||||
|
func (f *directIO) Delete() error {
|
||||||
|
return f.DirectIO.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func initContainerAndCheckChildrenDieOnKill(t *testing.T, opts ...oci.SpecOpts) {
|
||||||
|
client, err := newClient(t, address)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
var (
|
||||||
|
image Image
|
||||||
|
ctx, cancel = testContext(t)
|
||||||
|
id = t.Name()
|
||||||
|
)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = append(opts, oci.WithImageConfig(image))
|
||||||
|
opts = append(opts, longCommand)
|
||||||
|
|
||||||
|
container, err := client.NewContainer(ctx, id,
|
||||||
|
WithNewSnapshot(id, image),
|
||||||
|
WithNewSpec(opts...),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer container.Delete(ctx, WithSnapshotCleanup)
|
||||||
|
|
||||||
|
stdout := bytes.NewBuffer(nil)
|
||||||
|
task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout)))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer task.Delete(ctx)
|
||||||
|
|
||||||
|
statusC, err := task.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := task.Start(ctx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give the shim time to reap the init process and kill the orphans
|
||||||
|
select {
|
||||||
|
case <-statusC:
|
||||||
|
case <-time.After(100 * time.Millisecond):
|
||||||
|
}
|
||||||
|
|
||||||
|
command := []string{"ps", "ax"}
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
command = []string{"tasklist"}
|
||||||
|
}
|
||||||
|
b, err := exec.Command(command[0], command[1:]...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The container is using longCommand, which contains sleep 1 on Linux, and ping -t localhost on Windows.
|
||||||
|
if strings.Contains(string(b), "sleep 1") || strings.Contains(string(b), "ping -t localhost") {
|
||||||
|
t.Fatalf("killing init didn't kill all its children:\n%v", string(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := task.Delete(ctx, WithProcessKill); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainerKillInitKillsChildWhenNotHostPid(t *testing.T) {
|
||||||
|
initContainerAndCheckChildrenDieOnKill(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTaskResize(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
client, err := newClient(t, address)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
var (
|
||||||
|
image Image
|
||||||
|
ctx, cancel = testContext(t)
|
||||||
|
id = t.Name()
|
||||||
|
)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer container.Delete(ctx, WithSnapshotCleanup)
|
||||||
|
|
||||||
|
task, err := container.NewTask(ctx, empty())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer task.Delete(ctx)
|
||||||
|
|
||||||
|
statusC, err := task.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := task.Resize(ctx, 32, 32); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
task.Kill(ctx, syscall.SIGKILL)
|
||||||
|
<-statusC
|
||||||
|
}
|
||||||
|
|
||||||
func TestContainerImage(t *testing.T) {
|
func TestContainerImage(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@ -2050,3 +2282,73 @@ func TestContainerNoSTDIN(t *testing.T) {
|
|||||||
t.Errorf("expected status 0 from wait but received %d", code)
|
t.Errorf("expected status 0 from wait but received %d", code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTaskSpec(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
client, err := newClient(t, address)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
var (
|
||||||
|
image Image
|
||||||
|
ctx, cancel = testContext(t)
|
||||||
|
id = t.Name()
|
||||||
|
)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
image, err = client.GetImage(ctx, testImage)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer container.Delete(ctx, WithSnapshotCleanup)
|
||||||
|
|
||||||
|
task, err := container.NewTask(ctx, empty())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer task.Delete(ctx)
|
||||||
|
|
||||||
|
statusC, err := task.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := task.Spec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if spec == nil {
|
||||||
|
t.Fatal("spec from task is nil")
|
||||||
|
}
|
||||||
|
direct, err := newDirectIO(ctx, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer direct.Delete()
|
||||||
|
|
||||||
|
lt, err := container.Task(ctx, direct.IOAttach)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err = lt.Spec(ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if spec == nil {
|
||||||
|
t.Fatal("spec from loaded task is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
<-statusC
|
||||||
|
}
|
||||||
|
@ -18,8 +18,6 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -31,91 +29,10 @@ import (
|
|||||||
"github.com/containerd/cgroups"
|
"github.com/containerd/cgroups"
|
||||||
. "github.com/containerd/containerd"
|
. "github.com/containerd/containerd"
|
||||||
"github.com/containerd/containerd/oci"
|
"github.com/containerd/containerd/oci"
|
||||||
"github.com/containerd/containerd/pkg/testutil"
|
|
||||||
"github.com/containerd/containerd/plugin"
|
"github.com/containerd/containerd/plugin"
|
||||||
"github.com/containerd/containerd/runtime/v2/runc/options"
|
"github.com/containerd/containerd/runtime/v2/runc/options"
|
||||||
srvconfig "github.com/containerd/containerd/services/server/config"
|
|
||||||
exec "golang.org/x/sys/execabs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// the following nolint is for shutting up gometalinter on non-linux.
|
|
||||||
// nolint: unused
|
|
||||||
func newDaemonWithConfig(t *testing.T, configTOML string) (*Client, *daemon, func()) {
|
|
||||||
if testing.Short() {
|
|
||||||
t.Skip()
|
|
||||||
}
|
|
||||||
testutil.RequiresRoot(t)
|
|
||||||
var (
|
|
||||||
ctrd = daemon{}
|
|
||||||
configTOMLDecoded srvconfig.Config
|
|
||||||
buf = bytes.NewBuffer(nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
tempDir, err := os.MkdirTemp("", "containerd-test-new-daemon-with-config")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
os.RemoveAll(tempDir)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
configTOMLFile := filepath.Join(tempDir, "config.toml")
|
|
||||||
if err = os.WriteFile(configTOMLFile, []byte(configTOML), 0600); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = srvconfig.LoadConfig(configTOMLFile, &configTOMLDecoded); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
address := configTOMLDecoded.GRPC.Address
|
|
||||||
if address == "" {
|
|
||||||
address = filepath.Join(tempDir, "containerd.sock")
|
|
||||||
}
|
|
||||||
args := []string{"-c", configTOMLFile}
|
|
||||||
if configTOMLDecoded.Root == "" {
|
|
||||||
args = append(args, "--root", filepath.Join(tempDir, "root"))
|
|
||||||
}
|
|
||||||
if configTOMLDecoded.State == "" {
|
|
||||||
args = append(args, "--state", filepath.Join(tempDir, "state"))
|
|
||||||
}
|
|
||||||
if err = ctrd.start("containerd", address, args, buf, buf); err != nil {
|
|
||||||
t.Fatalf("%v: %s", err, buf.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
waitCtx, waitCancel := context.WithTimeout(context.TODO(), 2*time.Second)
|
|
||||||
client, err := ctrd.waitForStart(waitCtx)
|
|
||||||
waitCancel()
|
|
||||||
if err != nil {
|
|
||||||
ctrd.Kill()
|
|
||||||
ctrd.Wait()
|
|
||||||
t.Fatalf("%v: %s", err, buf.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup := func() {
|
|
||||||
if err := client.Close(); err != nil {
|
|
||||||
t.Fatalf("failed to close client: %v", err)
|
|
||||||
}
|
|
||||||
if err := ctrd.Stop(); err != nil {
|
|
||||||
if err := ctrd.Kill(); err != nil {
|
|
||||||
t.Fatalf("failed to signal containerd: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := ctrd.Wait(); err != nil {
|
|
||||||
if _, ok := err.(*exec.ExitError); !ok {
|
|
||||||
t.Fatalf("failed to wait for: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := os.RemoveAll(tempDir); err != nil {
|
|
||||||
t.Fatalf("failed to remove %s: %v", tempDir, err)
|
|
||||||
}
|
|
||||||
// cleaning config-specific resources is up to the caller
|
|
||||||
}
|
|
||||||
return client, &ctrd, cleanup
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestDaemonRuntimeRoot ensures plugin.linux.runtime_root is not ignored
|
// TestDaemonRuntimeRoot ensures plugin.linux.runtime_root is not ignored
|
||||||
func TestDaemonRuntimeRoot(t *testing.T) {
|
func TestDaemonRuntimeRoot(t *testing.T) {
|
||||||
runtimeRoot, err := os.MkdirTemp("", "containerd-test-runtime-root")
|
runtimeRoot, err := os.MkdirTemp("", "containerd-test-runtime-root")
|
||||||
|
@ -19,6 +19,7 @@ package client
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
@ -110,8 +111,12 @@ func (d *daemon) Restart(stopCb func()) error {
|
|||||||
return errors.New("daemon is not running")
|
return errors.New("daemon is not running")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signal := syscall.SIGTERM
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
signal = syscall.SIGKILL
|
||||||
|
}
|
||||||
var err error
|
var err error
|
||||||
if err = d.cmd.Process.Signal(syscall.SIGTERM); err != nil {
|
if err = d.cmd.Process.Signal(signal); err != nil {
|
||||||
return errors.Wrap(err, "failed to signal daemon")
|
return errors.Wrap(err, "failed to signal daemon")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/cio"
|
||||||
"github.com/containerd/containerd/containers"
|
"github.com/containerd/containerd/containers"
|
||||||
"github.com/containerd/containerd/oci"
|
"github.com/containerd/containerd/oci"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
@ -56,3 +57,15 @@ func withExecExitStatus(s *specs.Process, es int) {
|
|||||||
func withExecArgs(s *specs.Process, args ...string) {
|
func withExecArgs(s *specs.Process, args ...string) {
|
||||||
s.Args = args
|
s.Args = args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newDirectIO(ctx context.Context, terminal bool) (*directIO, error) {
|
||||||
|
fifos, err := cio.NewFIFOSetInDir("", "", terminal)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dio, err := cio.NewDirectIO(ctx, fifos)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &directIO{DirectIO: *dio}, nil
|
||||||
|
}
|
||||||
|
@ -17,9 +17,12 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/cio"
|
||||||
"github.com/containerd/containerd/containers"
|
"github.com/containerd/containerd/containers"
|
||||||
"github.com/containerd/containerd/oci"
|
"github.com/containerd/containerd/oci"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
@ -53,3 +56,21 @@ func withExecExitStatus(s *specs.Process, es int) {
|
|||||||
func withExecArgs(s *specs.Process, args ...string) {
|
func withExecArgs(s *specs.Process, args ...string) {
|
||||||
s.Args = append([]string{"cmd", "/c"}, args...)
|
s.Args = append([]string{"cmd", "/c"}, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type bytesBuffer struct {
|
||||||
|
*bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close is a noop operation.
|
||||||
|
func (b bytesBuffer) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDirectIO(ctx context.Context, terminal bool) (*directIO, error) {
|
||||||
|
readb := bytesBuffer{bytes.NewBuffer(nil)}
|
||||||
|
writeb := io.NopCloser(bytes.NewBuffer(nil))
|
||||||
|
errb := io.NopCloser(bytes.NewBuffer(nil))
|
||||||
|
|
||||||
|
dio := cio.NewDirectIO(readb, writeb, errb, terminal)
|
||||||
|
return &directIO{DirectIO: *dio}, nil
|
||||||
|
}
|
||||||
|
@ -28,10 +28,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestLeaseResources(t *testing.T) {
|
func TestLeaseResources(t *testing.T) {
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
t.Skip()
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := testContext(t)
|
ctx, cancel := testContext(t)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@ -41,11 +37,15 @@ func TestLeaseResources(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
|
snapshotterName := "native"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
snapshotterName = "windows"
|
||||||
|
}
|
||||||
var (
|
var (
|
||||||
ls = client.LeasesService()
|
ls = client.LeasesService()
|
||||||
cs = client.ContentStore()
|
cs = client.ContentStore()
|
||||||
imgSrv = client.ImageService()
|
imgSrv = client.ImageService()
|
||||||
sn = client.SnapshotService("native")
|
sn = client.SnapshotService(snapshotterName)
|
||||||
)
|
)
|
||||||
|
|
||||||
l, err := ls.Create(ctx, leases.WithRandomID())
|
l, err := ls.Create(ctx, leases.WithRandomID())
|
||||||
@ -57,7 +57,7 @@ func TestLeaseResources(t *testing.T) {
|
|||||||
// step 1: download image
|
// step 1: download image
|
||||||
imageName := "k8s.gcr.io/pause:3.6"
|
imageName := "k8s.gcr.io/pause:3.6"
|
||||||
|
|
||||||
image, err := client.Pull(ctx, imageName, WithPullUnpack, WithPullSnapshotter("native"))
|
image, err := client.Pull(ctx, imageName, WithPullUnpack, WithPullSnapshotter(snapshotterName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ func TestLeaseResources(t *testing.T) {
|
|||||||
// step 2: reference snapshotter with lease
|
// step 2: reference snapshotter with lease
|
||||||
r := leases.Resource{
|
r := leases.Resource{
|
||||||
ID: chainID.String(),
|
ID: chainID.String(),
|
||||||
Type: "snapshots/native",
|
Type: "snapshots/" + snapshotterName,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ls.AddResource(ctx, l, r); err != nil {
|
if err := ls.AddResource(ctx, l, r); err != nil {
|
||||||
|
@ -17,8 +17,12 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -26,8 +30,93 @@ import (
|
|||||||
. "github.com/containerd/containerd"
|
. "github.com/containerd/containerd"
|
||||||
"github.com/containerd/containerd/containers"
|
"github.com/containerd/containerd/containers"
|
||||||
"github.com/containerd/containerd/oci"
|
"github.com/containerd/containerd/oci"
|
||||||
|
"github.com/containerd/containerd/pkg/testutil"
|
||||||
|
srvconfig "github.com/containerd/containerd/services/server/config"
|
||||||
|
exec "golang.org/x/sys/execabs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// the following nolint is for shutting up gometalinter on non-linux.
|
||||||
|
// nolint: unused
|
||||||
|
func newDaemonWithConfig(t *testing.T, configTOML string) (*Client, *daemon, func()) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip()
|
||||||
|
}
|
||||||
|
testutil.RequiresRoot(t)
|
||||||
|
var (
|
||||||
|
ctrd = daemon{}
|
||||||
|
configTOMLDecoded srvconfig.Config
|
||||||
|
buf = bytes.NewBuffer(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
tempDir, err := os.MkdirTemp("", "containerd-test-new-daemon-with-config")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
os.RemoveAll(tempDir)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
configTOMLFile := filepath.Join(tempDir, "config.toml")
|
||||||
|
if err = os.WriteFile(configTOMLFile, []byte(configTOML), 0600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = srvconfig.LoadConfig(configTOMLFile, &configTOMLDecoded); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
address := configTOMLDecoded.GRPC.Address
|
||||||
|
if address == "" {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
address = fmt.Sprintf(`\\.\pipe\containerd-containerd-test-%s`, filepath.Base(tempDir))
|
||||||
|
} else {
|
||||||
|
address = filepath.Join(tempDir, "containerd.sock")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args := []string{"-c", configTOMLFile}
|
||||||
|
if configTOMLDecoded.Root == "" {
|
||||||
|
args = append(args, "--root", filepath.Join(tempDir, "root"))
|
||||||
|
}
|
||||||
|
if configTOMLDecoded.State == "" {
|
||||||
|
args = append(args, "--state", filepath.Join(tempDir, "state"))
|
||||||
|
}
|
||||||
|
if err = ctrd.start("containerd", address, args, buf, buf); err != nil {
|
||||||
|
t.Fatalf("%v: %s", err, buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
waitCtx, waitCancel := context.WithTimeout(context.TODO(), 2*time.Second)
|
||||||
|
client, err := ctrd.waitForStart(waitCtx)
|
||||||
|
waitCancel()
|
||||||
|
if err != nil {
|
||||||
|
ctrd.Kill()
|
||||||
|
ctrd.Wait()
|
||||||
|
t.Fatalf("%v: %s", err, buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup := func() {
|
||||||
|
if err := client.Close(); err != nil {
|
||||||
|
t.Fatalf("failed to close client: %v", err)
|
||||||
|
}
|
||||||
|
if err := ctrd.Stop(); err != nil {
|
||||||
|
if err := ctrd.Kill(); err != nil {
|
||||||
|
t.Fatalf("failed to signal containerd: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := ctrd.Wait(); err != nil {
|
||||||
|
if _, ok := err.(*exec.ExitError); !ok {
|
||||||
|
t.Fatalf("failed to wait for: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := os.RemoveAll(tempDir); err != nil {
|
||||||
|
t.Fatalf("failed to remove %s: %v", tempDir, err)
|
||||||
|
}
|
||||||
|
// cleaning config-specific resources is up to the caller
|
||||||
|
}
|
||||||
|
return client, &ctrd, cleanup
|
||||||
|
}
|
||||||
|
|
||||||
// TestRestartMonitor tests restarting containers
|
// TestRestartMonitor tests restarting containers
|
||||||
// with the restart monitor service plugin
|
// with the restart monitor service plugin
|
||||||
func TestRestartMonitor(t *testing.T) {
|
func TestRestartMonitor(t *testing.T) {
|
||||||
@ -60,7 +149,7 @@ version = 2
|
|||||||
WithNewSnapshot(id, image),
|
WithNewSnapshot(id, image),
|
||||||
WithNewSpec(
|
WithNewSpec(
|
||||||
oci.WithImageConfig(image),
|
oci.WithImageConfig(image),
|
||||||
withProcessArgs("sleep", "infinity"),
|
longCommand,
|
||||||
),
|
),
|
||||||
withRestartStatus(Running),
|
withRestartStatus(Running),
|
||||||
)
|
)
|
Loading…
Reference in New Issue
Block a user