Move spec generation to Container Create

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2017-08-22 16:56:25 -04:00
parent fa14f2ef3a
commit c601606f84
18 changed files with 128 additions and 314 deletions

View File

@ -74,7 +74,7 @@ In containerd, a container is a metadata object. Resources such as an OCI runti
```go
redis, err := client.NewContainer(context, "redis-master",
containerd.WithSpec(spec),
containerd.WithNewSpec(spec),
)
defer redis.Delete(context)
```
@ -89,7 +89,7 @@ image, err := client.Pull(context, "docker.io/library/redis:latest", containerd.
// allocate a new RW root filesystem for a container based on the image
redis, err := client.NewContainer(context, "redis-master",
containerd.WithSpec(spec),
containerd.WithNewSpec(spec),
containerd.WithNewSnapshot("redis-rootfs", image),
)
@ -97,7 +97,7 @@ redis, err := client.NewContainer(context, "redis-master",
for i := 0; i < 10; i++ {
id := fmt.Sprintf("id-%s", i)
container, err := client.NewContainer(ctx, id,
containerd.WithSpec(spec),
containerd.WithNewSpec(spec),
containerd.WithNewSnapshotView(id, image),
)
}

View File

@ -5,12 +5,13 @@ package containerd
import (
"context"
"github.com/containerd/containerd/containers"
specs "github.com/opencontainers/runtime-spec/specs-go"
)
// WithApparmor sets the provided apparmor profile to the spec
func WithApparmorProfile(profile string) SpecOpts {
return func(_ context.Context, _ *Client, s *specs.Spec) error {
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Process.ApparmorProfile = profile
return nil
}

View File

@ -1,105 +0,0 @@
package containerd
import (
"fmt"
"testing"
)
func BenchmarkContainerCreate(b *testing.B) {
client, err := newClient(b, address)
if err != nil {
b.Fatal(err)
}
defer client.Close()
ctx, cancel := testContext()
defer cancel()
image, err := client.GetImage(ctx, testImage)
if err != nil {
b.Error(err)
return
}
spec, err := GenerateSpec(ctx, client, WithImageConfig(image), withTrue())
if err != nil {
b.Error(err)
return
}
var containers []Container
defer func() {
for _, c := range containers {
if err := c.Delete(ctx, WithSnapshotCleanup); err != nil {
b.Error(err)
}
}
}()
// reset the timer before creating containers
b.ResetTimer()
for i := 0; i < b.N; i++ {
id := fmt.Sprintf("%s-%d", b.Name(), i)
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewSnapshot(id, image))
if err != nil {
b.Error(err)
return
}
containers = append(containers, container)
}
b.StopTimer()
}
func BenchmarkContainerStart(b *testing.B) {
client, err := newClient(b, address)
if err != nil {
b.Fatal(err)
}
defer client.Close()
ctx, cancel := testContext()
defer cancel()
image, err := client.GetImage(ctx, testImage)
if err != nil {
b.Error(err)
return
}
spec, err := GenerateSpec(ctx, client, WithImageConfig(image), withTrue())
if err != nil {
b.Error(err)
return
}
var containers []Container
defer func() {
for _, c := range containers {
if err := c.Delete(ctx, WithSnapshotCleanup); err != nil {
b.Error(err)
}
}
}()
for i := 0; i < b.N; i++ {
id := fmt.Sprintf("%s-%d", b.Name(), i)
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewSnapshot(id, image))
if err != nil {
b.Error(err)
return
}
containers = append(containers, container)
}
// reset the timer before starting tasks
b.ResetTimer()
for _, c := range containers {
task, err := c.NewTask(ctx, empty())
if err != nil {
b.Error(err)
return
}
defer task.Delete(ctx)
if err := task.Start(ctx); err != nil {
b.Error(err)
return
}
}
b.StopTimer()
}

View File

@ -98,7 +98,7 @@ func test(c config) error {
return err
}
logrus.Info("generating spec from image")
spec, err := containerd.GenerateSpec(ctx, client, containerd.WithImageConfig(image), containerd.WithProcessArgs("true"))
spec, err := containerd.GenerateSpec(ctx, client, nil, containerd.WithImageConfig(image), containerd.WithProcessArgs("true"))
if err != nil {
return err
}

View File

@ -8,6 +8,7 @@ import (
"github.com/containerd/console"
"github.com/containerd/containerd"
"github.com/containerd/containerd/containers"
digest "github.com/opencontainers/go-digest"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
@ -24,7 +25,7 @@ type killer interface {
}
func withEnv(context *cli.Context) containerd.SpecOpts {
return func(_ gocontext.Context, _ *containerd.Client, s *specs.Spec) error {
return func(_ gocontext.Context, _ *containerd.Client, _ *containers.Container, s *specs.Spec) error {
env := context.StringSlice("env")
if len(env) > 0 {
s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, env)
@ -34,7 +35,7 @@ func withEnv(context *cli.Context) containerd.SpecOpts {
}
func withMounts(context *cli.Context) containerd.SpecOpts {
return func(_ gocontext.Context, _ *containerd.Client, s *specs.Spec) error {
return func(_ gocontext.Context, _ *containerd.Client, _ *containers.Container, s *specs.Spec) error {
for _, mount := range context.StringSlice("mount") {
m, err := parseMountFlag(mount)
if err != nil {

View File

@ -111,11 +111,7 @@ func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli
if context.Bool("net-host") {
opts = append(opts, setHostNetworking())
}
spec, err := containerd.GenerateSpec(ctx, client, opts...)
if err != nil {
return nil, err
}
cOpts = append([]containerd.NewContainerOpts{containerd.WithSpec(spec)}, cOpts...)
cOpts = append([]containerd.NewContainerOpts{containerd.WithNewSpec(opts...)}, cOpts...)
return client.NewContainer(ctx, id, cOpts...)
}

View File

@ -115,7 +115,7 @@ func newContainer(ctx gocontext.Context, client *containerd.Client, context *cli
}
return client.NewContainer(ctx, id,
containerd.WithSpec(spec),
containerd.WithNewSpec(spec),
containerd.WithContainerLabels(labels),
containerd.WithRuntime(context.String("runtime")),
// TODO(mlaventure): containerd.WithImage(image),

View File

@ -28,12 +28,7 @@ func TestCheckpointRestore(t *testing.T) {
t.Error(err)
return
}
spec, err := GenerateSpec(ctx, client, WithImageConfig(image), WithProcessArgs("sleep", "100"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(WithImageConfig(image), WithProcessArgs("sleep", "100")), WithNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -113,12 +108,7 @@ func TestCheckpointRestoreNewContainer(t *testing.T) {
t.Error(err)
return
}
spec, err := GenerateSpec(ctx, client, WithImageConfig(image), WithProcessArgs("sleep", "100"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(WithImageConfig(image), WithProcessArgs("sleep", "100")), WithNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -211,12 +201,7 @@ func TestCheckpointLeaveRunning(t *testing.T) {
t.Error(err)
return
}
spec, err := GenerateSpec(ctx, client, WithImageConfig(image), WithProcessArgs("sleep", "100"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(WithImageConfig(image), WithProcessArgs("sleep", "100")), WithNewSnapshot(id, image))
if err != nil {
t.Error(err)
return

View File

@ -14,6 +14,7 @@ import (
"time"
"github.com/containerd/cgroups"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/linux/runcopts"
specs "github.com/opencontainers/runtime-spec/specs-go"
"golang.org/x/sys/unix"
@ -39,16 +40,14 @@ func TestContainerUpdate(t *testing.T) {
t.Error(err)
return
}
spec, err := generateSpec(ctx, client, WithImageConfig(image), withProcessArgs("sleep", "30"))
if err != nil {
t.Error(err)
return
}
limit := int64(32 * 1024 * 1024)
spec.Linux.Resources.Memory = &specs.LinuxMemory{
Limit: &limit,
memory := func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Linux.Resources.Memory = &specs.LinuxMemory{
Limit: &limit,
}
return nil
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(WithImageConfig(image), withProcessArgs("sleep", "30"), memory), WithNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -127,12 +126,7 @@ func TestShimInCgroup(t *testing.T) {
t.Error(err)
return
}
spec, err := GenerateSpec(ctx, client, WithImageConfig(image), WithProcessArgs("sleep", "30"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), WithNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(WithImageConfig(image), WithProcessArgs("sleep", "30")), WithNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -202,12 +196,7 @@ func TestDaemonRestart(t *testing.T) {
return
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withProcessArgs("sleep", "30"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "30")), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -293,12 +282,7 @@ func TestContainerAttach(t *testing.T) {
}
}
spec, err := generateSpec(withImageConfig(ctx, image), withCat())
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withCat()), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return

View File

@ -58,13 +58,7 @@ func TestNewContainer(t *testing.T) {
ctx, cancel := testContext()
defer cancel()
spec, err := generateSpec(ctx, client)
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec))
container, err := client.NewContainer(ctx, id, WithNewSpec())
if err != nil {
t.Error(err)
return
@ -106,13 +100,7 @@ func TestContainerStart(t *testing.T) {
return
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withExitStatus(7))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withExitStatus(7)), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -184,13 +172,7 @@ func TestContainerOutput(t *testing.T) {
return
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withProcessArgs("echo", expected))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("echo", expected)), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -258,12 +240,7 @@ func TestContainerExec(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withProcessArgs("sleep", "100"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -287,6 +264,11 @@ func TestContainerExec(t *testing.T) {
t.Error(err)
return
}
spec, err := container.Spec()
if err != nil {
t.Error(err)
return
}
// start an exec process without running the original container process info
processSpec := spec.Process
@ -357,12 +339,7 @@ func TestContainerPids(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withProcessArgs("sleep", "100"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -435,12 +412,7 @@ func TestContainerCloseIO(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withCat())
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withCat()), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -505,12 +477,7 @@ func TestDeleteRunningContainer(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withProcessArgs("sleep", "100"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -573,12 +540,7 @@ func TestContainerKill(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withProcessArgs("sleep", "10"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "10")), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -642,12 +604,7 @@ func TestContainerNoBinaryExists(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), WithProcessArgs("nothing"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), WithProcessArgs("nothing")), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -696,12 +653,7 @@ func TestContainerExecNoBinaryExists(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withProcessArgs("sleep", "100"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -723,6 +675,11 @@ func TestContainerExecNoBinaryExists(t *testing.T) {
t.Error(err)
return
}
spec, err := container.Spec()
if err != nil {
t.Error(err)
return
}
// start an exec process without running the original container process
processSpec := spec.Process
@ -769,17 +726,11 @@ func TestUserNamespaces(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client,
withImageConfig(image),
withExitStatus(7),
withUserNamespace(0, 1000, 10000),
)
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id,
WithSpec(spec),
WithNewSpec(withImageConfig(image),
withExitStatus(7),
withUserNamespace(0, 1000, 10000),
),
withRemappedSnapshot(id, image, 1000, 1000),
)
if err != nil {
@ -852,12 +803,7 @@ func TestWaitStoppedTask(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withExitStatus(7))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withExitStatus(7)), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -928,12 +874,7 @@ func TestWaitStoppedProcess(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withProcessArgs("sleep", "100"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -956,6 +897,11 @@ func TestWaitStoppedProcess(t *testing.T) {
t.Error(err)
return
}
spec, err := container.Spec()
if err != nil {
t.Error(err)
return
}
// start an exec process without running the original container process info
processSpec := spec.Process
@ -1027,12 +973,7 @@ func TestTaskForceDelete(t *testing.T) {
return
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withProcessArgs("sleep", "30"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "30")), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -1080,12 +1021,7 @@ func TestProcessForceDelete(t *testing.T) {
return
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withProcessArgs("sleep", "30"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "30")), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -1110,6 +1046,12 @@ func TestProcessForceDelete(t *testing.T) {
t.Error(err)
return
}
spec, err := container.Spec()
if err != nil {
t.Error(err)
return
}
processSpec := spec.Process
withExecArgs(processSpec, "sleep", "20")
execID := t.Name() + "_exec"
@ -1160,16 +1102,11 @@ func TestContainerHostname(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client,
withImageConfig(image),
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image),
withProcessArgs("hostname"),
WithHostname(expected),
)
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
),
withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -1243,12 +1180,7 @@ func TestContainerExitedAtSet(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withTrue())
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withTrue()), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -1315,12 +1247,7 @@ func TestDeleteContainerExecCreated(t *testing.T) {
}
}
spec, err := generateSpec(ctx, client, withImageConfig(image), withProcessArgs("sleep", "100"))
if err != nil {
t.Error(err)
return
}
container, err := client.NewContainer(ctx, id, WithSpec(spec), withNewSnapshot(id, image))
container, err := client.NewContainer(ctx, id, WithNewSpec(withImageConfig(image), withProcessArgs("sleep", "100")), withNewSnapshot(id, image))
if err != nil {
t.Error(err)
return
@ -1343,6 +1270,11 @@ func TestDeleteContainerExecCreated(t *testing.T) {
t.Error(err)
return
}
spec, err := container.Spec()
if err != nil {
t.Error(err)
return
}
// start an exec process without running the original container process info
processSpec := spec.Process

View File

@ -10,7 +10,7 @@ For many functions and methods within the client package you will generally see
If we look at the `NewContainer` method on the client we can see that it has a required argument of `id` and then additional `NewContainerOpts`.
There are a few built in options that allow the container to be created with an existing spec, `WithSpec`, and snapshot opts for creating or using an existing snapshot.
There are a few built in options that allow the container to be created with an existing spec, `WithNewSpec`, and snapshot opts for creating or using an existing snapshot.
```go
func (c *Client) NewContainer(ctx context.Context, id string, opts ...NewContainerOpts) (Container, error) {

View File

@ -109,7 +109,7 @@ The container will be based off of the image, use the runtime information in the
container, err := client.NewContainer(
ctx,
"redis-server",
containerd.WithSpec(spec),
containerd.WithNewSpec(spec),
containerd.WithImage(image),
containerd.WithNewSnapshot("redis-server-snapshot", image),
)
@ -254,7 +254,7 @@ func redisExample() error {
container, err := client.NewContainer(
ctx,
"redis-server",
containerd.WithSpec(spec),
containerd.WithNewSpec(spec),
containerd.WithImage(image),
containerd.WithNewSnapshot("redis-server-snapshot", image),
)

View File

@ -6,17 +6,14 @@ import (
"context"
"fmt"
"github.com/containerd/containerd/containers"
specs "github.com/opencontainers/runtime-spec/specs-go"
)
const newLine = "\n"
func generateSpec(ctx context.Context, client *Client, opts ...SpecOpts) (*specs.Spec, error) {
return GenerateSpec(ctx, client, opts...)
}
func withExitStatus(es int) SpecOpts {
return func(_ context.Context, _ *Client, s *specs.Spec) error {
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Process.Args = []string{"sh", "-c", fmt.Sprintf("exit %d", es)}
return nil
}

View File

@ -3,18 +3,19 @@ package containerd
import (
"context"
"github.com/containerd/containerd/containers"
specs "github.com/opencontainers/runtime-spec/specs-go"
)
// GenerateSpec will generate a default spec from the provided image
// for use as a containerd container
func GenerateSpec(ctx context.Context, client *Client, opts ...SpecOpts) (*specs.Spec, error) {
func GenerateSpec(ctx context.Context, client *Client, c *containers.Container, opts ...SpecOpts) (*specs.Spec, error) {
s, err := createDefaultSpec()
if err != nil {
return nil, err
}
for _, o := range opts {
if err := o(ctx, client, s); err != nil {
if err := o(ctx, client, c, s); err != nil {
return nil, err
}
}

View File

@ -3,15 +3,16 @@ package containerd
import (
"context"
"github.com/containerd/containerd/containers"
specs "github.com/opencontainers/runtime-spec/specs-go"
)
// SpecOpts sets spec specific information to a newly generated OCI spec
type SpecOpts func(context.Context, *Client, *specs.Spec) error
type SpecOpts func(context.Context, *Client, *containers.Container, *specs.Spec) error
// WithProcessArgs replaces the args on the generated spec
func WithProcessArgs(args ...string) SpecOpts {
return func(_ context.Context, _ *Client, s *specs.Spec) error {
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Process.Args = args
return nil
}
@ -19,7 +20,7 @@ func WithProcessArgs(args ...string) SpecOpts {
// WithHostname sets the container's hostname
func WithHostname(name string) SpecOpts {
return func(_ context.Context, _ *Client, s *specs.Spec) error {
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Hostname = name
return nil
}

View File

@ -22,7 +22,7 @@ import (
// WithTTY sets the information on the spec as well as the environment variables for
// using a TTY
func WithTTY(_ context.Context, _ *Client, s *specs.Spec) error {
func WithTTY(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Process.Terminal = true
s.Process.Env = append(s.Process.Env, "TERM=xterm")
return nil
@ -30,7 +30,7 @@ func WithTTY(_ context.Context, _ *Client, s *specs.Spec) error {
// WithHostNamespace allows a task to run inside the host's linux namespace
func WithHostNamespace(ns specs.LinuxNamespaceType) SpecOpts {
return func(_ context.Context, _ *Client, s *specs.Spec) error {
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
for i, n := range s.Linux.Namespaces {
if n.Type == ns {
s.Linux.Namespaces = append(s.Linux.Namespaces[:i], s.Linux.Namespaces[i+1:]...)
@ -44,7 +44,7 @@ func WithHostNamespace(ns specs.LinuxNamespaceType) SpecOpts {
// WithLinuxNamespace uses the passed in namespace for the spec. If a namespace of the same type already exists in the
// spec, the existing namespace is replaced by the one provided.
func WithLinuxNamespace(ns specs.LinuxNamespace) SpecOpts {
return func(_ context.Context, _ *Client, s *specs.Spec) error {
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
for i, n := range s.Linux.Namespaces {
if n.Type == ns.Type {
before := s.Linux.Namespaces[:i]
@ -61,7 +61,7 @@ func WithLinuxNamespace(ns specs.LinuxNamespace) SpecOpts {
// WithImageConfig configures the spec to from the configuration of an Image
func WithImageConfig(i Image) SpecOpts {
return func(ctx context.Context, client *Client, s *specs.Spec) error {
return func(ctx context.Context, client *Client, c *containers.Container, s *specs.Spec) error {
var (
image = i.(*image)
store = client.ContentStore()
@ -129,7 +129,7 @@ func WithImageConfig(i Image) SpecOpts {
// WithRootFSPath specifies unmanaged rootfs path.
func WithRootFSPath(path string, readonly bool) SpecOpts {
return func(_ context.Context, _ *Client, s *specs.Spec) error {
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Root = &specs.Root{
Path: path,
Readonly: readonly,
@ -139,10 +139,31 @@ func WithRootFSPath(path string, readonly bool) SpecOpts {
}
}
// WithSpec sets the provided spec for a new container
func WithSpec(spec *specs.Spec) NewContainerOpts {
// WithNewSpec generates a new spec for a new container
func WithNewSpec(opts ...SpecOpts) NewContainerOpts {
return func(ctx context.Context, client *Client, c *containers.Container) error {
any, err := typeurl.MarshalAny(spec)
s, err := createDefaultSpec()
if err != nil {
return err
}
for _, o := range opts {
if err := o(ctx, client, c, s); err != nil {
return err
}
}
any, err := typeurl.MarshalAny(s)
if err != nil {
return err
}
c.Spec = any
return nil
}
}
// WithSpec sets the provided spec on the container
func WithSpec(s *specs.Spec) NewContainerOpts {
return func(ctx context.Context, client *Client, c *containers.Container) error {
any, err := typeurl.MarshalAny(s)
if err != nil {
return err
}
@ -160,13 +181,13 @@ func WithResources(resources *specs.LinuxResources) UpdateTaskOpts {
}
// WithNoNewPrivileges sets no_new_privileges on the process for the container
func WithNoNewPrivileges(_ context.Context, _ *Client, s *specs.Spec) error {
func WithNoNewPrivileges(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Process.NoNewPrivileges = true
return nil
}
// WithHostHostsFile bind-mounts the host's /etc/hosts into the container as readonly
func WithHostHostsFile(_ context.Context, _ *Client, s *specs.Spec) error {
func WithHostHostsFile(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Mounts = append(s.Mounts, specs.Mount{
Destination: "/etc/hosts",
Type: "bind",
@ -177,7 +198,7 @@ func WithHostHostsFile(_ context.Context, _ *Client, s *specs.Spec) error {
}
// WithHostResolvconf bind-mounts the host's /etc/resolv.conf into the container as readonly
func WithHostResolvconf(_ context.Context, _ *Client, s *specs.Spec) error {
func WithHostResolvconf(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Mounts = append(s.Mounts, specs.Mount{
Destination: "/etc/resolv.conf",
Type: "bind",
@ -188,7 +209,7 @@ func WithHostResolvconf(_ context.Context, _ *Client, s *specs.Spec) error {
}
// WithHostLocaltime bind-mounts the host's /etc/localtime into the container as readonly
func WithHostLocaltime(_ context.Context, _ *Client, s *specs.Spec) error {
func WithHostLocaltime(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Mounts = append(s.Mounts, specs.Mount{
Destination: "/etc/localtime",
Type: "bind",
@ -201,7 +222,7 @@ func WithHostLocaltime(_ context.Context, _ *Client, s *specs.Spec) error {
// WithUserNamespace sets the uid and gid mappings for the task
// this can be called multiple times to add more mappings to the generated spec
func WithUserNamespace(container, host, size uint32) SpecOpts {
return func(_ context.Context, _ *Client, s *specs.Spec) error {
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
var hasUserns bool
for _, ns := range s.Linux.Namespaces {
if ns.Type == specs.UserNamespace {
@ -271,7 +292,7 @@ func WithRemappedSnapshot(id string, i Image, uid, gid uint32) NewContainerOpts
// WithCgroup sets the container's cgroup path
func WithCgroup(path string) SpecOpts {
return func(_ context.Context, _ *Client, s *specs.Spec) error {
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Linux.CgroupsPath = path
return nil
}
@ -279,20 +300,20 @@ func WithCgroup(path string) SpecOpts {
// WithNamespacedCgroup uses the namespace set on the context to create a
// root directory for containers in the cgroup with the id as the subcgroup
func WithNamespacedCgroup(id string) SpecOpts {
return func(ctx context.Context, _ *Client, s *specs.Spec) error {
func WithNamespacedCgroup() SpecOpts {
return func(ctx context.Context, _ *Client, c *containers.Container, s *specs.Spec) error {
namespace, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return err
}
s.Linux.CgroupsPath = filepath.Join("/", namespace, id)
s.Linux.CgroupsPath = filepath.Join("/", namespace, c.ID)
return nil
}
}
// WithUserIDs allows the UID and GID for the Process to be set
func WithUserIDs(uid, gid uint32) SpecOpts {
return func(_ context.Context, _ *Client, s *specs.Spec) error {
return func(_ context.Context, _ *Client, _ *containers.Container, s *specs.Spec) error {
s.Process.User.UID = uid
s.Process.User.GID = gid
return nil

View File

@ -60,7 +60,7 @@ func WithTTY(width, height int) SpecOpts {
}
}
func WithSpec(spec *specs.Spec) NewContainerOpts {
func WithNewSpec(spec *specs.Spec) NewContainerOpts {
return func(ctx context.Context, client *Client, c *containers.Container) error {
any, err := typeurl.MarshalAny(spec)
if err != nil {

View File

@ -12,7 +12,7 @@ import (
func TestGenerateSpec(t *testing.T) {
t.Parallel()
s, err := GenerateSpec(context.Background(), nil)
s, err := GenerateSpec(context.Background(), nil, nil)
if err != nil {
t.Fatal(err)
}
@ -52,7 +52,7 @@ func TestGenerateSpec(t *testing.T) {
func TestSpecWithTTY(t *testing.T) {
t.Parallel()
s, err := GenerateSpec(context.Background(), nil, WithTTY)
s, err := GenerateSpec(context.Background(), nil, nil, WithTTY)
if err != nil {
t.Fatal(err)
}
@ -69,7 +69,7 @@ func TestWithLinuxNamespace(t *testing.T) {
t.Parallel()
replacedNS := specs.LinuxNamespace{Type: specs.NetworkNamespace, Path: "/var/run/netns/test"}
s, err := GenerateSpec(context.Background(), nil, WithLinuxNamespace(replacedNS))
s, err := GenerateSpec(context.Background(), nil, nil, WithLinuxNamespace(replacedNS))
if err != nil {
t.Fatal(err)
}