Update containerd to 5ba368748b.

Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
Lantao Liu
2019-02-05 00:17:00 -08:00
parent f8b3450847
commit c27a12dd08
148 changed files with 3015 additions and 1235 deletions

View File

@@ -1,8 +1,9 @@
# cgroups
[![Build Status](https://travis-ci.org/containerd/cgroups.svg?branch=master)](https://travis-ci.org/containerd/cgroups)
[![codecov](https://codecov.io/gh/containerd/cgroups/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/cgroups)
[![GoDoc](https://godoc.org/github.com/containerd/cgroups?status.svg)](https://godoc.org/github.com/containerd/cgroups)
[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/cgroups)](https://goreportcard.com/report/github.com/containerd/cgroups)
Go package for creating, managing, inspecting, and destroying cgroups.
The resources format for settings on the cgroup uses the OCI runtime-spec found
@@ -110,3 +111,14 @@ err := control.MoveTo(destination)
```go
subCgroup, err := control.New("child", resources)
```
## Project details
Cgroups is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
As a containerd sub-project, you will find the:
* [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
* [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
* and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
information in our [`containerd/project`](https://github.com/containerd/project) repository.

View File

@@ -191,31 +191,42 @@ func (b *blkioController) readEntry(devices map[deviceKey]string, path, name str
}
func createBlkioSettings(blkio *specs.LinuxBlockIO) []blkioSettings {
settings := []blkioSettings{
{
name: "weight",
value: blkio.Weight,
format: uintf,
},
{
name: "leaf_weight",
value: blkio.LeafWeight,
format: uintf,
},
}
for _, wd := range blkio.WeightDevice {
settings := []blkioSettings{}
if blkio.Weight != nil {
settings = append(settings,
blkioSettings{
name: "weight_device",
value: wd,
format: weightdev,
},
blkioSettings{
name: "leaf_weight_device",
value: wd,
format: weightleafdev,
name: "weight",
value: blkio.Weight,
format: uintf,
})
}
if blkio.LeafWeight != nil {
settings = append(settings,
blkioSettings{
name: "leaf_weight",
value: blkio.LeafWeight,
format: uintf,
})
}
for _, wd := range blkio.WeightDevice {
if wd.Weight != nil {
settings = append(settings,
blkioSettings{
name: "weight_device",
value: wd,
format: weightdev,
})
}
if wd.LeafWeight != nil {
settings = append(settings,
blkioSettings{
name: "leaf_weight_device",
value: wd,
format: weightleafdev,
})
}
}
for _, t := range []struct {
name string
list []specs.LinuxThrottleDevice
@@ -265,12 +276,12 @@ func uintf(v interface{}) []byte {
func weightdev(v interface{}) []byte {
wd := v.(specs.LinuxWeightDevice)
return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, wd.Weight))
return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, *wd.Weight))
}
func weightleafdev(v interface{}) []byte {
wd := v.(specs.LinuxWeightDevice)
return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, wd.LeafWeight))
return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, *wd.LeafWeight))
}
func throttleddev(v interface{}) []byte {

View File

@@ -48,11 +48,12 @@ func New(hierarchy Hierarchy, path Path, resources *specs.LinuxResources) (Cgrou
// Load will load an existing cgroup and allow it to be controlled
func Load(hierarchy Hierarchy, path Path) (Cgroup, error) {
var activeSubsystems []Subsystem
subsystems, err := hierarchy()
if err != nil {
return nil, err
}
// check the the subsystems still exist
// check that the subsystems still exist, and keep only those that actually exist
for _, s := range pathers(subsystems) {
p, err := path(s.Name())
if err != nil {
@@ -63,14 +64,15 @@ func Load(hierarchy Hierarchy, path Path) (Cgroup, error) {
}
if _, err := os.Lstat(s.Path(p)); err != nil {
if os.IsNotExist(err) {
return nil, ErrCgroupDeleted
continue
}
return nil, err
}
activeSubsystems = append(activeSubsystems, s)
}
return &cgroup{
path: path,
subsystems: subsystems,
subsystems: activeSubsystems,
}, nil
}
@@ -319,6 +321,49 @@ func (c *cgroup) processes(subsystem Name, recursive bool) ([]Process, error) {
return processes, err
}
// Tasks returns the tasks running inside the cgroup along
// with the subsystem used, pid, and path
func (c *cgroup) Tasks(subsystem Name, recursive bool) ([]Task, error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.err != nil {
return nil, c.err
}
return c.tasks(subsystem, recursive)
}
func (c *cgroup) tasks(subsystem Name, recursive bool) ([]Task, error) {
s := c.getSubsystem(subsystem)
sp, err := c.path(subsystem)
if err != nil {
return nil, err
}
path := s.(pather).Path(sp)
var tasks []Task
err = filepath.Walk(path, func(p string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !recursive && info.IsDir() {
if p == path {
return nil
}
return filepath.SkipDir
}
dir, name := filepath.Split(p)
if name != cgroupTasks {
return nil
}
procs, err := readTasksPids(dir, subsystem)
if err != nil {
return err
}
tasks = append(tasks, procs...)
return nil
})
return tasks, err
}
// Freeze freezes the entire cgroup and all the processes inside it
func (c *cgroup) Freeze() error {
c.mu.Lock()

View File

@@ -44,6 +44,15 @@ type Process struct {
Path string
}
type Task struct {
// Subsystem is the name of the subsystem that the task is in
Subsystem Name
// Pid is the process id of the task
Pid int
// Path is the full path of the subsystem and location that the task is in
Path string
}
// Cgroup handles interactions with the individual groups to perform
// actions on them as them main interface to this cgroup package
type Cgroup interface {
@@ -64,6 +73,8 @@ type Cgroup interface {
Update(resources *specs.LinuxResources) error
// Processes returns all the processes in a select subsystem for the cgroup
Processes(Name, bool) ([]Process, error)
// Tasks returns all the tasks in a select subsystem for the cgroup
Tasks(Name, bool) ([]Task, error)
// Freeze freezes or pauses all processes inside the cgroup
Freeze() error
// Thaw thaw or resumes all processes inside the cgroup

View File

@@ -57,21 +57,21 @@ func (c *cpusetController) Create(path string, resources *specs.LinuxResources)
if resources.CPU != nil {
for _, t := range []struct {
name string
value *string
value string
}{
{
name: "cpus",
value: &resources.CPU.Cpus,
value: resources.CPU.Cpus,
},
{
name: "mems",
value: &resources.CPU.Mems,
value: resources.CPU.Mems,
},
} {
if t.value != nil {
if t.value != "" {
if err := ioutil.WriteFile(
filepath.Join(c.Path(path), fmt.Sprintf("cpuset.%s", t.name)),
[]byte(*t.value),
[]byte(t.value),
defaultFilePerm,
); err != nil {
return err

View File

@@ -58,6 +58,9 @@ func (d *devicesController) Create(path string, resources *specs.LinuxResources)
if device.Allow {
file = allowDeviceFile
}
if device.Type == "" {
device.Type = "a"
}
if err := ioutil.WriteFile(
filepath.Join(d.Path(path), file),
[]byte(deviceString(device)),

View File

@@ -50,7 +50,7 @@ func (n *netprioController) Create(path string, resources *specs.LinuxResources)
if resources.Network != nil {
for _, prio := range resources.Network.Priorities {
if err := ioutil.WriteFile(
filepath.Join(n.Path(path), "net_prio_ifpriomap"),
filepath.Join(n.Path(path), "net_prio.ifpriomap"),
formatPrio(prio.Name, prio.Priority),
defaultFilePerm,
); err != nil {

View File

@@ -42,7 +42,7 @@ const (
)
// Subsystems returns a complete list of the default cgroups
// avaliable on most linux systems
// available on most linux systems
func Subsystems() []Name {
n := []Name{
Hugetlb,

View File

@@ -32,6 +32,11 @@ const (
defaultSlice = "system.slice"
)
var (
canDelegate bool
once sync.Once
)
func Systemd() ([]Subsystem, error) {
root, err := v1MountPoint()
if err != nil {
@@ -54,7 +59,7 @@ func Slice(slice, name string) Path {
slice = defaultSlice
}
return func(subsystem Name) (string, error) {
return filepath.Join(slice, unitName(name)), nil
return filepath.Join(slice, name), nil
}
}
@@ -80,15 +85,39 @@ func (s *SystemdController) Create(path string, resources *specs.LinuxResources)
}
defer conn.Close()
slice, name := splitName(path)
// We need to see if systemd can handle the delegate property
// Systemd will return an error if it cannot handle delegate regardless
// of its bool setting.
checkDelegate := func() {
canDelegate = true
dlSlice := newProperty("Delegate", true)
if _, err := conn.StartTransientUnit(slice, "testdelegate", []systemdDbus.Property{dlSlice}, nil); err != nil {
if dbusError, ok := err.(dbus.Error); ok {
// Starting with systemd v237, Delegate is not even a property of slices anymore,
// so the D-Bus call fails with "InvalidArgs" error.
if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") || strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.InvalidArgs") {
canDelegate = false
}
}
}
conn.StopUnit(slice, "testDelegate", nil)
}
once.Do(checkDelegate)
properties := []systemdDbus.Property{
systemdDbus.PropDescription(fmt.Sprintf("cgroup %s", name)),
systemdDbus.PropWants(slice),
newProperty("DefaultDependencies", false),
newProperty("Delegate", true),
newProperty("MemoryAccounting", true),
newProperty("CPUAccounting", true),
newProperty("BlockIOAccounting", true),
}
// If we can delegate, we add the property back in
if canDelegate {
properties = append(properties, newProperty("Delegate", true))
}
ch := make(chan string)
_, err = conn.StartTransientUnit(name, "replace", properties, ch)
if err != nil {

View File

@@ -111,7 +111,7 @@ func remove(path string) error {
return fmt.Errorf("cgroups: unable to remove path %q", path)
}
// readPids will read all the pids in a cgroup by the provided path
// readPids will read all the pids of processes in a cgroup by the provided path
func readPids(path string, subsystem Name) ([]Process, error) {
f, err := os.Open(filepath.Join(path, cgroupProcs))
if err != nil {
@@ -138,6 +138,33 @@ func readPids(path string, subsystem Name) ([]Process, error) {
return out, nil
}
// readTasksPids will read all the pids of tasks in a cgroup by the provided path
func readTasksPids(path string, subsystem Name) ([]Task, error) {
f, err := os.Open(filepath.Join(path, cgroupTasks))
if err != nil {
return nil, err
}
defer f.Close()
var (
out []Task
s = bufio.NewScanner(f)
)
for s.Scan() {
if t := s.Text(); t != "" {
pid, err := strconv.Atoi(t)
if err != nil {
return nil, err
}
out = append(out, Task{
Pid: pid,
Subsystem: subsystem,
Path: path,
})
}
}
return out, nil
}
func hugePageSizes() ([]string, error) {
var (
pageSizes []string

View File

@@ -172,11 +172,9 @@ checkpoint, err := task.Checkpoint(context)
err := client.Push(context, "myregistry/checkpoints/redis:master", checkpoint)
// on a new machine pull the checkpoint and restore the redis container
image, err := client.Pull(context, "myregistry/checkpoints/redis:master")
checkpoint, err := client.Pull(context, "myregistry/checkpoints/redis:master")
checkpoint := image.Target()
redis, err = client.NewContainer(context, "redis-master", containerd.WithCheckpoint(checkpoint, "redis-rootfs"))
redis, err = client.NewContainer(context, "redis-master", containerd.WithNewSnapshot("redis-rootfs", checkpoint))
defer container.Delete(context)
task, err = redis.NewTask(context, cio.Stdio, containerd.WithTaskCheckpoint(checkpoint))
@@ -212,11 +210,6 @@ See [PLUGINS.md](PLUGINS.md) for how to create plugins
Please see [RELEASES.md](RELEASES.md) for details on versioning and stability
of containerd components.
### Development reports.
Weekly summary on the progress and what is being worked on.
https://github.com/containerd/containerd/tree/master/reports
### Communication
For async communication and long running discussions please use issues and pull requests on the github repo.
@@ -227,6 +220,10 @@ For sync communication we have a community slack with a #containerd channel that
**Slack:** Catch us in the #containerd and #containerd-dev channels on dockercommunity.slack.com.
[Click here for an invite to docker community slack.](https://join.slack.com/t/dockercommunity/shared_invite/enQtNDY4MDc1Mzc0MzIwLTgxZDBlMmM4ZGEyNDc1N2FkMzlhODJkYmE1YTVkYjM1MDE3ZjAwZjBkOGFlOTJkZjRmZGYzNjYyY2M3ZTUxYzQ)
### Security audit
A third party security audit was performed by Cure53 in 4Q2018; the [full report](docs/SECURITY_AUDIT.pdf) is available in our docs/ directory.
### Reporting security issues
__If you are reporting a security issue, please reach out discreetly at security@containerd.io__.

View File

@@ -100,7 +100,7 @@ const (
// readdir calls to this directory do not follow to lower layers.
whiteoutOpaqueDir = whiteoutMetaPrefix + ".opq"
paxSchilyXattr = "SCHILY.xattrs."
paxSchilyXattr = "SCHILY.xattr."
)
// Apply applies a tar stream of an OCI style diff tar.

View File

@@ -74,7 +74,7 @@ func tarName(p string) (string, error) {
// in file names, it is mostly safe to replace however we must
// check just in case
if strings.Contains(p, "/") {
return "", fmt.Errorf("Windows path contains forward slash: %s", p)
return "", fmt.Errorf("windows path contains forward slash: %s", p)
}
return strings.Replace(p, string(os.PathSeparator), "/", -1), nil
@@ -130,11 +130,7 @@ func skipFile(hdr *tar.Header) bool {
// specific or Linux-specific, this warning should be changed to an error
// to cater for the situation where someone does manage to upload a Linux
// image but have it tagged as Windows inadvertently.
if strings.Contains(hdr.Name, ":") {
return true
}
return false
return strings.Contains(hdr.Name, ":")
}
// handleTarTypeBlockCharFifo is an OS-specific helper function used by

View File

@@ -1,4 +1,4 @@
// +build freebsd linux openbsd solaris
// +build !windows
/*
Copyright The containerd Authors.

View File

@@ -275,3 +275,7 @@ func Load(set *FIFOSet) (IO, error) {
closers: []io.Closer{set},
}, nil
}
func (p *pipes) closers() []io.Closer {
return []io.Closer{p.Stdin, p.Stdout, p.Stderr}
}

View File

@@ -152,7 +152,3 @@ func NewDirectIO(ctx context.Context, fifos *FIFOSet) (*DirectIO, error) {
},
}, err
}
func (p *pipes) closers() []io.Closer {
return []io.Closer{p.Stdin, p.Stdout, p.Stderr}
}

View File

@@ -17,6 +17,7 @@
package cio
import (
"context"
"fmt"
"io"
"net"
@@ -144,3 +145,22 @@ func NewDirectIO(stdin io.WriteCloser, stdout, stderr io.ReadCloser, terminal bo
},
}
}
// NewDirectIOFromFIFOSet returns an IO implementation that exposes the IO streams as io.ReadCloser
// and io.WriteCloser.
func NewDirectIOFromFIFOSet(ctx context.Context, stdin io.WriteCloser, stdout, stderr io.ReadCloser, fifos *FIFOSet) *DirectIO {
_, cancel := context.WithCancel(ctx)
pipes := pipes{
Stdin: stdin,
Stdout: stdout,
Stderr: stderr,
}
return &DirectIO{
pipes: pipes,
cio: cio{
config: fifos.Config,
closers: append(pipes.closers(), fifos),
cancel: cancel,
},
}
}

View File

@@ -61,6 +61,7 @@ import (
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"golang.org/x/sync/semaphore"
"google.golang.org/grpc"
"google.golang.org/grpc/health/grpc_health_v1"
)
@@ -292,6 +293,9 @@ type RemoteContext struct {
// platforms will be used to create a PlatformMatcher with no ordering
// preference.
Platforms []string
// MaxConcurrentDownloads is the max concurrent content downloads for each pull.
MaxConcurrentDownloads int
}
func defaultRemoteContext() *RemoteContext {
@@ -403,12 +407,23 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim
}
var (
schema1Converter *schema1.Converter
handler images.Handler
handler images.Handler
isConvertible bool
converterFunc func(context.Context, ocispec.Descriptor) (ocispec.Descriptor, error)
limiter *semaphore.Weighted
)
if desc.MediaType == images.MediaTypeDockerSchema1Manifest && rCtx.ConvertSchema1 {
schema1Converter = schema1.NewConverter(store, fetcher)
schema1Converter := schema1.NewConverter(store, fetcher)
handler = images.Handlers(append(rCtx.BaseHandlers, schema1Converter)...)
isConvertible = true
converterFunc = func(ctx context.Context, _ ocispec.Descriptor) (ocispec.Descriptor, error) {
return schema1Converter.Convert(ctx)
}
} else {
// Get all the children for a descriptor
childrenHandler := images.ChildrenHandler(store)
@@ -421,18 +436,37 @@ func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, lim
childrenHandler = images.LimitManifests(childrenHandler, rCtx.PlatformMatcher, limit)
}
// set isConvertible to true if there is application/octet-stream media type
convertibleHandler := images.HandlerFunc(
func(_ context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
if desc.MediaType == docker.LegacyConfigMediaType {
isConvertible = true
}
return []ocispec.Descriptor{}, nil
},
)
handler = images.Handlers(append(rCtx.BaseHandlers,
remotes.FetchHandler(store, fetcher),
convertibleHandler,
childrenHandler,
)...)
converterFunc = func(ctx context.Context, desc ocispec.Descriptor) (ocispec.Descriptor, error) {
return docker.ConvertManifest(ctx, store, desc)
}
}
if err := images.Dispatch(ctx, handler, desc); err != nil {
if rCtx.MaxConcurrentDownloads > 0 {
limiter = semaphore.NewWeighted(int64(rCtx.MaxConcurrentDownloads))
}
if err := images.Dispatch(ctx, handler, limiter, desc); err != nil {
return images.Image{}, err
}
if schema1Converter != nil {
desc, err = schema1Converter.Convert(ctx)
if err != nil {
if isConvertible {
if desc, err = converterFunc(ctx, desc); err != nil {
return images.Image{}, err
}
}

View File

@@ -178,3 +178,11 @@ func WithImageHandler(h images.Handler) RemoteOpt {
return nil
}
}
// WithMaxConcurrentDownloads sets max concurrent download limit.
func WithMaxConcurrentDownloads(max int) RemoteOpt {
return func(client *Client, c *RemoteContext) error {
c.MaxConcurrentDownloads = max
return nil
}
}

View File

@@ -387,18 +387,16 @@ func (h *handler) Execute(_ []string, r <-chan svc.ChangeRequest, s chan<- svc.S
h.fromsvc <- nil
s <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown | svc.Accepted(windows.SERVICE_ACCEPT_PARAMCHANGE)}
Loop:
for {
select {
case c := <-r:
switch c.Cmd {
case svc.Interrogate:
s <- c.CurrentStatus
case svc.Stop, svc.Shutdown:
s <- svc.Status{State: svc.StopPending, Accepts: 0}
h.s.Stop()
break Loop
}
for c := range r {
switch c.Cmd {
case svc.Interrogate:
s <- c.CurrentStatus
case svc.Stop, svc.Shutdown:
s <- svc.Status{State: svc.StopPending, Accepts: 0}
h.s.Stop()
break Loop
}
}

View File

@@ -124,6 +124,10 @@ var (
Name: "allow-new-privs",
Usage: "turn off OCI spec's NoNewPrivileges feature flag",
},
cli.Uint64Flag{
Name: "memory-limit",
Usage: "memory limit (in bytes) for the container",
},
}
)

View File

@@ -1,3 +1,5 @@
// +build windows
/*
Copyright The containerd Authors.
@@ -14,17 +16,15 @@
limitations under the License.
*/
package archive
package commands
import (
"time"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
// as at MacOS 10.12 there is apparently no way to set timestamps
// with nanosecond precision. We could fall back to utimes/lutimes
// and lose the precision as a temporary workaround.
func chtimes(path string, atime, mtime time.Time) error {
return errors.New("OSX missing UtimesNanoAt")
func init() {
ContainerFlags = append(ContainerFlags, cli.Uint64Flag{
Name: "cpu-count",
Usage: "number of CPUs available to the container",
})
}

View File

@@ -290,6 +290,11 @@ var (
Name: "validate",
Usage: "validate the result against a format (json, mediatype, etc.)",
},
cli.StringFlag{
Name: "editor",
Usage: "select editor (vim, emacs, etc.)",
EnvVar: "EDITOR",
},
},
Action: func(context *cli.Context) error {
var (
@@ -320,7 +325,7 @@ var (
}
defer ra.Close()
nrc, err := edit(content.NewReader(ra))
nrc, err := edit(context, content.NewReader(ra))
if err != nil {
return err
}
@@ -505,7 +510,12 @@ var (
}
)
func edit(rd io.Reader) (io.ReadCloser, error) {
func edit(context *cli.Context, rd io.Reader) (io.ReadCloser, error) {
editor := context.String("editor")
if editor == "" {
return nil, fmt.Errorf("editor is required")
}
tmp, err := ioutil.TempFile(os.Getenv("XDG_RUNTIME_DIR"), "edit-")
if err != nil {
return nil, err
@@ -516,7 +526,7 @@ func edit(rd io.Reader) (io.ReadCloser, error) {
return nil, err
}
cmd := exec.Command("sh", "-c", "$EDITOR "+tmp.Name())
cmd := exec.Command("sh", "-c", fmt.Sprintf("%s %s", editor, tmp.Name()))
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout

View File

@@ -21,7 +21,7 @@ import (
"os"
"github.com/containerd/containerd/cmd/ctr/commands"
oci "github.com/containerd/containerd/images/oci"
"github.com/containerd/containerd/images/oci"
"github.com/containerd/containerd/reference"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -52,6 +52,10 @@ Currently, only OCI format is supported.
Usage: "media type of manifest digest",
Value: ocispec.MediaTypeImageManifest,
},
cli.BoolFlag{
Name: "all-platforms",
Usage: "exports content from all platforms",
},
},
Action: func(context *cli.Context) error {
var (
@@ -101,7 +105,14 @@ Currently, only OCI format is supported.
return nil
}
}
r, err := client.Export(ctx, &oci.V1Exporter{}, desc)
var (
exportOpts []oci.V1ExporterOpt
)
exportOpts = append(exportOpts, oci.WithAllPlatforms(context.Bool("all-platforms")))
r, err := client.Export(ctx, desc, exportOpts...)
if err != nil {
return err
}

View File

@@ -86,9 +86,10 @@ func parseMountFlag(m string) (specs.Mount, error) {
// Command runs a container
var Command = cli.Command{
Name: "run",
Usage: "run a container",
ArgsUsage: "[flags] Image|RootFS ID [COMMAND] [ARG...]",
Name: "run",
Usage: "run a container",
ArgsUsage: "[flags] Image|RootFS ID [COMMAND] [ARG...]",
SkipArgReorder: true,
Flags: append([]cli.Flag{
cli.BoolFlag{
Name: "rm",

View File

@@ -139,6 +139,10 @@ func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli
// NOTE: can be set to "" explicitly for disabling cgroup.
opts = append(opts, oci.WithCgroup(context.String("cgroup")))
}
limit := context.Uint64("memory-limit")
if limit != 0 {
opts = append(opts, oci.WithMemoryLimit(limit))
}
}
cOpts = append(cOpts, containerd.WithRuntime(context.String("runtime"), nil))

View File

@@ -105,6 +105,14 @@ func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli
if context.Bool("isolated") {
opts = append(opts, oci.WithWindowsHyperV)
}
limit := context.Uint64("memory-limit")
if limit != 0 {
opts = append(opts, oci.WithMemoryLimit(limit))
}
ccount := context.Uint64("cpu-count")
if ccount != 0 {
opts = append(opts, oci.WithWindowsCPUCount(ccount))
}
}
cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("label"))))

View File

@@ -36,6 +36,14 @@ var checkpointCommand = cli.Command{
Name: "exit",
Usage: "stop the container after the checkpoint",
},
cli.StringFlag{
Name: "image-path",
Usage: "path to criu image files",
},
cli.StringFlag{
Name: "work-path",
Usage: "path to criu work files and logs",
},
},
Action: func(context *cli.Context) error {
id := context.Args().First()
@@ -59,40 +67,55 @@ var checkpointCommand = cli.Command{
if err != nil {
return err
}
var opts []containerd.CheckpointTaskOpts
if context.Bool("exit") {
opts = append(opts, withExit(info.Runtime.Name))
}
opts := []containerd.CheckpointTaskOpts{withCheckpointOpts(info.Runtime.Name, context)}
checkpoint, err := task.Checkpoint(ctx, opts...)
if err != nil {
return err
}
fmt.Println(checkpoint.Name())
if context.String("image-path") == "" {
fmt.Println(checkpoint.Name())
}
return nil
},
}
func withExit(rt string) containerd.CheckpointTaskOpts {
// withCheckpointOpts only suitable for runc runtime now
func withCheckpointOpts(rt string, context *cli.Context) containerd.CheckpointTaskOpts {
return func(r *containerd.CheckpointTaskInfo) error {
imagePath := context.String("image-path")
workPath := context.String("work-path")
switch rt {
case "io.containerd.runc.v1":
if r.Options == nil {
r.Options = &options.CheckpointOptions{
Exit: true,
}
} else {
opts, _ := r.Options.(*options.CheckpointOptions)
r.Options = &options.CheckpointOptions{}
}
opts, _ := r.Options.(*options.CheckpointOptions)
if context.Bool("exit") {
opts.Exit = true
}
default:
if imagePath != "" {
opts.ImagePath = imagePath
}
if workPath != "" {
opts.WorkPath = workPath
}
case "io.containerd.runtime.v1.linux":
if r.Options == nil {
r.Options = &runctypes.CheckpointOptions{
Exit: true,
}
} else {
opts, _ := r.Options.(*runctypes.CheckpointOptions)
r.Options = &runctypes.CheckpointOptions{}
}
opts, _ := r.Options.(*runctypes.CheckpointOptions)
if context.Bool("exit") {
opts.Exit = true
}
if imagePath != "" {
opts.ImagePath = imagePath
}
if workPath != "" {
opts.WorkPath = workPath
}
}
return nil
}

View File

@@ -28,9 +28,10 @@ import (
//TODO:(jessvalarezo) exec-id is optional here, update to required arg
var execCommand = cli.Command{
Name: "exec",
Usage: "execute additional processes in an existing container",
ArgsUsage: "[flags] CONTAINER CMD [ARG...]",
Name: "exec",
Usage: "execute additional processes in an existing container",
ArgsUsage: "[flags] CONTAINER CMD [ARG...]",
SkipArgReorder: true,
Flags: []cli.Flag{
cli.StringFlag{
Name: "cwd",

View File

@@ -47,7 +47,5 @@ func unlock(ref string) {
locksMu.Lock()
defer locksMu.Unlock()
if _, ok := locks[ref]; ok {
delete(locks, ref)
}
delete(locks, ref)
}

View File

@@ -58,7 +58,7 @@ func (s *fsApplier) Apply(ctx context.Context, desc ocispec.Descriptor, mounts [
defer func() {
if err == nil {
log.G(ctx).WithFields(logrus.Fields{
"d": time.Now().Sub(t1),
"d": time.Since(t1),
"dgst": desc.Digest,
"size": desc.Size,
"media": desc.MediaType,

View File

@@ -20,36 +20,23 @@ import (
"context"
"io"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/images/oci"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
type exportOpts struct {
}
// ExportOpt allows the caller to specify export-specific options
type ExportOpt func(c *exportOpts) error
func resolveExportOpt(opts ...ExportOpt) (exportOpts, error) {
var eopts exportOpts
for _, o := range opts {
if err := o(&eopts); err != nil {
return eopts, err
}
}
return eopts, nil
}
// Export exports an image to a Tar stream.
// OCI format is used by default.
// It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc.
// TODO(AkihiroSuda): support exporting multiple descriptors at once to a single archive stream.
func (c *Client) Export(ctx context.Context, exporter images.Exporter, desc ocispec.Descriptor, opts ...ExportOpt) (io.ReadCloser, error) {
_, err := resolveExportOpt(opts...) // unused now
func (c *Client) Export(ctx context.Context, desc ocispec.Descriptor, opts ...oci.V1ExporterOpt) (io.ReadCloser, error) {
exporter, err := oci.ResolveV1ExportOpt(opts...)
if err != nil {
return nil, err
}
pr, pw := io.Pipe()
go func() {
pw.CloseWithError(errors.Wrap(exporter.Export(ctx, c.ContentStore(), desc, pw), "export failed"))

View File

@@ -185,7 +185,6 @@ func (s *scanner) scanQuoted(quote rune) {
ch = s.next()
}
}
return
}
func (s *scanner) scanEscape(quote rune) rune {

View File

@@ -45,7 +45,7 @@ var (
// Validate return nil if the string s is a valid identifier.
//
// identifiers must be valid domain names according to RFC 1035, section 2.3.1. To
// enforce case insensitvity, all characters must be lower case.
// enforce case insensitivity, all characters must be lower case.
//
// In general, identifiers that pass this validation, should be safe for use as
// a domain names or filesystem path component.

View File

@@ -170,26 +170,22 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string) error {
chain = append(chain, layer.Diff.Digest)
}
if unpacked {
desc, err := i.i.Config(ctx, cs, i.platform)
if err != nil {
return err
}
rootfs := identity.ChainID(chain).String()
cinfo := content.Info{
Digest: desc.Digest,
Labels: map[string]string{
fmt.Sprintf("containerd.io/gc.ref.snapshot.%s", snapshotterName): rootfs,
},
}
if _, err := cs.Update(ctx, cinfo, fmt.Sprintf("labels.containerd.io/gc.ref.snapshot.%s", snapshotterName)); err != nil {
return err
}
desc, err := i.i.Config(ctx, cs, i.platform)
if err != nil {
return err
}
return nil
rootfs := identity.ChainID(chain).String()
cinfo := content.Info{
Digest: desc.Digest,
Labels: map[string]string{
fmt.Sprintf("containerd.io/gc.ref.snapshot.%s", snapshotterName): rootfs,
},
}
_, err = cs.Update(ctx, cinfo, fmt.Sprintf("labels.containerd.io/gc.ref.snapshot.%s", snapshotterName))
return err
}
func (i *image) getLayers(ctx context.Context, platform platforms.MatchComparer) ([]rootfs.Layer, error) {

View File

@@ -26,6 +26,7 @@ import (
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
)
var (
@@ -108,19 +109,30 @@ func Walk(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) err
// handler may return `ErrSkipDesc` to signal to the dispatcher to not traverse
// any children.
//
// A concurrency limiter can be passed in to limit the number of concurrent
// handlers running. When limiter is nil, there is no limit.
//
// Typically, this function will be used with `FetchHandler`, often composed
// with other handlers.
//
// If any handler returns an error, the dispatch session will be canceled.
func Dispatch(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) error {
func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, descs ...ocispec.Descriptor) error {
eg, ctx := errgroup.WithContext(ctx)
for _, desc := range descs {
desc := desc
if limiter != nil {
if err := limiter.Acquire(ctx, 1); err != nil {
return err
}
}
eg.Go(func() error {
desc := desc
children, err := handler.Handle(ctx, desc)
if limiter != nil {
limiter.Release(1)
}
if err != nil {
if errors.Cause(err) == ErrSkipDesc {
return nil // don't traverse the children.
@@ -129,7 +141,7 @@ func Dispatch(ctx context.Context, handler Handler, descs ...ocispec.Descriptor)
}
if len(children) > 0 {
return Dispatch(ctx, handler, children...)
return Dispatch(ctx, handler, limiter, children...)
}
return nil

View File

@@ -25,6 +25,7 @@ import (
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/platforms"
ocispecs "github.com/opencontainers/image-spec/specs-go"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
@@ -37,6 +38,36 @@ import (
// e.g. application/vnd.docker.image.rootfs.diff.tar.gzip
// -> application/vnd.oci.image.layer.v1.tar+gzip
type V1Exporter struct {
AllPlatforms bool
}
// V1ExporterOpt allows the caller to set additional options to a new V1Exporter
type V1ExporterOpt func(c *V1Exporter) error
// DefaultV1Exporter return a default V1Exporter pointer
func DefaultV1Exporter() *V1Exporter {
return &V1Exporter{
AllPlatforms: false,
}
}
// ResolveV1ExportOpt return a new V1Exporter with V1ExporterOpt
func ResolveV1ExportOpt(opts ...V1ExporterOpt) (*V1Exporter, error) {
exporter := DefaultV1Exporter()
for _, o := range opts {
if err := o(exporter); err != nil {
return exporter, err
}
}
return exporter, nil
}
// WithAllPlatforms set V1Exporter`s AllPlatforms option
func WithAllPlatforms(allPlatforms bool) V1ExporterOpt {
return func(c *V1Exporter) error {
c.AllPlatforms = allPlatforms
return nil
}
}
// Export implements Exporter.
@@ -56,8 +87,15 @@ func (oe *V1Exporter) Export(ctx context.Context, store content.Provider, desc o
return nil, nil
}
childrenHandler := images.ChildrenHandler(store)
if !oe.AllPlatforms {
// get local default platform to fetch image manifest
childrenHandler = images.FilterPlatforms(childrenHandler, platforms.Any(platforms.DefaultSpec()))
}
handlers := images.Handlers(
images.ChildrenHandler(store),
childrenHandler,
images.HandlerFunc(exportHandler),
)

View File

@@ -99,8 +99,7 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt
})
}
var handler images.HandlerFunc
handler = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
var handler images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
// Only save images at top level
if desc.Digest != index.Digest {
return images.Children(ctx, cs, desc)

View File

@@ -59,7 +59,6 @@ func (c *Client) Install(ctx context.Context, image Image, opts ...InstallOpts)
if err != nil {
return err
}
defer r.Close()
if _, err := archive.Apply(ctx, path, r, archive.WithFilter(func(hdr *tar.Header) (bool, error) {
d := filepath.Dir(hdr.Name)
result := d == "bin"
@@ -73,8 +72,10 @@ func (c *Client) Install(ctx context.Context, image Image, opts ...InstallOpts)
}
return result, nil
})); err != nil {
r.Close()
return err
}
r.Close()
}
return nil
}

View File

@@ -38,16 +38,31 @@ import (
type contentStore struct {
content.Store
db *DB
l sync.RWMutex
db *DB
shared bool
l sync.RWMutex
}
// newContentStore returns a namespaced content store using an existing
// content store interface.
func newContentStore(db *DB, cs content.Store) *contentStore {
// policy defines the sharing behavior for content between namespaces. Both
// modes will result in shared storage in the backend for committed. Choose
// "shared" to prevent separate namespaces from having to pull the same content
// twice. Choose "isolated" if the content must not be shared between
// namespaces.
//
// If the policy is "shared", writes will try to resolve the "expected" digest
// against the backend, allowing imports of content from other namespaces. In
// "isolated" mode, the client must prove they have the content by providing
// the entire blob before the content can be added to another namespace.
//
// Since we have only two policies right now, it's simpler using bool to
// represent it internally.
func newContentStore(db *DB, shared bool, cs content.Store) *contentStore {
return &contentStore{
Store: cs,
db: db,
Store: cs,
db: db,
shared: shared,
}
}
@@ -383,13 +398,15 @@ func (cs *contentStore) Writer(ctx context.Context, opts ...content.WriterOpt) (
return nil
}
if st, err := cs.Store.Info(ctx, wOpts.Desc.Digest); err == nil {
// Ensure the expected size is the same, it is likely
// an error if the size is mismatched but the caller
// must resolve this on commit
if wOpts.Desc.Size == 0 || wOpts.Desc.Size == st.Size {
shared = true
wOpts.Desc.Size = st.Size
if cs.shared {
if st, err := cs.Store.Info(ctx, wOpts.Desc.Digest); err == nil {
// Ensure the expected size is the same, it is likely
// an error if the size is mismatched but the caller
// must resolve this on commit
if wOpts.Desc.Size == 0 || wOpts.Desc.Size == st.Size {
shared = true
wOpts.Desc.Size = st.Size
}
}
}
}
@@ -762,7 +779,7 @@ func (cs *contentStore) garbageCollect(ctx context.Context) (d time.Duration, er
t1 := time.Now()
defer func() {
if err == nil {
d = time.Now().Sub(t1)
d = time.Since(t1)
}
cs.l.Unlock()
}()

View File

@@ -46,6 +46,19 @@ const (
dbVersion = 3
)
// DBOpt configures how we set up the DB
type DBOpt func(*dbOptions)
// WithPolicyIsolated isolates contents between namespaces
func WithPolicyIsolated(o *dbOptions) {
o.shared = false
}
// dbOptions configure db options.
type dbOptions struct {
shared bool
}
// DB represents a metadata database backed by a bolt
// database. The database is fully namespaced and stores
// image, container, namespace, snapshot, and content data
@@ -72,19 +85,28 @@ type DB struct {
// mutationCallbacks are called after each mutation with the flag
// set indicating whether any dirty flags are set
mutationCallbacks []func(bool)
dbopts dbOptions
}
// NewDB creates a new metadata database using the provided
// bolt database, content store, and snapshotters.
func NewDB(db *bolt.DB, cs content.Store, ss map[string]snapshots.Snapshotter) *DB {
func NewDB(db *bolt.DB, cs content.Store, ss map[string]snapshots.Snapshotter, opts ...DBOpt) *DB {
m := &DB{
db: db,
ss: make(map[string]*snapshotter, len(ss)),
dirtySS: map[string]struct{}{},
dbopts: dbOptions{
shared: true,
},
}
for _, opt := range opts {
opt(&m.dbopts)
}
// Initialize data stores
m.cs = newContentStore(m, cs)
m.cs = newContentStore(m, m.dbopts.shared, cs)
for name, sn := range ss {
m.ss[name] = newSnapshotter(m, name, sn)
}
@@ -154,7 +176,7 @@ func (m *DB) Init(ctx context.Context) error {
if err := m.migrate(tx); err != nil {
return errors.Wrapf(err, "failed to migrate to %s.%d", m.schema, m.version)
}
log.G(ctx).WithField("d", time.Now().Sub(t0)).Debugf("finished database migration to %s.%d", m.schema, m.version)
log.G(ctx).WithField("d", time.Since(t0)).Debugf("finished database migration to %s.%d", m.schema, m.version)
}
}
@@ -306,7 +328,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
m.cleanupSnapshotter(snapshotterName)
sl.Lock()
stats.SnapshotD[snapshotterName] = time.Now().Sub(st1)
stats.SnapshotD[snapshotterName] = time.Since(st1)
sl.Unlock()
wg.Done()
@@ -321,7 +343,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
go func() {
ct1 := time.Now()
m.cleanupContent()
stats.ContentD = time.Now().Sub(ct1)
stats.ContentD = time.Since(ct1)
wg.Done()
}()
m.dirtyCS = false
@@ -329,7 +351,7 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
m.dirtyL.Unlock()
stats.MetaD = time.Now().Sub(t1)
stats.MetaD = time.Since(t1)
m.wlock.Unlock()
wg.Wait()

View File

@@ -296,10 +296,6 @@ func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)
bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectSnapshots, []byte(ss), []byte(name))
if bkt == nil {
getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectSnapshots).ForEach(func(k, v []byte) error {
return nil
})
// Node may be created from dead edge
return nil
}

View File

@@ -628,7 +628,7 @@ func (s *snapshotter) garbageCollect(ctx context.Context) (d time.Duration, err
}
}
if err == nil {
d = time.Now().Sub(t1)
d = time.Since(t1)
}
}()

View File

@@ -141,8 +141,10 @@ func WithEnv(environmentVariables []string) SpecOpts {
// replaced by env key or appended to the list
func replaceOrAppendEnvValues(defaults, overrides []string) []string {
cache := make(map[string]int, len(defaults))
results := make([]string, 0, len(defaults))
for i, e := range defaults {
parts := strings.SplitN(e, "=", 2)
results = append(results, e)
cache[parts[0]] = i
}
@@ -150,7 +152,7 @@ func replaceOrAppendEnvValues(defaults, overrides []string) []string {
// Values w/o = means they want this env to be removed/unset.
if !strings.Contains(value, "=") {
if i, exists := cache[value]; exists {
defaults[i] = "" // Used to indicate it should be removed
results[i] = "" // Used to indicate it should be removed
}
continue
}
@@ -158,21 +160,21 @@ func replaceOrAppendEnvValues(defaults, overrides []string) []string {
// Just do a normal set/update
parts := strings.SplitN(value, "=", 2)
if i, exists := cache[parts[0]]; exists {
defaults[i] = value
results[i] = value
} else {
defaults = append(defaults, value)
results = append(results, value)
}
}
// Now remove all entries that we want to "unset"
for i := 0; i < len(defaults); i++ {
if defaults[i] == "" {
defaults = append(defaults[:i], defaults[i+1:]...)
for i := 0; i < len(results); i++ {
if results[i] == "" {
results = append(results[:i], results[i+1:]...)
i--
}
}
return defaults
return results
}
// WithProcessArgs replaces the args on the generated spec
@@ -310,7 +312,7 @@ func WithImageConfigArgs(image Image, args []string) SpecOpts {
setProcess(s)
if s.Linux != nil {
s.Process.Env = append(s.Process.Env, config.Env...)
s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, config.Env)
cmd := config.Cmd
if len(args) > 0 {
cmd = args
@@ -332,8 +334,14 @@ func WithImageConfigArgs(image Image, args []string) SpecOpts {
// even if there is no specified user in the image config
return WithAdditionalGIDs("root")(ctx, client, c, s)
} else if s.Windows != nil {
s.Process.Env = config.Env
s.Process.Args = append(config.Entrypoint, config.Cmd...)
s.Process.Env = replaceOrAppendEnvValues(s.Process.Env, config.Env)
cmd := config.Cmd
if len(args) > 0 {
cmd = args
}
s.Process.Args = append(config.Entrypoint, cmd...)
s.Process.Cwd = config.WorkingDir
s.Process.User = specs.User{
Username: config.User,
}
@@ -1026,3 +1034,32 @@ func WithWindowsHyperV(_ context.Context, _ Client, _ *containers.Container, s *
}
return nil
}
// WithMemoryLimit sets the `Linux.LinuxResources.Memory.Limit` section to the
// `limit` specified if the `Linux` section is not `nil`. Additionally sets the
// `Windows.WindowsResources.Memory.Limit` section if the `Windows` section is
// not `nil`.
func WithMemoryLimit(limit uint64) SpecOpts {
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
if s.Linux != nil {
if s.Linux.Resources == nil {
s.Linux.Resources = &specs.LinuxResources{}
}
if s.Linux.Resources.Memory == nil {
s.Linux.Resources.Memory = &specs.LinuxMemory{}
}
l := int64(limit)
s.Linux.Resources.Memory.Limit = &l
}
if s.Windows != nil {
if s.Windows.Resources == nil {
s.Windows.Resources = &specs.WindowsResources{}
}
if s.Windows.Resources.Memory == nil {
s.Windows.Resources.Memory = &specs.WindowsMemoryResources{}
}
s.Windows.Resources.Memory.Limit = &limit
}
return nil
}
}

View File

@@ -0,0 +1,41 @@
// +build windows
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package oci
import (
"context"
"github.com/containerd/containerd/containers"
specs "github.com/opencontainers/runtime-spec/specs-go"
)
// WithWindowsCPUCount sets the `Windows.Resources.CPU.Count` section to the
// `count` specified.
func WithWindowsCPUCount(count uint64) SpecOpts {
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
if s.Windows.Resources == nil {
s.Windows.Resources = &specs.WindowsResources{}
}
if s.Windows.Resources.CPU == nil {
s.Windows.Resources.CPU = &specs.WindowsCPUResources{}
}
s.Windows.Resources.CPU.Count = &count
return nil
}
}

View File

@@ -70,9 +70,9 @@ func (h Bar) Format(state fmt.State, r rune) {
negative := width - pad - positive
n := 1
n += copy(p[n:], []byte(green))
n += copy(p[n:], green)
n += copy(p[n:], bytes.Repeat([]byte("+"), positive))
n += copy(p[n:], []byte(reset))
n += copy(p[n:], reset)
if negative > 0 {
copy(p[n:len(p)-1], bytes.Repeat([]byte("-"), negative))

View File

@@ -19,6 +19,6 @@ package progress
const (
escape = "\x1b"
reset = escape + "[0m"
red = escape + "[31m" // nolint: unused, varcheck
red = escape + "[31m" // nolint: staticcheck, varcheck
green = escape + "[32m"
)

View File

@@ -42,10 +42,7 @@ var (
// IsSkipPlugin returns true if the error is skipping the plugin
func IsSkipPlugin(err error) bool {
if errors.Cause(err) == ErrSkipPlugin {
return true
}
return false
return errors.Cause(err) == ErrSkipPlugin
}
// Type is the type of the plugin

View File

@@ -111,9 +111,11 @@ func (p *process) Start(ctx context.Context) error {
ExecID: p.id,
})
if err != nil {
p.io.Cancel()
p.io.Wait()
p.io.Close()
if p.io != nil {
p.io.Cancel()
p.io.Wait()
p.io.Close()
}
return errdefs.FromGRPC(err)
}
p.pid = r.Pid

View File

@@ -79,8 +79,8 @@ func init() {
var t octetType
isCtl := c <= 31 || c == 127
isChar := 0 <= c && c <= 127
isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0
if strings.IndexRune(" \t\r\n", rune(c)) >= 0 {
isSeparator := strings.ContainsRune(" \t\"(),/:;<=>?@[]\\{}", rune(c))
if strings.ContainsRune(" \t\r\n", rune(c)) {
t |= isSpace
}
if isChar && !isCtl && !isSeparator {

View File

@@ -194,7 +194,11 @@ func (a *dockerAuthorizer) fetchTokenWithOAuth(ctx context.Context, to tokenOpti
form.Set("password", to.secret)
}
resp, err := ctxhttp.PostForm(ctx, a.client, to.realm, form)
resp, err := ctxhttp.Post(
ctx, a.client, to.realm,
"application/x-www-form-urlencoded; charset=utf-8",
strings.NewReader(form.Encode()),
)
if err != nil {
return "", err
}

View File

@@ -0,0 +1,88 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package docker
import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/remotes"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
)
// LegacyConfigMediaType should be replaced by OCI image spec.
//
// More detail: docker/distribution#1622
const LegacyConfigMediaType = "application/octet-stream"
// ConvertManifest changes application/octet-stream to schema2 config media type if need.
//
// NOTE:
// 1. original manifest will be deleted by next gc round.
// 2. don't cover manifest list.
func ConvertManifest(ctx context.Context, store content.Store, desc ocispec.Descriptor) (ocispec.Descriptor, error) {
if !(desc.MediaType == images.MediaTypeDockerSchema2Manifest ||
desc.MediaType == ocispec.MediaTypeImageManifest) {
log.G(ctx).Warnf("do nothing for media type: %s", desc.MediaType)
return desc, nil
}
// read manifest data
mb, err := content.ReadBlob(ctx, store, desc)
if err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to read index data")
}
var manifest ocispec.Manifest
if err := json.Unmarshal(mb, &manifest); err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to unmarshal data into manifest")
}
// check config media type
if manifest.Config.MediaType != LegacyConfigMediaType {
return desc, nil
}
manifest.Config.MediaType = images.MediaTypeDockerSchema2Config
data, err := json.MarshalIndent(manifest, "", " ")
if err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to marshal manifest")
}
// update manifest with gc labels
desc.Digest = digest.Canonical.FromBytes(data)
desc.Size = int64(len(data))
labels := map[string]string{}
for i, c := range append([]ocispec.Descriptor{manifest.Config}, manifest.Layers...) {
labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = c.Digest.String()
}
ref := remotes.MakeRefKey(ctx, desc)
if err := content.WriteBlob(ctx, store, ref, bytes.NewReader(data), desc, content.WithLabels(labels)); err != nil {
return ocispec.Descriptor{}, errors.Wrap(err, "failed to update content")
}
return desc, nil
}

View File

@@ -181,7 +181,7 @@ func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, pr
pushHandler,
)
if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
if err := images.Dispatch(ctx, images.Handlers(handlers...), nil, desc); err != nil {
return err
}

View File

@@ -60,6 +60,8 @@ type CreateOptions struct {
ShimCgroup string `protobuf:"bytes,9,opt,name=shim_cgroup,json=shimCgroup,proto3" json:"shim_cgroup,omitempty"`
IoUid uint32 `protobuf:"varint,10,opt,name=io_uid,json=ioUid,proto3" json:"io_uid,omitempty"`
IoGid uint32 `protobuf:"varint,11,opt,name=io_gid,json=ioGid,proto3" json:"io_gid,omitempty"`
CriuWorkPath string `protobuf:"bytes,12,opt,name=criu_work_path,json=criuWorkPath,proto3" json:"criu_work_path,omitempty"`
CriuImagePath string `protobuf:"bytes,13,opt,name=criu_image_path,json=criuImagePath,proto3" json:"criu_image_path,omitempty"`
}
func (m *CreateOptions) Reset() { *m = CreateOptions{} }
@@ -74,6 +76,8 @@ type CheckpointOptions struct {
FileLocks bool `protobuf:"varint,5,opt,name=file_locks,json=fileLocks,proto3" json:"file_locks,omitempty"`
EmptyNamespaces []string `protobuf:"bytes,6,rep,name=empty_namespaces,json=emptyNamespaces" json:"empty_namespaces,omitempty"`
CgroupsMode string `protobuf:"bytes,7,opt,name=cgroups_mode,json=cgroupsMode,proto3" json:"cgroups_mode,omitempty"`
WorkPath string `protobuf:"bytes,8,opt,name=work_path,json=workPath,proto3" json:"work_path,omitempty"`
ImagePath string `protobuf:"bytes,9,opt,name=image_path,json=imagePath,proto3" json:"image_path,omitempty"`
}
func (m *CheckpointOptions) Reset() { *m = CheckpointOptions{} }
@@ -252,6 +256,18 @@ func (m *CreateOptions) MarshalTo(dAtA []byte) (int, error) {
i++
i = encodeVarintRunc(dAtA, i, uint64(m.IoGid))
}
if len(m.CriuWorkPath) > 0 {
dAtA[i] = 0x62
i++
i = encodeVarintRunc(dAtA, i, uint64(len(m.CriuWorkPath)))
i += copy(dAtA[i:], m.CriuWorkPath)
}
if len(m.CriuImagePath) > 0 {
dAtA[i] = 0x6a
i++
i = encodeVarintRunc(dAtA, i, uint64(len(m.CriuImagePath)))
i += copy(dAtA[i:], m.CriuImagePath)
}
return i, nil
}
@@ -341,6 +357,18 @@ func (m *CheckpointOptions) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintRunc(dAtA, i, uint64(len(m.CgroupsMode)))
i += copy(dAtA[i:], m.CgroupsMode)
}
if len(m.WorkPath) > 0 {
dAtA[i] = 0x42
i++
i = encodeVarintRunc(dAtA, i, uint64(len(m.WorkPath)))
i += copy(dAtA[i:], m.WorkPath)
}
if len(m.ImagePath) > 0 {
dAtA[i] = 0x4a
i++
i = encodeVarintRunc(dAtA, i, uint64(len(m.ImagePath)))
i += copy(dAtA[i:], m.ImagePath)
}
return i, nil
}
@@ -439,6 +467,14 @@ func (m *CreateOptions) Size() (n int) {
if m.IoGid != 0 {
n += 1 + sovRunc(uint64(m.IoGid))
}
l = len(m.CriuWorkPath)
if l > 0 {
n += 1 + l + sovRunc(uint64(l))
}
l = len(m.CriuImagePath)
if l > 0 {
n += 1 + l + sovRunc(uint64(l))
}
return n
}
@@ -470,6 +506,14 @@ func (m *CheckpointOptions) Size() (n int) {
if l > 0 {
n += 1 + l + sovRunc(uint64(l))
}
l = len(m.WorkPath)
if l > 0 {
n += 1 + l + sovRunc(uint64(l))
}
l = len(m.ImagePath)
if l > 0 {
n += 1 + l + sovRunc(uint64(l))
}
return n
}
@@ -525,6 +569,8 @@ func (this *CreateOptions) String() string {
`ShimCgroup:` + fmt.Sprintf("%v", this.ShimCgroup) + `,`,
`IoUid:` + fmt.Sprintf("%v", this.IoUid) + `,`,
`IoGid:` + fmt.Sprintf("%v", this.IoGid) + `,`,
`CriuWorkPath:` + fmt.Sprintf("%v", this.CriuWorkPath) + `,`,
`CriuImagePath:` + fmt.Sprintf("%v", this.CriuImagePath) + `,`,
`}`,
}, "")
return s
@@ -541,6 +587,8 @@ func (this *CheckpointOptions) String() string {
`FileLocks:` + fmt.Sprintf("%v", this.FileLocks) + `,`,
`EmptyNamespaces:` + fmt.Sprintf("%v", this.EmptyNamespaces) + `,`,
`CgroupsMode:` + fmt.Sprintf("%v", this.CgroupsMode) + `,`,
`WorkPath:` + fmt.Sprintf("%v", this.WorkPath) + `,`,
`ImagePath:` + fmt.Sprintf("%v", this.ImagePath) + `,`,
`}`,
}, "")
return s
@@ -994,6 +1042,64 @@ func (m *CreateOptions) Unmarshal(dAtA []byte) error {
break
}
}
case 12:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CriuWorkPath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRunc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.CriuWorkPath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 13:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CriuImagePath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRunc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.CriuImagePath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipRunc(dAtA[iNdEx:])
@@ -1202,6 +1308,64 @@ func (m *CheckpointOptions) Unmarshal(dAtA []byte) error {
}
m.CgroupsMode = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field WorkPath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRunc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.WorkPath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 9:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ImagePath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRunc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ImagePath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipRunc(dAtA[iNdEx:])
@@ -1412,39 +1576,43 @@ func init() {
}
var fileDescriptorRunc = []byte{
// 541 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x93, 0xc1, 0x6e, 0xd3, 0x40,
0x10, 0x86, 0x6b, 0xda, 0x26, 0xce, 0xa4, 0x29, 0xb0, 0x50, 0xc9, 0x14, 0x91, 0x86, 0x00, 0x52,
0xb8, 0xa4, 0x12, 0x88, 0x13, 0xb7, 0xa6, 0x08, 0x55, 0x40, 0xa9, 0x0c, 0x95, 0x10, 0x42, 0x5a,
0xb9, 0xeb, 0x21, 0x59, 0xc5, 0xde, 0x59, 0x79, 0xd7, 0xd4, 0xb9, 0xf5, 0x09, 0x78, 0xae, 0x1e,
0x39, 0x72, 0x42, 0x34, 0x2f, 0x02, 0xf2, 0xda, 0x0e, 0x9c, 0x39, 0x72, 0xfb, 0xe7, 0xfb, 0xc7,
0x9e, 0xd1, 0xbf, 0x1a, 0x98, 0x4c, 0xa5, 0x9d, 0xe5, 0x67, 0x63, 0x41, 0xe9, 0xbe, 0x20, 0x65,
0x23, 0xa9, 0x30, 0x8b, 0xff, 0x96, 0x59, 0xae, 0xac, 0x4c, 0x71, 0x3f, 0x91, 0x2a, 0x2f, 0xca,
0x4a, 0xd8, 0x85, 0x46, 0xe3, 0xd4, 0x58, 0x67, 0x64, 0x89, 0xed, 0xfc, 0x69, 0x1f, 0xbb, 0xb6,
0x71, 0x69, 0xee, 0xde, 0x9e, 0xd2, 0x94, 0x5c, 0xc7, 0x7e, 0xa9, 0xaa, 0xe6, 0xe1, 0x57, 0x0f,
0xba, 0x61, 0xae, 0xc4, 0x5b, 0x6d, 0x25, 0x29, 0xc3, 0x02, 0x68, 0xd7, 0x23, 0x02, 0x6f, 0xe0,
0x8d, 0x3a, 0x61, 0x53, 0xb2, 0xfb, 0xb0, 0x55, 0x4b, 0x9e, 0x11, 0xd9, 0xe0, 0x9a, 0xb3, 0xbb,
0x35, 0x0b, 0x89, 0x2c, 0xbb, 0x0b, 0x1d, 0x91, 0xc9, 0x9c, 0xeb, 0xc8, 0xce, 0x82, 0x75, 0xe7,
0xfb, 0x25, 0x38, 0x89, 0xec, 0x8c, 0x3d, 0x82, 0x6d, 0xb3, 0x30, 0x16, 0xd3, 0x98, 0x8b, 0x69,
0x46, 0xb9, 0x0e, 0x36, 0x06, 0xde, 0xc8, 0x0f, 0x7b, 0x35, 0x9d, 0x38, 0x38, 0xbc, 0x58, 0x87,
0xde, 0x24, 0xc3, 0xc8, 0x62, 0xb3, 0xd2, 0x10, 0x7a, 0x8a, 0xb8, 0x96, 0x5f, 0xc8, 0x56, 0x93,
0x3d, 0xf7, 0x5d, 0x57, 0xd1, 0x49, 0xc9, 0xdc, 0xe4, 0x3b, 0xe0, 0x93, 0x46, 0xc5, 0xad, 0xd0,
0x6e, 0x31, 0x3f, 0x6c, 0x97, 0xf5, 0x7b, 0xa1, 0xd9, 0x13, 0xd8, 0xc1, 0xc2, 0x62, 0xa6, 0xa2,
0x84, 0xe7, 0x4a, 0x16, 0xdc, 0x90, 0x98, 0xa3, 0x35, 0x6e, 0x41, 0x3f, 0xbc, 0xd5, 0x98, 0xa7,
0x4a, 0x16, 0xef, 0x2a, 0x8b, 0xed, 0x82, 0x6f, 0x31, 0x4b, 0xa5, 0x8a, 0x92, 0x7a, 0xcb, 0x55,
0xcd, 0xee, 0x01, 0x7c, 0x96, 0x09, 0xf2, 0x84, 0xc4, 0xdc, 0x04, 0x9b, 0xce, 0xed, 0x94, 0xe4,
0x75, 0x09, 0xd8, 0x63, 0xb8, 0x81, 0xa9, 0xb6, 0x0b, 0xae, 0xa2, 0x14, 0x8d, 0x8e, 0x04, 0x9a,
0xa0, 0x35, 0x58, 0x1f, 0x75, 0xc2, 0xeb, 0x8e, 0x1f, 0xaf, 0x70, 0x99, 0x68, 0x95, 0x84, 0xe1,
0x29, 0xc5, 0x18, 0xb4, 0xab, 0x44, 0x6b, 0xf6, 0x86, 0x62, 0x64, 0x0f, 0x61, 0x5b, 0x11, 0x57,
0x78, 0xce, 0xe7, 0xb8, 0xc8, 0xa4, 0x9a, 0x06, 0xbe, 0x1b, 0xb8, 0xa5, 0xe8, 0x18, 0xcf, 0x5f,
0x55, 0x8c, 0xed, 0x41, 0xd7, 0xcc, 0x64, 0xda, 0xe4, 0xda, 0x71, 0xff, 0x81, 0x12, 0x55, 0xa1,
0xb2, 0x1d, 0x68, 0x49, 0xe2, 0xb9, 0x8c, 0x03, 0x18, 0x78, 0xa3, 0x5e, 0xb8, 0x29, 0xe9, 0x54,
0xc6, 0x35, 0x9e, 0xca, 0x38, 0xe8, 0x36, 0xf8, 0xa5, 0x8c, 0x87, 0xbf, 0x3c, 0xb8, 0x39, 0x99,
0xa1, 0x98, 0x6b, 0x92, 0xca, 0x36, 0xcf, 0xc0, 0x60, 0x03, 0x0b, 0xd9, 0xa4, 0xef, 0xf4, 0xff,
0x1a, 0xfb, 0xf0, 0x19, 0x6c, 0x9f, 0x64, 0x24, 0xd0, 0x98, 0x43, 0xb4, 0x91, 0x4c, 0x0c, 0x7b,
0x00, 0x6d, 0x2c, 0x50, 0x70, 0x19, 0x57, 0x77, 0x71, 0x00, 0xcb, 0x1f, 0x7b, 0xad, 0x17, 0x05,
0x8a, 0xa3, 0xc3, 0xb0, 0x55, 0x5a, 0x47, 0xf1, 0xc1, 0xa7, 0xcb, 0xab, 0xfe, 0xda, 0xf7, 0xab,
0xfe, 0xda, 0xc5, 0xb2, 0xef, 0x5d, 0x2e, 0xfb, 0xde, 0xb7, 0x65, 0xdf, 0xfb, 0xb9, 0xec, 0x7b,
0x1f, 0x0f, 0xfe, 0xf5, 0xb0, 0x9f, 0xaf, 0xd4, 0x87, 0xb5, 0xb3, 0x96, 0xbb, 0xd9, 0xa7, 0xbf,
0x03, 0x00, 0x00, 0xff, 0xff, 0x18, 0xa1, 0x4b, 0x5b, 0x27, 0x04, 0x00, 0x00,
// 604 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x94, 0xcf, 0x6e, 0xd3, 0x40,
0x10, 0xc6, 0xeb, 0xfe, 0x49, 0x9c, 0x49, 0xd2, 0xc2, 0x42, 0x25, 0xd3, 0xaa, 0x69, 0x08, 0x7f,
0x14, 0x2e, 0xa9, 0x04, 0xe2, 0xc4, 0xad, 0x29, 0x42, 0x15, 0x50, 0x2a, 0x43, 0x05, 0x42, 0x48,
0x2b, 0x77, 0x3d, 0x24, 0xab, 0xc4, 0x3b, 0x96, 0x77, 0x4d, 0x92, 0x1b, 0x4f, 0xc0, 0x0b, 0xf1,
0x02, 0x3d, 0x21, 0x8e, 0x9c, 0x10, 0xcd, 0x93, 0xa0, 0x5d, 0xc7, 0x69, 0xcf, 0x1c, 0xb9, 0xcd,
0xfc, 0xe6, 0xb3, 0x67, 0xf4, 0x7d, 0xb2, 0xa1, 0x3f, 0x90, 0x66, 0x98, 0x9f, 0xf7, 0x04, 0x25,
0x07, 0x82, 0x94, 0x89, 0xa4, 0xc2, 0x2c, 0xbe, 0x5e, 0x66, 0xb9, 0x32, 0x32, 0xc1, 0x83, 0xb1,
0x54, 0xf9, 0xd4, 0x76, 0xc2, 0xcc, 0x52, 0xd4, 0xae, 0xea, 0xa5, 0x19, 0x19, 0x62, 0xdb, 0x57,
0xf2, 0x9e, 0x93, 0xf5, 0xec, 0x70, 0xe7, 0xf6, 0x80, 0x06, 0xe4, 0x14, 0x07, 0xb6, 0x2a, 0xc4,
0x9d, 0x6f, 0x1e, 0xd4, 0xc3, 0x5c, 0x89, 0x37, 0xa9, 0x91, 0xa4, 0x34, 0x0b, 0xa0, 0xba, 0x58,
0x11, 0x78, 0x6d, 0xaf, 0x5b, 0x0b, 0xcb, 0x96, 0xdd, 0x85, 0xc6, 0xa2, 0xe4, 0x19, 0x91, 0x09,
0x56, 0xdd, 0xb8, 0xbe, 0x60, 0x21, 0x91, 0x61, 0xbb, 0x50, 0x13, 0x99, 0xcc, 0x79, 0x1a, 0x99,
0x61, 0xb0, 0xe6, 0xe6, 0xbe, 0x05, 0xa7, 0x91, 0x19, 0xb2, 0x07, 0xb0, 0xa9, 0x67, 0xda, 0x60,
0x12, 0x73, 0x31, 0xc8, 0x28, 0x4f, 0x83, 0xf5, 0xb6, 0xd7, 0xf5, 0xc3, 0xe6, 0x82, 0xf6, 0x1d,
0xec, 0xfc, 0x58, 0x83, 0x66, 0x3f, 0xc3, 0xc8, 0x60, 0x79, 0x52, 0x07, 0x9a, 0x8a, 0x78, 0x2a,
0xbf, 0x90, 0x29, 0x36, 0x7b, 0xee, 0xb9, 0xba, 0xa2, 0x53, 0xcb, 0xdc, 0xe6, 0x3b, 0xe0, 0x53,
0x8a, 0x8a, 0x1b, 0x91, 0xba, 0xc3, 0xfc, 0xb0, 0x6a, 0xfb, 0x77, 0x22, 0x65, 0x8f, 0x61, 0x1b,
0xa7, 0x06, 0x33, 0x15, 0x8d, 0x79, 0xae, 0xe4, 0x94, 0x6b, 0x12, 0x23, 0x34, 0xda, 0x1d, 0xe8,
0x87, 0xb7, 0xca, 0xe1, 0x99, 0x92, 0xd3, 0xb7, 0xc5, 0x88, 0xed, 0x80, 0x6f, 0x30, 0x4b, 0xa4,
0x8a, 0xc6, 0x8b, 0x2b, 0x97, 0x3d, 0xdb, 0x03, 0xf8, 0x2c, 0xc7, 0xc8, 0xc7, 0x24, 0x46, 0x3a,
0xd8, 0x70, 0xd3, 0x9a, 0x25, 0xaf, 0x2c, 0x60, 0x8f, 0xe0, 0x06, 0x26, 0xa9, 0x99, 0x71, 0x15,
0x25, 0xa8, 0xd3, 0x48, 0xa0, 0x0e, 0x2a, 0xed, 0xb5, 0x6e, 0x2d, 0xdc, 0x72, 0xfc, 0x64, 0x89,
0xad, 0xa3, 0x85, 0x13, 0x9a, 0x27, 0x14, 0x63, 0x50, 0x2d, 0x1c, 0x5d, 0xb0, 0xd7, 0x14, 0x23,
0xbb, 0x0f, 0x9b, 0x8a, 0xb8, 0xc2, 0x09, 0x1f, 0xe1, 0x2c, 0x93, 0x6a, 0x10, 0xf8, 0x6e, 0x61,
0x43, 0xd1, 0x09, 0x4e, 0x5e, 0x16, 0x8c, 0xed, 0x43, 0x5d, 0x0f, 0x65, 0x52, 0xfa, 0x5a, 0x73,
0xef, 0x01, 0x8b, 0x0a, 0x53, 0xd9, 0x36, 0x54, 0x24, 0xf1, 0x5c, 0xc6, 0x01, 0xb4, 0xbd, 0x6e,
0x33, 0xdc, 0x90, 0x74, 0x26, 0xe3, 0x05, 0x1e, 0xc8, 0x38, 0xa8, 0x97, 0xf8, 0x85, 0x8c, 0xed,
0x52, 0x17, 0xe3, 0x84, 0xb2, 0x51, 0x91, 0x65, 0xc3, 0xbd, 0xb1, 0x61, 0xe9, 0x7b, 0xca, 0x46,
0x2e, 0xcf, 0x87, 0xb0, 0xe5, 0x54, 0x32, 0x89, 0x06, 0x58, 0xc8, 0x9a, 0x4e, 0xd6, 0xb4, 0xf8,
0xd8, 0x52, 0xab, 0xeb, 0x7c, 0x5f, 0x85, 0x9b, 0xfd, 0x21, 0x8a, 0x51, 0x4a, 0x52, 0x99, 0x32,
0x54, 0x06, 0xeb, 0x38, 0x95, 0x65, 0x96, 0xae, 0xfe, 0x6f, 0x43, 0xdc, 0x85, 0xda, 0x95, 0x95,
0x7e, 0xf1, 0x59, 0x4c, 0x4a, 0x1b, 0xf7, 0x00, 0xae, 0x39, 0x58, 0x44, 0x57, 0x93, 0x4b, 0xf7,
0x9e, 0xc2, 0xe6, 0x69, 0x46, 0x02, 0xb5, 0x3e, 0x42, 0x13, 0xc9, 0xb1, 0x66, 0xf7, 0xa0, 0x8a,
0x53, 0x14, 0x5c, 0xc6, 0xc5, 0x17, 0x7a, 0x08, 0xf3, 0xdf, 0xfb, 0x95, 0xe7, 0x53, 0x14, 0xc7,
0x47, 0x61, 0xc5, 0x8e, 0x8e, 0xe3, 0xc3, 0x4f, 0x17, 0x97, 0xad, 0x95, 0x5f, 0x97, 0xad, 0x95,
0xaf, 0xf3, 0x96, 0x77, 0x31, 0x6f, 0x79, 0x3f, 0xe7, 0x2d, 0xef, 0xcf, 0xbc, 0xe5, 0x7d, 0x3c,
0xfc, 0xd7, 0x5f, 0xcc, 0xb3, 0x65, 0xf5, 0x61, 0xe5, 0xbc, 0xe2, 0xfe, 0x1e, 0x4f, 0xfe, 0x06,
0x00, 0x00, 0xff, 0xff, 0x7f, 0x24, 0x6f, 0x2e, 0xb1, 0x04, 0x00, 0x00,
}

View File

@@ -25,6 +25,8 @@ message CreateOptions {
string shim_cgroup = 9;
uint32 io_uid = 10;
uint32 io_gid = 11;
string criu_work_path = 12;
string criu_image_path = 13;
}
message CheckpointOptions {
@@ -35,6 +37,8 @@ message CheckpointOptions {
bool file_locks = 5;
repeated string empty_namespaces = 6;
string cgroups_mode = 7;
string work_path = 8;
string image_path = 9;
}
message ProcessDetails {

View File

@@ -69,4 +69,8 @@ type PlatformRuntime interface {
// Tasks returns all the current tasks for the runtime.
// Any container runs at most one task at a time.
Tasks(context.Context, bool) ([]Task, error)
// Add adds a task into runtime.
Add(context.Context, Task) error
// Delete remove a task.
Delete(context.Context, string)
}

View File

@@ -20,6 +20,7 @@ package linux
import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -114,12 +115,12 @@ func (b *bundle) NewShimClient(ctx context.Context, namespace string, getClientO
// Delete deletes the bundle from disk
func (b *bundle) Delete() error {
err := os.RemoveAll(b.path)
err := atomicDelete(b.path)
if err == nil {
return os.RemoveAll(b.workDir)
return atomicDelete(b.workDir)
}
// error removing the bundle path; still attempt removing work dir
err2 := os.RemoveAll(b.workDir)
err2 := atomicDelete(b.workDir)
if err2 == nil {
return err
}
@@ -152,3 +153,13 @@ func (b *bundle) shimConfig(namespace string, c *Config, runcOptions *runctypes.
SystemdCgroup: systemdCgroup,
}
}
// atomicDelete renames the path to a hidden file before removal
func atomicDelete(path string) error {
// create a hidden dir for an atomic removal
atomicPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path)))
if err := os.Rename(path, atomicPath); err != nil {
return err
}
return os.RemoveAll(atomicPath)
}

View File

@@ -69,7 +69,3 @@ func (s *deletedState) SetExited(status int) {
func (s *deletedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
return nil, errors.Errorf("cannot exec in a deleted state")
}
func (s *deletedState) Pid() int {
return -1
}

View File

@@ -49,7 +49,7 @@ type execProcess struct {
io runc.IO
status int
exited time.Time
pid int
pid *safePid
closers []io.Closer
stdin io.Closer
stdio proc.Stdio
@@ -69,11 +69,7 @@ func (e *execProcess) ID() string {
}
func (e *execProcess) Pid() int {
return e.execState.Pid()
}
func (e *execProcess) pidv() int {
return e.pid
return e.pid.get()
}
func (e *execProcess) ExitStatus() int {
@@ -145,7 +141,7 @@ func (e *execProcess) Kill(ctx context.Context, sig uint32, _ bool) error {
}
func (e *execProcess) kill(ctx context.Context, sig uint32, _ bool) error {
pid := e.pid
pid := e.pid.get()
if pid != 0 {
if err := unix.Kill(pid, syscall.Signal(sig)); err != nil {
return errors.Wrapf(checkKillError(err), "exec kill error")
@@ -170,6 +166,12 @@ func (e *execProcess) Start(ctx context.Context) error {
}
func (e *execProcess) start(ctx context.Context) (err error) {
// The reaper may receive exit signal right after
// the container is started, before the e.pid is updated.
// In that case, we want to block the signal handler to
// access e.pid until it is updated.
e.pid.Lock()
defer e.pid.Unlock()
var (
socket *runc.Socket
pidfile = filepath.Join(e.path, fmt.Sprintf("%s.pid", e.id))
@@ -201,7 +203,7 @@ func (e *execProcess) start(ctx context.Context) (err error) {
return e.parent.runtimeError(err, "OCI runtime exec failed")
}
if e.stdio.Stdin != "" {
sc, err := fifo.OpenFifo(ctx, e.stdio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
sc, err := fifo.OpenFifo(context.Background(), e.stdio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
if err != nil {
return errors.Wrapf(err, "failed to open stdin fifo %s", e.stdio.Stdin)
}
@@ -209,6 +211,8 @@ func (e *execProcess) start(ctx context.Context) (err error) {
e.stdin = sc
}
var copyWaitGroup sync.WaitGroup
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
if socket != nil {
console, err := socket.ReceiveMaster()
if err != nil {
@@ -227,7 +231,7 @@ func (e *execProcess) start(ctx context.Context) (err error) {
if err != nil {
return errors.Wrap(err, "failed to retrieve OCI runtime exec pid")
}
e.pid = pid
e.pid.pid = pid
return nil
}
@@ -245,11 +249,11 @@ func (e *execProcess) Status(ctx context.Context) (string, error) {
e.mu.Lock()
defer e.mu.Unlock()
// if we don't have a pid then the exec process has just been created
if e.pid == 0 {
if e.pid.get() == 0 {
return "created", nil
}
// if we have a pid and it can be signaled, the process is running
if err := unix.Kill(e.pid, 0); err == nil {
if err := unix.Kill(e.pid.get(), 0); err == nil {
return "running", nil
}
// else if we have a pid but it can nolonger be signaled, it has stopped

View File

@@ -31,7 +31,6 @@ type execState interface {
Delete(context.Context) error
Kill(context.Context, uint32, bool) error
SetExited(int)
Pid() int
}
type execCreatedState struct {
@@ -83,12 +82,6 @@ func (s *execCreatedState) SetExited(status int) {
}
}
func (s *execCreatedState) Pid() int {
s.p.mu.Lock()
defer s.p.mu.Unlock()
return s.p.pidv()
}
type execRunningState struct {
p *execProcess
}
@@ -127,12 +120,6 @@ func (s *execRunningState) SetExited(status int) {
}
}
func (s *execRunningState) Pid() int {
s.p.mu.Lock()
defer s.p.mu.Unlock()
return s.p.pidv()
}
type execStoppedState struct {
p *execProcess
}
@@ -170,7 +157,3 @@ func (s *execStoppedState) Kill(ctx context.Context, sig uint32, all bool) error
func (s *execStoppedState) SetExited(status int) {
// no op
}
func (s *execStoppedState) Pid() int {
return s.p.pidv()
}

View File

@@ -76,6 +76,7 @@ type Init struct {
IoGID int
NoPivotRoot bool
NoNewKeyring bool
CriuWorkPath string
}
// NewRunc returns a new runc instance for a process
@@ -132,7 +133,7 @@ func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
opts := &runc.RestoreOpts{
CheckpointOpts: runc.CheckpointOpts{
ImagePath: r.Checkpoint,
WorkDir: p.WorkDir,
WorkDir: p.CriuWorkPath,
ParentPath: r.ParentCheckpoint,
},
PidFile: pidFile,
@@ -160,7 +161,7 @@ func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
return p.runtimeError(err, "OCI runtime create failed")
}
if r.Stdin != "" {
sc, err := fifo.OpenFifo(ctx, r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
sc, err := fifo.OpenFifo(context.Background(), r.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
if err != nil {
return errors.Wrapf(err, "failed to open stdin fifo %s", r.Stdin)
}
@@ -168,6 +169,8 @@ func (p *Init) Create(ctx context.Context, r *CreateConfig) error {
p.closers = append(p.closers, sc)
}
var copyWaitGroup sync.WaitGroup
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
if socket != nil {
console, err := socket.ReceiveMaster()
if err != nil {
@@ -404,6 +407,7 @@ func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (proc.Proce
Terminal: r.Terminal,
},
waitBlock: make(chan struct{}),
pid: &safePid{},
}
e.execState = &execCreatedState{p: e}
return e, nil
@@ -422,8 +426,12 @@ func (p *Init) checkpoint(ctx context.Context, r *CheckpointConfig) error {
if !r.Exit {
actions = append(actions, runc.LeaveRunning)
}
work := filepath.Join(p.WorkDir, "criu-work")
defer os.RemoveAll(work)
// keep criu work directory if criu work dir is set
work := r.WorkDir
if work == "" {
work = filepath.Join(p.WorkDir, "criu-work")
defer os.RemoveAll(work)
}
if err := p.runtime.Checkpoint(ctx, p.id, &runc.CheckpointOpts{
WorkDir: work,
ImagePath: r.Path,

View File

@@ -172,7 +172,7 @@ func (s *createdCheckpointState) Start(ctx context.Context) error {
return p.runtimeError(err, "OCI runtime restore failed")
}
if sio.Stdin != "" {
sc, err := fifo.OpenFifo(ctx, sio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
sc, err := fifo.OpenFifo(context.Background(), sio.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0)
if err != nil {
return errors.Wrapf(err, "failed to open stdin fifo %s", sio.Stdin)
}

View File

@@ -111,7 +111,7 @@ func copyPipes(ctx context.Context, rio runc.IO, stdin, stdout, stderr string, w
if stdin == "" {
return nil
}
f, err := fifo.OpenFifo(ctx, stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0)
f, err := fifo.OpenFifo(context.Background(), stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0)
if err != nil {
return fmt.Errorf("containerd-shim: opening %s failed: %s", stdin, err)
}

View File

@@ -55,6 +55,7 @@ type ExecConfig struct {
// CheckpointConfig holds task checkpoint configuration
type CheckpointConfig struct {
WorkDir string
Path string
Exit bool
AllowOpenTCP bool

View File

@@ -23,6 +23,7 @@ import (
"io"
"os"
"strings"
"sync"
"time"
"github.com/containerd/containerd/errdefs"
@@ -31,6 +32,18 @@ import (
"golang.org/x/sys/unix"
)
// safePid is a thread safe wrapper for pid.
type safePid struct {
sync.Mutex
pid int
}
func (s *safePid) get() int {
s.Lock()
defer s.Unlock()
return s.pid
}
// TODO(mlaventure): move to runc package?
func getLastRuntimeError(r *runc.Runc) (string, error) {
if r.Log == "" {
@@ -93,7 +106,9 @@ func checkKillError(err error) error {
if err == nil {
return nil
}
if strings.Contains(err.Error(), "os: process already finished") || err == unix.ESRCH {
if strings.Contains(err.Error(), "os: process already finished") ||
strings.Contains(err.Error(), "container not running") ||
err == unix.ESRCH {
return errors.Wrapf(errdefs.ErrNotFound, "process already finished")
}
return errors.Wrapf(err, "unknown error after kill")

View File

@@ -290,6 +290,10 @@ func (r *Runtime) restoreTasks(ctx context.Context) ([]*Task, error) {
continue
}
name := namespace.Name()
// skip hidden directories
if len(name) > 0 && name[0] == '.' {
continue
}
log.G(ctx).WithField("namespace", name).Debug("loading tasks in namespace")
tasks, err := r.loadTasks(ctx, name)
if err != nil {
@@ -305,6 +309,16 @@ func (r *Runtime) Get(ctx context.Context, id string) (runtime.Task, error) {
return r.tasks.Get(ctx, id)
}
// Add a runtime task
func (r *Runtime) Add(ctx context.Context, task runtime.Task) error {
return r.tasks.Add(ctx, task)
}
// Delete a runtime task
func (r *Runtime) Delete(ctx context.Context, id string) {
r.tasks.Delete(ctx, id)
}
func (r *Runtime) loadTasks(ctx context.Context, ns string) ([]*Task, error) {
dir, err := ioutil.ReadDir(filepath.Join(r.state, ns))
if err != nil {

View File

@@ -29,10 +29,10 @@ import (
// OpenShimStdoutLog opens the shim log for reading
func OpenShimStdoutLog(ctx context.Context, logDirPath string) (io.ReadWriteCloser, error) {
return fifo.OpenFifo(ctx, filepath.Join(logDirPath, "shim.stdout.log"), unix.O_RDWR|unix.O_CREAT|unix.O_NONBLOCK, 0700)
return fifo.OpenFifo(ctx, filepath.Join(logDirPath, "shim.stdout.log"), unix.O_RDWR|unix.O_CREAT, 0700)
}
// OpenShimStderrLog opens the shim log
func OpenShimStderrLog(ctx context.Context, logDirPath string) (io.ReadWriteCloser, error) {
return fifo.OpenFifo(ctx, filepath.Join(logDirPath, "shim.stderr.log"), unix.O_RDWR|unix.O_CREAT|unix.O_NONBLOCK, 0700)
return fifo.OpenFifo(ctx, filepath.Join(logDirPath, "shim.stderr.log"), unix.O_RDWR|unix.O_CREAT, 0700)
}

View File

@@ -448,6 +448,7 @@ func (s *Service) Checkpoint(ctx context.Context, r *shimapi.CheckpointTaskReque
AllowTerminal: options.Terminal,
FileLocks: options.FileLocks,
EmptyNamespaces: options.EmptyNamespaces,
WorkDir: options.WorkPath,
}); err != nil {
return nil, errdefs.ToGRPC(err)
}
@@ -657,5 +658,11 @@ func newInit(ctx context.Context, path, workDir, runtimeRoot, namespace, criu st
p.IoGID = int(options.IoGid)
p.NoPivotRoot = options.NoPivotRoot
p.NoNewKeyring = options.NoNewKeyring
p.CriuWorkPath = options.CriuWorkPath
if p.CriuWorkPath == "" {
// if criu work path not set, use container WorkDir
p.CriuWorkPath = p.WorkDir
}
return p, nil
}

View File

@@ -36,9 +36,9 @@ This command will launch new shims.
The start command MUST accept the following flags:
* `-namespace` the namespace for the container
* `-id` the id of the container
* `-address` the address of the containerd's main socket
* `-publish-binary` the binary path to publish events back to containerd
* `-id` the id of the container
The start command, as well as all binary calls to the shim, has the bundle for the container set as the `cwd`.
@@ -58,11 +58,12 @@ If a bundle is still on disk but containerd cannot connect to a shim, the delete
The delete command MUST accept the following flags:
* `-namespace` the namespace for the container
* `-id` the id of the container
* `-address` the address of the containerd's main socket
* `-publish-binary` the binary path to publish events back to containerd
* `-id` the id of the container
* `-bundle` the path to the bundle to delete. On non-Windows platforms this will match `cwd`
The delete command will be executed in the container's bundle as its `cwd`.
The delete command will be executed in the container's bundle as its `cwd` except for on the Windows platform.
### Host Level Shim Configuration
@@ -148,8 +149,27 @@ Filesystems are provided by the containerd snapshotters.
### Events
The shim MUST publish a `runtime.TaskExitEventTopic` when the container exits.
If the shim collects Out of Memory events, it SHOULD also publish a `runtime.TaskOOMEventTopic`.
The Runtime v2 supports an async event model. In order for the an upstream caller (such as Docker) to get these events in the correct order a Runtime v2 shim MUST implement the following events where `Compliance=MUST`. This avoids race conditions between the shim and shim client where for example a call to `Start` can signal a `TaskExitEventTopic` before even returning the results from the `Start` call. With these guarantees of a Runtime v2 shim a call to `Start` is required to have published the async event `TaskStartEventTopic` before the shim can publish the `TaskExitEventTopic`.
#### Tasks
| Topic | Compliance | Description |
| ----- | ---------- | ----------- |
| `runtime.TaskCreateEventTopic` | MUST | When a task is successfully created |
| `runtime.TaskStartEventTopic` | MUST (follow `TaskCreateEventTopic`) | When a task is successfully started |
| `runtime.TaskExitEventTopic` | MUST (follow `TaskStartEventTopic`) | When a task exits expected or unexpected |
| `runtime.TaskDeleteEventTopic` | MUST (follow `TaskExitEventTopic` or `TaskCreateEventTopic` if never started) | When a task is removed from a shim |
| `runtime.TaskPausedEventTopic` | SHOULD | When a task is successfully paused |
| `runtime.TaskResumedEventTopic` | SHOULD (follow `TaskPausedEventTopic`) | When a task is successfully resumed |
| `runtime.TaskCheckpointedEventTopic` | SHOULD | When a task is checkpointed |
| `runtime.TaskOOMEventTopic` | SHOULD | If the shim collects Out of Memory events |
#### Execs
| Topic | Compliance | Description |
| ----- | ---------- | ----------- |
| `runtime.TaskExecAddedEventTopic` | MUST (follow `TaskCreateEventTopic` ) | When an exec is successfully added |
| `runtime.TaskExecStartedEventTopic` | MUST (follow `TaskExecStartedEventTopic`) | When an exec is successfully started |
### Other

View File

@@ -24,7 +24,6 @@ import (
gruntime "runtime"
"strings"
eventstypes "github.com/containerd/containerd/api/events"
"github.com/containerd/containerd/events/exchange"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/runtime"
@@ -152,13 +151,6 @@ func (b *binary) Delete(ctx context.Context) (*runtime.Exit, error) {
// remove self from the runtime task list
// this seems dirty but it cleans up the API across runtimes, tasks, and the service
b.rtTasks.Delete(ctx, b.bundle.ID)
// shim will send the exit event
b.events.Publish(ctx, runtime.TaskDeleteEventTopic, &eventstypes.TaskDelete{
ContainerID: b.bundle.ID,
ExitStatus: response.ExitStatus,
ExitedAt: response.ExitedAt,
Pid: response.Pid,
})
return &runtime.Exit{
Status: response.ExitStatus,
Timestamp: response.ExitedAt,

View File

@@ -18,6 +18,7 @@ package v2
import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -114,20 +115,30 @@ type Bundle struct {
// Delete a bundle atomically
func (b *Bundle) Delete() error {
work, werr := os.Readlink(filepath.Join(b.Path, "work"))
err := os.RemoveAll(b.Path)
err := atomicDelete(b.Path)
if err == nil {
if werr == nil {
return os.RemoveAll(work)
return atomicDelete(work)
}
return nil
}
// error removing the bundle path; still attempt removing work dir
var err2 error
if werr == nil {
err2 = os.RemoveAll(work)
err2 = atomicDelete(work)
if err2 == nil {
return err
}
}
return errors.Wrapf(err, "failed to remove both bundle and workdir locations: %v", err2)
}
// atomicDelete renames the path to a hidden file before removal
func atomicDelete(path string) error {
// create a hidden dir for an atomic removal
atomicPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path)))
if err := os.Rename(path, atomicPath); err != nil {
return err
}
return os.RemoveAll(atomicPath)
}

View File

@@ -130,6 +130,16 @@ func (m *TaskManager) Get(ctx context.Context, id string) (runtime.Task, error)
return m.tasks.Get(ctx, id)
}
// Add a runtime task
func (m *TaskManager) Add(ctx context.Context, task runtime.Task) error {
return m.tasks.Add(ctx, task)
}
// Delete a runtime task
func (m *TaskManager) Delete(ctx context.Context, id string) {
m.tasks.Delete(ctx, id)
}
// Tasks lists all tasks
func (m *TaskManager) Tasks(ctx context.Context, all bool) ([]runtime.Task, error) {
return m.tasks.GetAll(ctx, all)
@@ -145,6 +155,10 @@ func (m *TaskManager) loadExistingTasks(ctx context.Context) error {
continue
}
ns := nsd.Name()
// skip hidden directories
if len(ns) > 0 && ns[0] == '.' {
continue
}
log.G(ctx).WithField("namespace", ns).Debug("loading tasks in namespace")
if err := m.loadTasks(namespaces.WithNamespace(ctx, ns)); err != nil {
log.G(ctx).WithField("namespace", ns).WithError(err).Error("loading tasks in namespace")

View File

@@ -19,7 +19,6 @@ package v2
import (
"context"
eventstypes "github.com/containerd/containerd/api/events"
tasktypes "github.com/containerd/containerd/api/types/task"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/runtime"
@@ -114,18 +113,13 @@ func (p *process) CloseIO(ctx context.Context) error {
// Start the process
func (p *process) Start(ctx context.Context) error {
response, err := p.shim.task.Start(ctx, &task.StartRequest{
_, err := p.shim.task.Start(ctx, &task.StartRequest{
ID: p.shim.ID(),
ExecID: p.id,
})
if err != nil {
return errdefs.FromGRPC(err)
}
p.shim.events.Publish(ctx, runtime.TaskExecStartedEventTopic, &eventstypes.TaskExecStarted{
ContainerID: p.shim.ID(),
Pid: response.Pid,
ExecID: p.id,
})
return nil
}

View File

@@ -55,6 +55,10 @@ type Options struct {
CriuPath string `protobuf:"bytes,8,opt,name=criu_path,json=criuPath,proto3" json:"criu_path,omitempty"`
// enable systemd cgroups
SystemdCgroup bool `protobuf:"varint,9,opt,name=systemd_cgroup,json=systemdCgroup,proto3" json:"systemd_cgroup,omitempty"`
// criu image path
CriuImagePath string `protobuf:"bytes,10,opt,name=criu_image_path,json=criuImagePath,proto3" json:"criu_image_path,omitempty"`
// criu work path
CriuWorkPath string `protobuf:"bytes,11,opt,name=criu_work_path,json=criuWorkPath,proto3" json:"criu_work_path,omitempty"`
}
func (m *Options) Reset() { *m = Options{} }
@@ -76,6 +80,10 @@ type CheckpointOptions struct {
EmptyNamespaces []string `protobuf:"bytes,6,rep,name=empty_namespaces,json=emptyNamespaces" json:"empty_namespaces,omitempty"`
// set the cgroups mode, soft, full, strict
CgroupsMode string `protobuf:"bytes,7,opt,name=cgroups_mode,json=cgroupsMode,proto3" json:"cgroups_mode,omitempty"`
// checkpoint image path
ImagePath string `protobuf:"bytes,8,opt,name=image_path,json=imagePath,proto3" json:"image_path,omitempty"`
// checkpoint work path
WorkPath string `protobuf:"bytes,9,opt,name=work_path,json=workPath,proto3" json:"work_path,omitempty"`
}
func (m *CheckpointOptions) Reset() { *m = CheckpointOptions{} }
@@ -175,6 +183,18 @@ func (m *Options) MarshalTo(dAtA []byte) (int, error) {
}
i++
}
if len(m.CriuImagePath) > 0 {
dAtA[i] = 0x52
i++
i = encodeVarintOci(dAtA, i, uint64(len(m.CriuImagePath)))
i += copy(dAtA[i:], m.CriuImagePath)
}
if len(m.CriuWorkPath) > 0 {
dAtA[i] = 0x5a
i++
i = encodeVarintOci(dAtA, i, uint64(len(m.CriuWorkPath)))
i += copy(dAtA[i:], m.CriuWorkPath)
}
return i, nil
}
@@ -264,6 +284,18 @@ func (m *CheckpointOptions) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintOci(dAtA, i, uint64(len(m.CgroupsMode)))
i += copy(dAtA[i:], m.CgroupsMode)
}
if len(m.ImagePath) > 0 {
dAtA[i] = 0x42
i++
i = encodeVarintOci(dAtA, i, uint64(len(m.ImagePath)))
i += copy(dAtA[i:], m.ImagePath)
}
if len(m.WorkPath) > 0 {
dAtA[i] = 0x4a
i++
i = encodeVarintOci(dAtA, i, uint64(len(m.WorkPath)))
i += copy(dAtA[i:], m.WorkPath)
}
return i, nil
}
@@ -334,6 +366,14 @@ func (m *Options) Size() (n int) {
if m.SystemdCgroup {
n += 2
}
l = len(m.CriuImagePath)
if l > 0 {
n += 1 + l + sovOci(uint64(l))
}
l = len(m.CriuWorkPath)
if l > 0 {
n += 1 + l + sovOci(uint64(l))
}
return n
}
@@ -365,6 +405,14 @@ func (m *CheckpointOptions) Size() (n int) {
if l > 0 {
n += 1 + l + sovOci(uint64(l))
}
l = len(m.ImagePath)
if l > 0 {
n += 1 + l + sovOci(uint64(l))
}
l = len(m.WorkPath)
if l > 0 {
n += 1 + l + sovOci(uint64(l))
}
return n
}
@@ -405,6 +453,8 @@ func (this *Options) String() string {
`Root:` + fmt.Sprintf("%v", this.Root) + `,`,
`CriuPath:` + fmt.Sprintf("%v", this.CriuPath) + `,`,
`SystemdCgroup:` + fmt.Sprintf("%v", this.SystemdCgroup) + `,`,
`CriuImagePath:` + fmt.Sprintf("%v", this.CriuImagePath) + `,`,
`CriuWorkPath:` + fmt.Sprintf("%v", this.CriuWorkPath) + `,`,
`}`,
}, "")
return s
@@ -421,6 +471,8 @@ func (this *CheckpointOptions) String() string {
`FileLocks:` + fmt.Sprintf("%v", this.FileLocks) + `,`,
`EmptyNamespaces:` + fmt.Sprintf("%v", this.EmptyNamespaces) + `,`,
`CgroupsMode:` + fmt.Sprintf("%v", this.CgroupsMode) + `,`,
`ImagePath:` + fmt.Sprintf("%v", this.ImagePath) + `,`,
`WorkPath:` + fmt.Sprintf("%v", this.WorkPath) + `,`,
`}`,
}, "")
return s
@@ -686,6 +738,64 @@ func (m *Options) Unmarshal(dAtA []byte) error {
}
}
m.SystemdCgroup = bool(v != 0)
case 10:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CriuImagePath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOci
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthOci
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.CriuImagePath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 11:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field CriuWorkPath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOci
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthOci
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.CriuWorkPath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipOci(dAtA[iNdEx:])
@@ -894,6 +1004,64 @@ func (m *CheckpointOptions) Unmarshal(dAtA []byte) error {
}
m.CgroupsMode = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ImagePath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOci
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthOci
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ImagePath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 9:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field WorkPath", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowOci
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthOci
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.WorkPath = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipOci(dAtA[iNdEx:])
@@ -1104,39 +1272,42 @@ func init() {
}
var fileDescriptorOci = []byte{
// 529 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xcd, 0x6e, 0xd3, 0x4c,
0x14, 0x86, 0xeb, 0xfe, 0x38, 0xf6, 0xf4, 0xe7, 0xfb, 0x18, 0xa8, 0x64, 0x8a, 0x70, 0x43, 0x00,
0x29, 0x6c, 0x12, 0x51, 0xc4, 0x8a, 0x0d, 0x6a, 0x8b, 0x50, 0x05, 0x94, 0xca, 0x50, 0x09, 0x75,
0x33, 0x72, 0xc6, 0x07, 0xe7, 0x28, 0xf1, 0x1c, 0xcb, 0x33, 0x4e, 0x9d, 0x1d, 0xf7, 0xc1, 0x0d,
0x75, 0xc9, 0x92, 0x15, 0xa2, 0xb9, 0x11, 0x90, 0xc7, 0x4e, 0x61, 0xcd, 0xca, 0xef, 0x3c, 0xef,
0xf1, 0x68, 0xe6, 0xd1, 0xb0, 0xc3, 0x14, 0xcd, 0xb8, 0x1c, 0x0d, 0x24, 0x65, 0x43, 0x49, 0xca,
0xc4, 0xa8, 0xa0, 0x48, 0xfe, 0x8e, 0x45, 0xa9, 0x0c, 0x66, 0x30, 0x9c, 0x1d, 0xd4, 0x51, 0x0e,
0x29, 0x37, 0x48, 0x4a, 0x0f, 0x49, 0xe2, 0x20, 0x2f, 0xc8, 0x10, 0xe7, 0x7f, 0xa6, 0x07, 0xf5,
0xc8, 0x60, 0xf6, 0x74, 0xef, 0x4e, 0x4a, 0x29, 0xd9, 0x7a, 0x58, 0xa7, 0x66, 0xb2, 0xf7, 0x75,
0x95, 0x75, 0xde, 0x37, 0xff, 0xf3, 0x1e, 0xdb, 0x56, 0x24, 0x72, 0x9c, 0x91, 0x11, 0x05, 0x91,
0x09, 0x9c, 0xae, 0xd3, 0xf7, 0xa2, 0x4d, 0x45, 0x67, 0x35, 0x8b, 0x88, 0x0c, 0x7f, 0xc4, 0x76,
0x14, 0x09, 0x05, 0x97, 0x62, 0x02, 0xf3, 0x02, 0x55, 0x1a, 0xac, 0xda, 0xa1, 0x2d, 0x45, 0xa7,
0x70, 0xf9, 0xa6, 0x61, 0x7c, 0x9f, 0x6d, 0xea, 0x31, 0x66, 0x42, 0xa6, 0x05, 0x95, 0x79, 0xb0,
0xd6, 0x75, 0xfa, 0x7e, 0xc4, 0x6a, 0x74, 0x64, 0x09, 0xdf, 0x65, 0x2e, 0x92, 0x28, 0x31, 0x09,
0xd6, 0xbb, 0x4e, 0x7f, 0x3b, 0xda, 0x40, 0x3a, 0xc7, 0xa4, 0xc5, 0x29, 0x26, 0xc1, 0xc6, 0x12,
0xbf, 0xc6, 0xa4, 0xde, 0x6e, 0x84, 0x2a, 0x2e, 0xe6, 0x42, 0xc5, 0x19, 0x04, 0x6e, 0xb3, 0x5d,
0x83, 0x4e, 0xe3, 0x0c, 0x38, 0x67, 0xeb, 0xf6, 0xc0, 0x1d, 0xdb, 0xd8, 0xcc, 0xef, 0x31, 0x5f,
0x16, 0x58, 0x8a, 0x3c, 0x36, 0xe3, 0xc0, 0xb3, 0x85, 0x57, 0x83, 0xb3, 0xd8, 0x8c, 0xf9, 0x63,
0xb6, 0xa3, 0xe7, 0xda, 0x40, 0x96, 0x2c, 0xcf, 0xe8, 0xdb, 0x6b, 0x6c, 0xb7, 0xb4, 0x39, 0x66,
0xef, 0x97, 0xc3, 0x6e, 0x1d, 0x8d, 0x41, 0x4e, 0x72, 0x42, 0x65, 0x96, 0x9e, 0x38, 0x5b, 0x87,
0x0a, 0x97, 0x7a, 0x6c, 0xe6, 0x77, 0x99, 0x47, 0x39, 0x28, 0x61, 0x64, 0xde, 0x1a, 0xe9, 0xd4,
0xeb, 0x8f, 0x32, 0xe7, 0x07, 0x6c, 0x17, 0x2a, 0x03, 0x85, 0x8a, 0xa7, 0xa2, 0x54, 0x58, 0x09,
0x4d, 0x72, 0x02, 0x46, 0x5b, 0x2d, 0x5e, 0x74, 0x7b, 0x59, 0x9e, 0x2b, 0xac, 0x3e, 0x34, 0x15,
0xdf, 0x63, 0x9e, 0x81, 0x22, 0x43, 0x15, 0x4f, 0xad, 0x21, 0x2f, 0xba, 0x59, 0xf3, 0xfb, 0x8c,
0x7d, 0xc6, 0x29, 0x88, 0x29, 0xc9, 0x89, 0xb6, 0xa2, 0xbc, 0xc8, 0xaf, 0xc9, 0xdb, 0x1a, 0xf0,
0x27, 0xec, 0x7f, 0xc8, 0x72, 0xd3, 0xb8, 0xd2, 0x79, 0x2c, 0x41, 0x07, 0x6e, 0x77, 0xad, 0xef,
0x47, 0xff, 0x59, 0x7e, 0x7a, 0x83, 0xf9, 0x03, 0xb6, 0xd5, 0xdc, 0x5e, 0x8b, 0x8c, 0x12, 0x68,
0xf5, 0x6d, 0xb6, 0xec, 0x1d, 0x25, 0xd0, 0x7b, 0xce, 0x76, 0xce, 0x0a, 0x92, 0xa0, 0xf5, 0x31,
0x98, 0x18, 0xa7, 0x9a, 0x3f, 0x64, 0x1d, 0xa8, 0x40, 0x0a, 0x4c, 0xac, 0x00, 0xff, 0x90, 0x2d,
0x7e, 0xec, 0xbb, 0xaf, 0x2a, 0x90, 0x27, 0xc7, 0x91, 0x5b, 0x57, 0x27, 0xc9, 0xe1, 0xc5, 0xd5,
0x75, 0xb8, 0xf2, 0xfd, 0x3a, 0x5c, 0xf9, 0xb2, 0x08, 0x9d, 0xab, 0x45, 0xe8, 0x7c, 0x5b, 0x84,
0xce, 0xcf, 0x45, 0xe8, 0x5c, 0xbc, 0xfc, 0xd7, 0xe7, 0xfd, 0xa2, 0xfd, 0x7e, 0x5a, 0x19, 0xb9,
0xf6, 0xed, 0x3e, 0xfb, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x78, 0xf4, 0x16, 0x4e, 0x2b, 0x03, 0x00,
0x00,
// 587 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xcf, 0x6e, 0xd3, 0x40,
0x10, 0x87, 0xeb, 0xfe, 0x49, 0xec, 0x4d, 0x93, 0xc2, 0x42, 0x25, 0xd3, 0x8a, 0x34, 0x94, 0x82,
0xc2, 0x25, 0x11, 0x45, 0x9c, 0xb8, 0xa0, 0xb6, 0x08, 0x55, 0x40, 0xa9, 0x0c, 0x15, 0xa8, 0x97,
0x95, 0xbb, 0x1e, 0x9c, 0x51, 0xe2, 0x1d, 0xcb, 0xbb, 0x69, 0xd2, 0x1b, 0xef, 0xc5, 0x0b, 0xf4,
0xc8, 0x91, 0x13, 0xa2, 0xb9, 0xf1, 0x16, 0x68, 0xd7, 0x4e, 0xdb, 0x33, 0x27, 0xcf, 0x7e, 0xf3,
0xf3, 0x78, 0xfd, 0xad, 0x96, 0xed, 0xa5, 0x68, 0x06, 0xe3, 0xb3, 0x9e, 0xa4, 0xac, 0x2f, 0x49,
0x99, 0x18, 0x15, 0x14, 0xc9, 0xed, 0xb2, 0x18, 0x2b, 0x83, 0x19, 0xf4, 0xcf, 0x77, 0x6d, 0x29,
0xfb, 0x94, 0x1b, 0x24, 0xa5, 0xfb, 0x24, 0xb1, 0x97, 0x17, 0x64, 0x88, 0xf3, 0x9b, 0x74, 0xcf,
0x46, 0x7a, 0xe7, 0xcf, 0x37, 0xee, 0xa7, 0x94, 0x92, 0x6b, 0xf7, 0x6d, 0x55, 0x26, 0xb7, 0xff,
0x2e, 0xb2, 0xfa, 0xc7, 0xf2, 0x7d, 0xbe, 0xcd, 0x9a, 0x8a, 0x44, 0x8e, 0xe7, 0x64, 0x44, 0x41,
0x64, 0x42, 0xaf, 0xe3, 0x75, 0xfd, 0xa8, 0xa1, 0xe8, 0xd8, 0xb2, 0x88, 0xc8, 0xf0, 0x1d, 0xd6,
0x52, 0x24, 0x14, 0x4c, 0xc4, 0x10, 0x2e, 0x0a, 0x54, 0x69, 0xb8, 0xe8, 0x42, 0xab, 0x8a, 0x8e,
0x60, 0xf2, 0xae, 0x64, 0x7c, 0x8b, 0x35, 0xf4, 0x00, 0x33, 0x21, 0xd3, 0x82, 0xc6, 0x79, 0xb8,
0xd4, 0xf1, 0xba, 0x41, 0xc4, 0x2c, 0xda, 0x77, 0x84, 0xaf, 0xb3, 0x1a, 0x92, 0x18, 0x63, 0x12,
0x2e, 0x77, 0xbc, 0x6e, 0x33, 0x5a, 0x41, 0x3a, 0xc1, 0xa4, 0xc2, 0x29, 0x26, 0xe1, 0xca, 0x1c,
0xbf, 0xc5, 0xc4, 0x8e, 0x3b, 0x43, 0x15, 0x17, 0x17, 0x42, 0xc5, 0x19, 0x84, 0xb5, 0x72, 0x5c,
0x89, 0x8e, 0xe2, 0x0c, 0x38, 0x67, 0xcb, 0x6e, 0xc3, 0x75, 0xd7, 0x71, 0x35, 0xdf, 0x64, 0x81,
0x2c, 0x70, 0x2c, 0xf2, 0xd8, 0x0c, 0x42, 0xdf, 0x35, 0x7c, 0x0b, 0x8e, 0x63, 0x33, 0xe0, 0x4f,
0x58, 0x4b, 0x5f, 0x68, 0x03, 0x59, 0x32, 0xdf, 0x63, 0xe0, 0x7e, 0xa3, 0x59, 0xd1, 0x6a, 0x9b,
0x4f, 0xd9, 0x9a, 0x9b, 0x81, 0x59, 0x9c, 0x42, 0x39, 0x89, 0xb9, 0x49, 0x4d, 0x8b, 0x0f, 0x2d,
0x75, 0xe3, 0x76, 0x58, 0xcb, 0xe5, 0x26, 0x54, 0x0c, 0xcb, 0x58, 0xc3, 0xc5, 0x56, 0x2d, 0xfd,
0x42, 0xc5, 0xd0, 0xa6, 0xb6, 0x7f, 0x2c, 0xb2, 0xbb, 0xfb, 0x03, 0x90, 0xc3, 0x9c, 0x50, 0x99,
0xb9, 0x75, 0xce, 0x96, 0x61, 0x8a, 0x73, 0xd9, 0xae, 0xe6, 0x0f, 0x98, 0x4f, 0x39, 0x28, 0x61,
0x64, 0x5e, 0xf9, 0xad, 0xdb, 0xf5, 0x67, 0x99, 0xf3, 0x5d, 0xb6, 0x0e, 0x53, 0x03, 0x85, 0x8a,
0x47, 0x62, 0xac, 0x70, 0x2a, 0x34, 0xc9, 0x21, 0x18, 0xed, 0x24, 0xfb, 0xd1, 0xbd, 0x79, 0xf3,
0x44, 0xe1, 0xf4, 0x53, 0xd9, 0xe2, 0x1b, 0xcc, 0x37, 0x50, 0x64, 0xa8, 0xe2, 0x91, 0xf3, 0xed,
0x47, 0xd7, 0x6b, 0xfe, 0x90, 0xb1, 0x6f, 0x38, 0x02, 0x31, 0x22, 0x39, 0xd4, 0x4e, 0xbb, 0x1f,
0x05, 0x96, 0xbc, 0xb7, 0x80, 0x3f, 0x63, 0x77, 0x20, 0xcb, 0x4d, 0x69, 0x5e, 0xe7, 0xb1, 0x04,
0x1d, 0xd6, 0x3a, 0x4b, 0xdd, 0x20, 0x5a, 0x73, 0xfc, 0xe8, 0x1a, 0xf3, 0x47, 0x6c, 0xb5, 0x74,
0xa9, 0x45, 0x46, 0x09, 0x54, 0x87, 0xd1, 0xa8, 0xd8, 0x07, 0x4a, 0xc0, 0x7e, 0xec, 0x96, 0xca,
0xf2, 0x50, 0x02, 0xbc, 0xd6, 0xb8, 0xc9, 0x82, 0x1b, 0x83, 0x41, 0x79, 0x64, 0x93, 0xb9, 0xbd,
0x97, 0xac, 0x75, 0x5c, 0x90, 0x04, 0xad, 0x0f, 0xc0, 0xc4, 0x38, 0xd2, 0xfc, 0x31, 0xab, 0xc3,
0x14, 0xa4, 0xc0, 0xc4, 0xc9, 0x0b, 0xf6, 0xd8, 0xec, 0xf7, 0x56, 0xed, 0xcd, 0x14, 0xe4, 0xe1,
0x41, 0x54, 0xb3, 0xad, 0xc3, 0x64, 0xef, 0xf4, 0xf2, 0xaa, 0xbd, 0xf0, 0xeb, 0xaa, 0xbd, 0xf0,
0x7d, 0xd6, 0xf6, 0x2e, 0x67, 0x6d, 0xef, 0xe7, 0xac, 0xed, 0xfd, 0x99, 0xb5, 0xbd, 0xd3, 0xd7,
0xff, 0x7b, 0xd1, 0x5e, 0x55, 0xcf, 0xaf, 0x0b, 0x67, 0x35, 0x77, 0x8b, 0x5e, 0xfc, 0x0b, 0x00,
0x00, 0xff, 0xff, 0x90, 0x50, 0x79, 0xf2, 0xb5, 0x03, 0x00, 0x00,
}

View File

@@ -25,6 +25,10 @@ message Options {
string criu_path = 8;
// enable systemd cgroups
bool systemd_cgroup = 9;
// criu image path
string criu_image_path = 10;
// criu work path
string criu_work_path = 11;
}
message CheckpointOptions {
@@ -42,6 +46,10 @@ message CheckpointOptions {
repeated string empty_namespaces = 6;
// set the cgroups mode, soft, full, strict
string cgroups_mode = 7;
// checkpoint image path
string image_path = 8;
// checkpoint work path
string work_path = 9;
}
message ProcessDetails {

View File

@@ -39,15 +39,18 @@ type Options_DebugType int32
const (
Options_NPIPE Options_DebugType = 0
Options_FILE Options_DebugType = 1
Options_ETW Options_DebugType = 2
)
var Options_DebugType_name = map[int32]string{
0: "NPIPE",
1: "FILE",
2: "ETW",
}
var Options_DebugType_value = map[string]int32{
"NPIPE": 0,
"FILE": 1,
"ETW": 2,
}
func (x Options_DebugType) String() string {
@@ -55,6 +58,29 @@ func (x Options_DebugType) String() string {
}
func (Options_DebugType) EnumDescriptor() ([]byte, []int) { return fileDescriptorRunhcs, []int{0, 0} }
type Options_SandboxIsolation int32
const (
Options_PROCESS Options_SandboxIsolation = 0
Options_HYPERVISOR Options_SandboxIsolation = 1
)
var Options_SandboxIsolation_name = map[int32]string{
0: "PROCESS",
1: "HYPERVISOR",
}
var Options_SandboxIsolation_value = map[string]int32{
"PROCESS": 0,
"HYPERVISOR": 1,
}
func (x Options_SandboxIsolation) String() string {
return proto.EnumName(Options_SandboxIsolation_name, int32(x))
}
func (Options_SandboxIsolation) EnumDescriptor() ([]byte, []int) {
return fileDescriptorRunhcs, []int{0, 1}
}
type Options struct {
// enable debug tracing
Debug bool `protobuf:"varint,1,opt,name=debug,proto3" json:"debug,omitempty"`
@@ -62,6 +88,17 @@ type Options struct {
DebugType Options_DebugType `protobuf:"varint,2,opt,name=debug_type,json=debugType,proto3,enum=containerd.runhcs.v1.Options_DebugType" json:"debug_type,omitempty"`
// registry key root for storage of the runhcs container state
RegistryRoot string `protobuf:"bytes,3,opt,name=registry_root,json=registryRoot,proto3" json:"registry_root,omitempty"`
// sandbox_image is the image to use for the sandbox that matches the
// sandbox_platform.
SandboxImage string `protobuf:"bytes,4,opt,name=sandbox_image,json=sandboxImage,proto3" json:"sandbox_image,omitempty"`
// sandbox_platform is a CRI setting that specifies the platform
// architecture for all sandbox's in this runtime. Values are
// 'windows/amd64' and 'linux/amd64'.
SandboxPlatform string `protobuf:"bytes,5,opt,name=sandbox_platform,json=sandboxPlatform,proto3" json:"sandbox_platform,omitempty"`
// sandbox_isolation is a CRI setting that specifies the isolation level of
// the sandbox. For Windows runtime PROCESS and HYPERVISOR are valid. For
// LCOW only HYPERVISOR is valid and default if omitted.
SandboxIsolation Options_SandboxIsolation `protobuf:"varint,6,opt,name=sandbox_isolation,json=sandboxIsolation,proto3,enum=containerd.runhcs.v1.Options_SandboxIsolation" json:"sandbox_isolation,omitempty"`
}
func (m *Options) Reset() { *m = Options{} }
@@ -71,6 +108,7 @@ func (*Options) Descriptor() ([]byte, []int) { return fileDescriptorRunhcs, []in
func init() {
proto.RegisterType((*Options)(nil), "containerd.runhcs.v1.Options")
proto.RegisterEnum("containerd.runhcs.v1.Options_DebugType", Options_DebugType_name, Options_DebugType_value)
proto.RegisterEnum("containerd.runhcs.v1.Options_SandboxIsolation", Options_SandboxIsolation_name, Options_SandboxIsolation_value)
}
func (m *Options) Marshal() (dAtA []byte, err error) {
size := m.Size()
@@ -108,6 +146,23 @@ func (m *Options) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintRunhcs(dAtA, i, uint64(len(m.RegistryRoot)))
i += copy(dAtA[i:], m.RegistryRoot)
}
if len(m.SandboxImage) > 0 {
dAtA[i] = 0x22
i++
i = encodeVarintRunhcs(dAtA, i, uint64(len(m.SandboxImage)))
i += copy(dAtA[i:], m.SandboxImage)
}
if len(m.SandboxPlatform) > 0 {
dAtA[i] = 0x2a
i++
i = encodeVarintRunhcs(dAtA, i, uint64(len(m.SandboxPlatform)))
i += copy(dAtA[i:], m.SandboxPlatform)
}
if m.SandboxIsolation != 0 {
dAtA[i] = 0x30
i++
i = encodeVarintRunhcs(dAtA, i, uint64(m.SandboxIsolation))
}
return i, nil
}
@@ -133,6 +188,17 @@ func (m *Options) Size() (n int) {
if l > 0 {
n += 1 + l + sovRunhcs(uint64(l))
}
l = len(m.SandboxImage)
if l > 0 {
n += 1 + l + sovRunhcs(uint64(l))
}
l = len(m.SandboxPlatform)
if l > 0 {
n += 1 + l + sovRunhcs(uint64(l))
}
if m.SandboxIsolation != 0 {
n += 1 + sovRunhcs(uint64(m.SandboxIsolation))
}
return n
}
@@ -157,6 +223,9 @@ func (this *Options) String() string {
`Debug:` + fmt.Sprintf("%v", this.Debug) + `,`,
`DebugType:` + fmt.Sprintf("%v", this.DebugType) + `,`,
`RegistryRoot:` + fmt.Sprintf("%v", this.RegistryRoot) + `,`,
`SandboxImage:` + fmt.Sprintf("%v", this.SandboxImage) + `,`,
`SandboxPlatform:` + fmt.Sprintf("%v", this.SandboxPlatform) + `,`,
`SandboxIsolation:` + fmt.Sprintf("%v", this.SandboxIsolation) + `,`,
`}`,
}, "")
return s
@@ -266,6 +335,83 @@ func (m *Options) Unmarshal(dAtA []byte) error {
}
m.RegistryRoot = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field SandboxImage", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunhcs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRunhcs
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.SandboxImage = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field SandboxPlatform", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunhcs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRunhcs
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.SandboxPlatform = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 6:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field SandboxIsolation", wireType)
}
m.SandboxIsolation = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRunhcs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.SandboxIsolation |= (Options_SandboxIsolation(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipRunhcs(dAtA[iNdEx:])
@@ -397,22 +543,29 @@ func init() {
}
var fileDescriptorRunhcs = []byte{
// 265 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x72, 0x4f, 0xcf, 0x2c, 0xc9,
0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d,
0x4a, 0x41, 0x66, 0x16, 0x95, 0xe6, 0x95, 0x64, 0xe6, 0xa6, 0xea, 0x97, 0x19, 0x81, 0x98, 0x19,
0xc9, 0xc5, 0xfa, 0xf9, 0x05, 0x25, 0x99, 0xf9, 0x79, 0xc5, 0x50, 0xae, 0x5e, 0x41, 0x51, 0x7e,
0x49, 0xbe, 0x90, 0x08, 0x42, 0x8b, 0x1e, 0x54, 0xa2, 0xcc, 0x50, 0x4a, 0x24, 0x3d, 0x3f, 0x3d,
0x1f, 0xac, 0x40, 0x1f, 0xc4, 0x82, 0xa8, 0x55, 0x5a, 0xc7, 0xc8, 0xc5, 0xee, 0x0f, 0x31, 0x44,
0x48, 0x84, 0x8b, 0x35, 0x25, 0x35, 0xa9, 0x34, 0x5d, 0x82, 0x51, 0x81, 0x51, 0x83, 0x23, 0x08,
0xc2, 0x11, 0x72, 0xe3, 0xe2, 0x02, 0x33, 0xe2, 0x4b, 0x2a, 0x0b, 0x52, 0x25, 0x98, 0x14, 0x18,
0x35, 0xf8, 0x8c, 0xd4, 0xf5, 0xb0, 0x59, 0xa1, 0x07, 0x35, 0x48, 0xcf, 0x05, 0xa4, 0x3e, 0xa4,
0xb2, 0x20, 0x35, 0x88, 0x33, 0x05, 0xc6, 0x14, 0x52, 0xe6, 0xe2, 0x2d, 0x4a, 0x4d, 0xcf, 0x2c,
0x2e, 0x29, 0xaa, 0x8c, 0x2f, 0xca, 0xcf, 0x2f, 0x91, 0x60, 0x56, 0x60, 0xd4, 0xe0, 0x0c, 0xe2,
0x81, 0x09, 0x06, 0xe5, 0xe7, 0x97, 0x28, 0x29, 0x70, 0x71, 0xc2, 0x35, 0x0b, 0x71, 0x72, 0xb1,
0xfa, 0x05, 0x78, 0x06, 0xb8, 0x0a, 0x30, 0x08, 0x71, 0x70, 0xb1, 0xb8, 0x79, 0xfa, 0xb8, 0x0a,
0x30, 0x3a, 0xc5, 0x9c, 0x78, 0x28, 0xc7, 0x70, 0xe3, 0xa1, 0x1c, 0x43, 0xc3, 0x23, 0x39, 0xc6,
0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x31, 0xca, 0x89, 0xfc,
0xf0, 0xb3, 0x86, 0xd2, 0x11, 0x0c, 0x49, 0x6c, 0xe0, 0x70, 0x31, 0x06, 0x04, 0x00, 0x00, 0xff,
0xff, 0x91, 0x7a, 0xda, 0xa5, 0x8e, 0x01, 0x00, 0x00,
// 383 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xcd, 0x6e, 0x9b, 0x40,
0x14, 0x85, 0x19, 0xff, 0x73, 0xdb, 0xba, 0x74, 0xe4, 0x05, 0xea, 0x02, 0x59, 0xee, 0xa2, 0xf6,
0x06, 0x54, 0x77, 0xd9, 0x9d, 0x5b, 0xdc, 0x22, 0x55, 0x35, 0x1a, 0xac, 0xb6, 0xf9, 0x91, 0x2c,
0x30, 0x04, 0x23, 0x19, 0x06, 0xc1, 0xd8, 0x8a, 0x77, 0x79, 0x89, 0xbc, 0x93, 0x97, 0x59, 0x66,
0x19, 0xf3, 0x24, 0x11, 0x30, 0x38, 0x51, 0x14, 0x65, 0x91, 0x15, 0xe7, 0x1e, 0xbe, 0x7b, 0xee,
0x5c, 0xcd, 0xc0, 0x4f, 0x3f, 0x60, 0xab, 0x8d, 0xa3, 0x2e, 0x69, 0xa8, 0x2d, 0x69, 0xc4, 0xec,
0x20, 0xf2, 0x12, 0xf7, 0xb1, 0x4c, 0x36, 0x11, 0x0b, 0x42, 0x4f, 0xdb, 0x8e, 0x73, 0xb9, 0x5a,
0xa6, 0x1a, 0x8d, 0x59, 0x40, 0xa3, 0x94, 0x97, 0x6a, 0x9c, 0x50, 0x46, 0x71, 0xef, 0xa1, 0x45,
0xe5, 0x3f, 0xb6, 0x5f, 0x3e, 0xf6, 0x7c, 0xea, 0xd3, 0x02, 0xd0, 0x72, 0x55, 0xb2, 0x83, 0xeb,
0x3a, 0xb4, 0x67, 0x65, 0x08, 0xee, 0x41, 0xd3, 0xf5, 0x9c, 0x8d, 0x2f, 0xa3, 0x3e, 0x1a, 0x76,
0x48, 0x59, 0xe0, 0x29, 0x40, 0x21, 0x16, 0x6c, 0x17, 0x7b, 0x72, 0xad, 0x8f, 0x86, 0xdd, 0xf1,
0x67, 0xf5, 0xb9, 0x11, 0x2a, 0x0f, 0x52, 0x7f, 0xe4, 0xfc, 0x7c, 0x17, 0x7b, 0x44, 0x74, 0x2b,
0x89, 0x3f, 0xc1, 0xbb, 0xc4, 0xf3, 0x83, 0x94, 0x25, 0xbb, 0x45, 0x42, 0x29, 0x93, 0xeb, 0x7d,
0x34, 0x14, 0xc9, 0xdb, 0xca, 0x24, 0x94, 0xb2, 0x1c, 0x4a, 0xed, 0xc8, 0x75, 0xe8, 0xe5, 0x22,
0x08, 0x6d, 0xdf, 0x93, 0x1b, 0x25, 0xc4, 0x4d, 0x23, 0xf7, 0xf0, 0x08, 0xa4, 0x0a, 0x8a, 0xd7,
0x36, 0xbb, 0xa0, 0x49, 0x28, 0x37, 0x0b, 0xee, 0x3d, 0xf7, 0x4d, 0x6e, 0xe3, 0x33, 0xf8, 0x70,
0xcc, 0x4b, 0xe9, 0xda, 0xce, 0xcf, 0x27, 0xb7, 0x8a, 0x1d, 0xd4, 0x97, 0x77, 0xb0, 0xf8, 0xc4,
0xaa, 0x8b, 0x54, 0x33, 0x8f, 0xce, 0x60, 0x04, 0xe2, 0x71, 0x53, 0x2c, 0x42, 0xf3, 0x8f, 0x69,
0x98, 0xba, 0x24, 0xe0, 0x0e, 0x34, 0xa6, 0xc6, 0x6f, 0x5d, 0x42, 0xb8, 0x0d, 0x75, 0x7d, 0xfe,
0x4f, 0xaa, 0x0d, 0x34, 0x90, 0x9e, 0x06, 0xe2, 0x37, 0xd0, 0x36, 0xc9, 0xec, 0xbb, 0x6e, 0x59,
0x92, 0x80, 0xbb, 0x00, 0xbf, 0x4e, 0x4c, 0x9d, 0xfc, 0x35, 0xac, 0x19, 0x91, 0xd0, 0xe4, 0x7c,
0x7f, 0x50, 0x84, 0xdb, 0x83, 0x22, 0x5c, 0x65, 0x0a, 0xda, 0x67, 0x0a, 0xba, 0xc9, 0x14, 0x74,
0x97, 0x29, 0xe8, 0x74, 0xf2, 0xfa, 0x67, 0xf2, 0x8d, 0x7f, 0xff, 0x0b, 0x4e, 0xab, 0xb8, 0xfe,
0xaf, 0xf7, 0x01, 0x00, 0x00, 0xff, 0xff, 0xe8, 0xe0, 0x0a, 0x7a, 0x75, 0x02, 0x00, 0x00,
}

View File

@@ -9,12 +9,35 @@ option go_package = "github.com/containerd/containerd/runtime/v2/runhcs/options;
message Options {
// enable debug tracing
bool debug = 1;
enum DebugType {
NPIPE = 0;
FILE = 1;
ETW = 2;
}
// debug tracing output type
DebugType debug_type = 2;
// registry key root for storage of the runhcs container state
string registry_root = 3;
// sandbox_image is the image to use for the sandbox that matches the
// sandbox_platform.
string sandbox_image = 4;
// sandbox_platform is a CRI setting that specifies the platform
// architecture for all sandbox's in this runtime. Values are
// 'windows/amd64' and 'linux/amd64'.
string sandbox_platform = 5;
enum SandboxIsolation {
PROCESS = 0;
HYPERVISOR = 1;
}
// sandbox_isolation is a CRI setting that specifies the isolation level of
// the sandbox. For Windows runtime PROCESS and HYPERVISOR are valid. For
// LCOW only HYPERVISOR is valid and default if omitted.
SandboxIsolation sandbox_isolation = 6;
}

View File

@@ -24,7 +24,6 @@ import (
"path/filepath"
"time"
eventstypes "github.com/containerd/containerd/api/events"
"github.com/containerd/containerd/api/types"
tasktypes "github.com/containerd/containerd/api/types/task"
"github.com/containerd/containerd/errdefs"
@@ -112,7 +111,7 @@ func (s *shim) Shutdown(ctx context.Context) error {
_, err := s.task.Shutdown(ctx, &task.ShutdownRequest{
ID: s.ID(),
})
if err != nil && err != ttrpc.ErrClosed {
if err != nil && errors.Cause(err) != ttrpc.ErrClosed {
return errdefs.FromGRPC(err)
}
return nil
@@ -163,12 +162,6 @@ func (s *shim) Delete(ctx context.Context) (*runtime.Exit, error) {
// remove self from the runtime task list
// this seems dirty but it cleans up the API across runtimes, tasks, and the service
s.rtTasks.Delete(ctx, s.ID())
s.events.Publish(ctx, runtime.TaskDeleteEventTopic, &eventstypes.TaskDelete{
ContainerID: s.ID(),
ExitStatus: response.ExitStatus,
ExitedAt: response.ExitedAt,
Pid: response.Pid,
})
return &runtime.Exit{
Status: response.ExitStatus,
Timestamp: response.ExitedAt,
@@ -212,9 +205,6 @@ func (s *shim) Pause(ctx context.Context) error {
}); err != nil {
return errdefs.FromGRPC(err)
}
s.events.Publish(ctx, runtime.TaskPausedEventTopic, &eventstypes.TaskPaused{
ContainerID: s.ID(),
})
return nil
}
@@ -224,9 +214,6 @@ func (s *shim) Resume(ctx context.Context) error {
}); err != nil {
return errdefs.FromGRPC(err)
}
s.events.Publish(ctx, runtime.TaskResumedEventTopic, &eventstypes.TaskResumed{
ContainerID: s.ID(),
})
return nil
}
@@ -238,10 +225,6 @@ func (s *shim) Start(ctx context.Context) error {
return errdefs.FromGRPC(err)
}
s.taskPid = int(response.Pid)
s.events.Publish(ctx, runtime.TaskStartEventTopic, &eventstypes.TaskStart{
ContainerID: s.ID(),
Pid: uint32(s.taskPid),
})
return nil
}
@@ -340,9 +323,6 @@ func (s *shim) Checkpoint(ctx context.Context, path string, options *ptypes.Any)
if _, err := s.task.Checkpoint(ctx, request); err != nil {
return errdefs.FromGRPC(err)
}
s.events.Publish(ctx, runtime.TaskCheckpointedEventTopic, &eventstypes.TaskCheckpointed{
ContainerID: s.ID(),
})
return nil
}

View File

@@ -62,6 +62,17 @@ type Opts struct {
Debug bool
}
// BinaryOpts allows the configuration of a shims binary setup
type BinaryOpts func(*Config)
// Config of shim binary options provided by shim implementations
type Config struct {
// NoSubreaper disables setting the shim as a child subreaper
NoSubreaper bool
// NoReaper disables the shim binary from reaping any child process implicitly
NoReaper bool
}
var (
debugFlag bool
idFlag string
@@ -118,27 +129,34 @@ func setLogger(ctx context.Context, id string) error {
}
// Run initializes and runs a shim server
func Run(id string, initFunc Init) {
if err := run(id, initFunc); err != nil {
func Run(id string, initFunc Init, opts ...BinaryOpts) {
var config Config
for _, o := range opts {
o(&config)
}
if err := run(id, initFunc, config); err != nil {
fmt.Fprintf(os.Stderr, "%s: %s\n", id, err)
os.Exit(1)
}
}
func run(id string, initFunc Init) error {
func run(id string, initFunc Init, config Config) error {
parseFlags()
setRuntime()
signals, err := setupSignals()
signals, err := setupSignals(config)
if err != nil {
return err
}
if err := subreaper(); err != nil {
return err
if !config.NoSubreaper {
if err := subreaper(); err != nil {
return err
}
}
publisher := &remoteEventsPublisher{
address: addressFlag,
containerdBinaryPath: containerdBinaryFlag,
noReaper: config.NoReaper,
}
if namespaceFlag == "" {
return fmt.Errorf("shim namespace cannot be empty")
@@ -266,4 +284,5 @@ func dumpStacks(logger *logrus.Entry) {
type remoteEventsPublisher struct {
address string
containerdBinaryPath string
noReaper bool
}

View File

@@ -0,0 +1,29 @@
// +build freebsd
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package shim
import "github.com/containerd/ttrpc"
func newServer() (*ttrpc.Server, error) {
return ttrpc.NewServer()
}
func subreaper() error {
return nil
}

View File

@@ -39,9 +39,13 @@ import (
// setupSignals creates a new signal handler for all signals and sets the shim as a
// sub-reaper so that the container processes are reparented
func setupSignals() (chan os.Signal, error) {
func setupSignals(config Config) (chan os.Signal, error) {
signals := make(chan os.Signal, 32)
signal.Notify(signals, unix.SIGTERM, unix.SIGINT, unix.SIGCHLD, unix.SIGPIPE)
smp := []os.Signal{unix.SIGTERM, unix.SIGINT, unix.SIGPIPE}
if !config.NoReaper {
smp = append(smp, unix.SIGCHLD)
}
signal.Notify(signals, smp...)
return signals, nil
}
@@ -72,9 +76,9 @@ func serveListener(path string) (net.Listener, error) {
func handleSignals(logger *logrus.Entry, signals chan os.Signal) error {
logger.Info("starting signal loop")
for {
select {
case s := <-signals:
for s := range signals {
switch s {
case unix.SIGCHLD:
if err := Reap(); err != nil {
@@ -102,6 +106,15 @@ func (l *remoteEventsPublisher) Publish(ctx context.Context, topic string, event
}
cmd := exec.CommandContext(ctx, l.containerdBinaryPath, "--address", l.address, "publish", "--topic", topic, "--namespace", ns)
cmd.Stdin = bytes.NewReader(data)
if l.noReaper {
if err := cmd.Start(); err != nil {
return err
}
if err := cmd.Wait(); err != nil {
return errors.Wrap(err, "failed to publish event")
}
return nil
}
c, err := Default.Start(cmd)
if err != nil {
return err

View File

@@ -40,7 +40,7 @@ import (
)
// setupSignals creates a new signal handler for all signals
func setupSignals() (chan os.Signal, error) {
func setupSignals(config Config) (chan os.Signal, error) {
signals := make(chan os.Signal, 32)
return signals, nil
}
@@ -108,12 +108,12 @@ func serveListener(path string) (net.Listener, error) {
func handleSignals(logger *logrus.Entry, signals chan os.Signal) error {
logger.Info("starting signal loop")
for {
select {
case s := <-signals:
for s := range signals {
switch s {
case os.Interrupt:
break
return nil
}
}
}

View File

@@ -31,8 +31,6 @@ import (
"github.com/pkg/errors"
)
const shimBinaryFormat = "containerd-shim-%s-%s"
var runtimePaths sync.Map
// Command returns the shim command with the provided args and configuration
@@ -65,7 +63,19 @@ func Command(ctx context.Context, runtime, containerdAddress, path string, cmdAr
if cmdPath, lerr = exec.LookPath(name); lerr != nil {
if eerr, ok := lerr.(*exec.Error); ok {
if eerr.Err == exec.ErrNotFound {
return nil, errors.Wrapf(os.ErrNotExist, "runtime %q binary not installed %q", runtime, name)
// LookPath only finds current directory matches based on
// the callers current directory but the caller is not
// likely in the same directory as the containerd
// executables. Instead match the calling binaries path
// (containerd) and see if they are side by side. If so
// execute the shim found there.
testPath := filepath.Join(filepath.Dir(self), name)
if _, serr := os.Stat(testPath); serr == nil {
cmdPath = testPath
}
if cmdPath == "" {
return nil, errors.Wrapf(os.ErrNotExist, "runtime %q binary not installed %q", runtime, name)
}
}
}
}

View File

@@ -31,6 +31,8 @@ import (
"github.com/pkg/errors"
)
const shimBinaryFormat = "containerd-shim-%s-%s"
func getSysProcAttr() *syscall.SysProcAttr {
return &syscall.SysProcAttr{
Setpgid: true,

View File

@@ -29,6 +29,8 @@ import (
"github.com/pkg/errors"
)
const shimBinaryFormat = "containerd-shim-%s-%s.exe"
func getSysProcAttr() *syscall.SysProcAttr {
return nil
}
@@ -54,7 +56,7 @@ func AnonDialer(address string, timeout time.Duration) (net.Conn, error) {
timedOutError := errors.Errorf("timed out waiting for npipe %s", address)
start := time.Now()
for {
remaining := timeout - time.Now().Sub(start)
remaining := timeout - time.Since(start)
if remaining <= 0 {
lastError = timedOutError
break
@@ -71,7 +73,7 @@ func AnonDialer(address string, timeout time.Duration) (net.Conn, error) {
// serve it within 5 seconds. We use the passed in timeout for the
// `DialPipe` timeout if the pipe exists however to give the pipe time
// to `Accept` the connection.
if time.Now().Sub(start) >= 5*time.Second {
if time.Since(start) >= 5*time.Second {
lastError = timedOutError
break
}

View File

@@ -28,5 +28,5 @@ import (
)
func openShimLog(ctx context.Context, bundle *Bundle) (io.ReadCloser, error) {
return fifo.OpenFifo(ctx, filepath.Join(bundle.Path, "log"), unix.O_RDONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
return fifo.OpenFifo(ctx, filepath.Join(bundle.Path, "log"), unix.O_RDWR|unix.O_CREAT, 0700)
}

View File

@@ -147,9 +147,7 @@ func (l *local) Update(ctx context.Context, req *api.UpdateContainerRequest, _ .
if err := l.withStoreUpdate(ctx, func(ctx context.Context, store containers.Store) error {
var fieldpaths []string
if req.UpdateMask != nil && len(req.UpdateMask.Paths) > 0 {
for _, path := range req.UpdateMask.Paths {
fieldpaths = append(fieldpaths, path)
}
fieldpaths = append(fieldpaths, req.UpdateMask.Paths...)
}
updated, err := store.Update(ctx, container, fieldpaths...)

View File

@@ -94,7 +94,6 @@ func (s *service) ListStream(req *api.ListContainersRequest, stream api.Containe
}
}
}
return nil
}
func (s *service) Create(ctx context.Context, req *api.CreateContainerRequest) (*api.CreateContainerResponse, error) {

View File

@@ -137,9 +137,7 @@ func (l *local) Update(ctx context.Context, req *imagesapi.UpdateImageRequest, _
)
if req.UpdateMask != nil && len(req.UpdateMask.Paths) > 0 {
for _, path := range req.UpdateMask.Paths {
fieldpaths = append(fieldpaths, path)
}
fieldpaths = append(fieldpaths, req.UpdateMask.Paths...)
}
updated, err := l.store.Update(ctx, image, fieldpaths...)

View File

@@ -83,6 +83,44 @@ type ProxyPlugin struct {
Address string `toml:"address"`
}
// BoltConfig defines the configuration values for the bolt plugin, which is
// loaded here, rather than back registered in the metadata package.
type BoltConfig struct {
// ContentSharingPolicy sets the sharing policy for content between
// namespaces.
//
// The default mode "shared" will make blobs available in all
// namespaces once it is pulled into any namespace. The blob will be pulled
// into the namespace if a writer is opened with the "Expected" digest that
// is already present in the backend.
//
// The alternative mode, "isolated" requires that clients prove they have
// access to the content by providing all of the content to the ingest
// before the blob is added to the namespace.
//
// Both modes share backing data, while "shared" will reduce total
// bandwidth across namespaces, at the cost of allowing access to any blob
// just by knowing its digest.
ContentSharingPolicy string `toml:"content_sharing_policy"`
}
const (
// SharingPolicyShared represents the "shared" sharing policy
SharingPolicyShared = "shared"
// SharingPolicyIsolated represents the "isolated" sharing policy
SharingPolicyIsolated = "isolated"
)
// Validate validates if BoltConfig is valid
func (bc *BoltConfig) Validate() error {
switch bc.ContentSharingPolicy {
case SharingPolicyShared, SharingPolicyIsolated:
return nil
default:
return errors.Wrapf(errdefs.ErrInvalidArgument, "unknown policy: %s", bc.ContentSharingPolicy)
}
}
// Decode unmarshals a plugin specific configuration by plugin id
func (c *Config) Decode(id string, v interface{}) (interface{}, error) {
data, ok := c.Plugins[id]

View File

@@ -238,6 +238,9 @@ func LoadPlugins(ctx context.Context, config *srvconfig.Config) ([]*plugin.Regis
plugin.ContentPlugin,
plugin.SnapshotPlugin,
},
Config: &srvconfig.BoltConfig{
ContentSharingPolicy: srvconfig.SharingPolicyShared,
},
InitFn: func(ic *plugin.InitContext) (interface{}, error) {
if err := os.MkdirAll(ic.Root, 0711); err != nil {
return nil, err
@@ -265,6 +268,22 @@ func LoadPlugins(ctx context.Context, config *srvconfig.Config) ([]*plugin.Regis
snapshotters[name] = sn.(snapshots.Snapshotter)
}
shared := true
ic.Meta.Exports["policy"] = srvconfig.SharingPolicyShared
if cfg, ok := ic.Config.(*srvconfig.BoltConfig); ok {
if cfg.ContentSharingPolicy != "" {
if err := cfg.Validate(); err != nil {
return nil, err
}
if cfg.ContentSharingPolicy == srvconfig.SharingPolicyIsolated {
ic.Meta.Exports["policy"] = srvconfig.SharingPolicyIsolated
shared = false
}
log.L.WithField("policy", cfg.ContentSharingPolicy).Info("metadata content store policy set")
}
}
path := filepath.Join(ic.Root, "meta.db")
ic.Meta.Exports["path"] = path
@@ -272,7 +291,12 @@ func LoadPlugins(ctx context.Context, config *srvconfig.Config) ([]*plugin.Regis
if err != nil {
return nil, err
}
mdb := metadata.NewDB(db, cs.(content.Store), snapshotters)
var dbopts []metadata.DBOpt
if !shared {
dbopts = append(dbopts, metadata.WithPolicyIsolated)
}
mdb := metadata.NewDB(db, cs.(content.Store), snapshotters, dbopts...)
if err := mdb.Init(ic.Context); err != nil {
return nil, err
}

View File

@@ -41,7 +41,9 @@ import (
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/runtime"
"github.com/containerd/containerd/runtime/linux/runctypes"
"github.com/containerd/containerd/runtime/v2"
"github.com/containerd/containerd/runtime/v2/runc/options"
"github.com/containerd/containerd/services"
"github.com/containerd/typeurl"
ptypes "github.com/gogo/protobuf/types"
@@ -123,11 +125,16 @@ type local struct {
}
func (l *local) Create(ctx context.Context, r *api.CreateTaskRequest, _ ...grpc.CallOption) (*api.CreateTaskResponse, error) {
var (
checkpointPath string
err error
)
if r.Checkpoint != nil {
container, err := l.getContainer(ctx, r.ContainerID)
if err != nil {
return nil, errdefs.ToGRPC(err)
}
checkpointPath, err := getRestorePath(container.Runtime.Name, r.Options)
if err != nil {
return nil, err
}
// jump get checkpointPath from checkpoint image
if checkpointPath != "" && r.Checkpoint != nil {
checkpointPath, err = ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "ctrd-checkpoint")
if err != nil {
return nil, err
@@ -149,10 +156,6 @@ func (l *local) Create(ctx context.Context, r *api.CreateTaskRequest, _ ...grpc.
return nil, err
}
}
container, err := l.getContainer(ctx, r.ContainerID)
if err != nil {
return nil, errdefs.ToGRPC(err)
}
opts := runtime.CreateOpts{
Spec: container.Spec,
IO: runtime.IO{
@@ -478,14 +481,27 @@ func (l *local) Checkpoint(ctx context.Context, r *api.CheckpointTaskRequest, _
if err != nil {
return nil, err
}
image, err := ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "ctd-checkpoint")
image, err := getCheckpointPath(container.Runtime.Name, r.Options)
if err != nil {
return nil, errdefs.ToGRPC(err)
return nil, err
}
checkpointImageExists := false
if image == "" {
checkpointImageExists = true
image, err = ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "ctd-checkpoint")
if err != nil {
return nil, errdefs.ToGRPC(err)
}
defer os.RemoveAll(image)
}
defer os.RemoveAll(image)
if err := t.Checkpoint(ctx, image, r.Options); err != nil {
return nil, errdefs.ToGRPC(err)
}
// do not commit checkpoint image if checkpoint ImagePath is passed,
// return if checkpointImageExists is false
if !checkpointImageExists {
return &api.CheckpointTaskResponse{}, nil
}
// write checkpoint to the content store
tar := archive.Diff(ctx, "", image)
cp, err := l.writeContent(ctx, images.MediaTypeContainerd1Checkpoint, image, tar)
@@ -663,3 +679,71 @@ func (l *local) allRuntimes() (o []runtime.PlatformRuntime) {
o = append(o, l.v2Runtime)
return o
}
// getCheckpointPath only suitable for runc runtime now
func getCheckpointPath(runtime string, option *ptypes.Any) (string, error) {
if option == nil {
return "", nil
}
var checkpointPath string
switch runtime {
case "io.containerd.runc.v1":
v, err := typeurl.UnmarshalAny(option)
if err != nil {
return "", err
}
opts, ok := v.(*options.CheckpointOptions)
if !ok {
return "", fmt.Errorf("invalid task checkpoint option for %s", runtime)
}
checkpointPath = opts.ImagePath
case "io.containerd.runtime.v1.linux":
v, err := typeurl.UnmarshalAny(option)
if err != nil {
return "", err
}
opts, ok := v.(*runctypes.CheckpointOptions)
if !ok {
return "", fmt.Errorf("invalid task checkpoint option for %s", runtime)
}
checkpointPath = opts.ImagePath
}
return checkpointPath, nil
}
// getRestorePath only suitable for runc runtime now
func getRestorePath(runtime string, option *ptypes.Any) (string, error) {
if option == nil {
return "", nil
}
var restorePath string
switch runtime {
case "io.containerd.runc.v1":
v, err := typeurl.UnmarshalAny(option)
if err != nil {
return "", err
}
opts, ok := v.(*options.Options)
if !ok {
return "", fmt.Errorf("invalid task create option for %s", runtime)
}
restorePath = opts.CriuImagePath
case "io.containerd.runtime.v1.linux":
v, err := typeurl.UnmarshalAny(option)
if err != nil {
return "", err
}
opts, ok := v.(*runctypes.CreateOptions)
if !ok {
return "", fmt.Errorf("invalid task create option for %s", runtime)
}
restorePath = opts.CriuImagePath
}
return restorePath, nil
}

View File

@@ -350,7 +350,7 @@ func (o *snapshotter) getCleanupDirectories(ctx context.Context, t storage.Trans
return cleanup, nil
}
func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, key, parent string, opts []snapshots.Opt) ([]mount.Mount, error) {
func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, key, parent string, opts []snapshots.Opt) (_ []mount.Mount, err error) {
ctx, t, err := o.ms.TransactionContext(ctx, true)
if err != nil {
return nil, err
@@ -426,7 +426,7 @@ func (o *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, k
}
func (o *snapshotter) prepareDirectory(ctx context.Context, snapshotDir string, kind snapshots.Kind) (string, error) {
td, err := ioutil.TempDir(filepath.Join(o.root, "snapshots"), "new-")
td, err := ioutil.TempDir(snapshotDir, "new-")
if err != nil {
return "", errors.Wrap(err, "failed to create temp dir")
}

View File

@@ -160,9 +160,13 @@ func (u *Usage) Add(other Usage) {
// layerPath, tmpDir := getLayerPath(), mkTmpDir() // just a path to layer tar file.
//
// We start by using a Snapshotter to Prepare a new snapshot transaction, using a
// key and descending from the empty parent "":
// key and descending from the empty parent "". To prevent our layer from being
// garbage collected during unpacking, we add the `containerd.io/gc.root` label:
//
// mounts, err := snapshotter.Prepare(ctx, key, "")
// noGcOpt := snapshotter.WithLabels(map[string]string{
// "containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339),
// })
// mounts, err := snapshotter.Prepare(ctx, key, "", noGcOpt)
// if err != nil { ... }
//
// We get back a list of mounts from Snapshotter.Prepare, with the key identifying
@@ -191,15 +195,13 @@ func (u *Usage) Add(other Usage) {
//
// Now that we've verified and unpacked our layer, we commit the active
// snapshot to a name. For this example, we are just going to use the layer
// digest, but in practice, this will probably be the ChainID:
// digest, but in practice, this will probably be the ChainID. This also removes
// the active snapshot:
//
// if err := snapshotter.Commit(ctx, digest.String(), key); err != nil { ... }
// if err := snapshotter.Commit(ctx, digest.String(), key, noGcOpt); err != nil { ... }
//
// Now, we have a layer in the Snapshotter that can be accessed with the digest
// provided during commit. Once you have committed the snapshot, the active
// snapshot can be removed with the following:
//
// snapshotter.Remove(ctx, key)
// provided during commit.
//
// Importing the Next Layer
//
@@ -207,7 +209,7 @@ func (u *Usage) Add(other Usage) {
// above except that the parent is provided as parent when calling
// Manager.Prepare, assuming a clean, unique key identifier:
//
// mounts, err := snapshotter.Prepare(ctx, key, parentDigest)
// mounts, err := snapshotter.Prepare(ctx, key, parentDigest, noGcOpt)
//
// We then mount, apply and commit, as we did above. The new snapshot will be
// based on the content of the previous one.

View File

@@ -37,6 +37,8 @@ import (
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/rootfs"
"github.com/containerd/containerd/runtime/linux/runctypes"
"github.com/containerd/containerd/runtime/v2/runc/options"
"github.com/containerd/typeurl"
google_protobuf "github.com/gogo/protobuf/types"
digest "github.com/opencontainers/go-digest"
@@ -147,6 +149,8 @@ type Task interface {
// OCI Index that can be push and pulled from a remote resource.
//
// Additional software like CRIU maybe required to checkpoint and restore tasks
// NOTE: Checkpoint supports to dump task information to a directory, in this way,
// an empty OCI Index will be returned.
Checkpoint(context.Context, ...CheckpointTaskOpts) (Image, error)
// Update modifies executing tasks with updated settings
Update(context.Context, ...UpdateTaskOpts) error
@@ -185,8 +189,10 @@ func (t *task) Start(ctx context.Context) error {
ContainerID: t.id,
})
if err != nil {
t.io.Cancel()
t.io.Close()
if t.io != nil {
t.io.Cancel()
t.io.Close()
}
return errdefs.FromGRPC(err)
}
t.pid = r.Pid
@@ -387,6 +393,8 @@ func (t *task) Resize(ctx context.Context, w, h uint32) error {
return errdefs.FromGRPC(err)
}
// NOTE: Checkpoint supports to dump task information to a directory, in this way, an empty
// OCI Index will be returned.
func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointTaskOpts) (Image, error) {
ctx, done, err := t.client.WithLease(ctx)
if err != nil {
@@ -433,6 +441,12 @@ func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointTaskOpts) (Imag
if err := t.checkpointTask(ctx, &index, request); err != nil {
return nil, err
}
// if checkpoint image path passed, jump checkpoint image,
// return an empty image
if isCheckpointPathExist(cr.Runtime.Name, i.Options) {
return NewImage(t.client, images.Image{}), nil
}
if cr.Image != "" {
if err := t.checkpointImage(ctx, &index, cr.Image); err != nil {
return nil, err
@@ -542,6 +556,7 @@ func (t *task) checkpointTask(ctx context.Context, index *v1.Index, request *tas
if err != nil {
return errdefs.FromGRPC(err)
}
// NOTE: response.Descriptors can be an empty slice if checkpoint image is jumped
// add the checkpoint descriptors to the index
for _, d := range response.Descriptors {
index.Manifests = append(index.Manifests, v1.Descriptor{
@@ -619,3 +634,24 @@ func writeContent(ctx context.Context, store content.Ingester, mediaType, ref st
Size: size,
}, nil
}
// isCheckpointPathExist only suitable for runc runtime now
func isCheckpointPathExist(runtime string, v interface{}) bool {
if v == nil {
return false
}
switch runtime {
case "io.containerd.runc.v1":
if opts, ok := v.(*options.CheckpointOptions); ok && opts.ImagePath != "" {
return true
}
case "io.containerd.runtime.v1.linux":
if opts, ok := v.(*runctypes.CheckpointOptions); ok && opts.ImagePath != "" {
return true
}
}
return false
}

View File

@@ -27,11 +27,18 @@ import (
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/mount"
"github.com/containerd/containerd/runtime/linux/runctypes"
"github.com/containerd/containerd/runtime/v2/runc/options"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)
const (
v1runtime = "io.containerd.runtime.v1.linux"
v2runtime = "io.containerd.runc.v1"
)
// NewTaskOpts allows the caller to set options on a new task
type NewTaskOpts func(context.Context, *Client, *TaskInfo) error
@@ -89,6 +96,60 @@ func WithCheckpointName(name string) CheckpointTaskOpts {
}
}
// WithCheckpointImagePath sets image path for checkpoint option
func WithCheckpointImagePath(rt, path string) CheckpointTaskOpts {
return func(r *CheckpointTaskInfo) error {
switch rt {
case v1runtime:
if r.Options == nil {
r.Options = &runctypes.CheckpointOptions{}
}
opts, ok := r.Options.(*runctypes.CheckpointOptions)
if !ok {
return errors.New("invalid v1 checkpoint options format")
}
opts.ImagePath = path
case v2runtime:
if r.Options == nil {
r.Options = &options.CheckpointOptions{}
}
opts, ok := r.Options.(*options.CheckpointOptions)
if !ok {
return errors.New("invalid v2 checkpoint options format")
}
opts.ImagePath = path
}
return nil
}
}
// WithRestoreImagePath sets image path for create option
func WithRestoreImagePath(rt, path string) NewTaskOpts {
return func(ctx context.Context, c *Client, ti *TaskInfo) error {
switch rt {
case v1runtime:
if ti.Options == nil {
ti.Options = &runctypes.CreateOptions{}
}
opts, ok := ti.Options.(*runctypes.CreateOptions)
if !ok {
return errors.New("invalid v1 create options format")
}
opts.CriuImagePath = path
case v2runtime:
if ti.Options == nil {
ti.Options = &options.Options{}
}
opts, ok := ti.Options.(*options.Options)
if !ok {
return errors.New("invalid v2 create options format")
}
opts.CriuImagePath = path
}
return nil
}
}
// ProcessDeleteOpts allows the caller to set options for the deletion of a task
type ProcessDeleteOpts func(context.Context, Process) error

View File

@@ -1,6 +1,6 @@
github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
github.com/containerd/cgroups 1152b960fcee041f50df15cdc67c29dbccf801ef
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/containerd/btrfs 2e1aa0ddf94f91fa282b6ed87c23bf0d64911244
@@ -20,7 +20,7 @@ github.com/gogo/protobuf v1.0.0
github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef
github.com/golang/protobuf v1.1.0
github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353 # v1.0.1-45-geba862d
github.com/opencontainers/runc v1.0.0-rc6
github.com/opencontainers/runc 12f6a991201fdb8f82579582d5e00e28fba06d0a
github.com/sirupsen/logrus v1.0.3
github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
@@ -29,21 +29,21 @@ github.com/pkg/errors v0.8.0
github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7
golang.org/x/sys 1b2967e3c290b7c545b3db0deeda16e9be4f98a2 https://github.com/golang/sys
github.com/opencontainers/image-spec v1.0.1
golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
golang.org/x/sync 42b317875d0fa942474b76e1b46a6060d720ae6e
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
github.com/Microsoft/go-winio v0.4.11
github.com/Microsoft/hcsshim v0.8.2
github.com/Microsoft/hcsshim v0.8.5
google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
github.com/containerd/ttrpc 2a805f71863501300ae1976d29f0454ae003e85a
github.com/containerd/ttrpc f02858b1457c5ca3aaec3a0803eb0d59f96e41d6
github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16
gotest.tools v2.1.0
github.com/google/go-cmp v0.1.0
go.etcd.io/bbolt v1.3.1-etcd.8
# cri dependencies
github.com/containerd/cri f913714917d2456d7e65a0be84962b1ce8acb487 # release/1.2 branch
github.com/containerd/cri 4dd6735020f5596dd41738f8c4f5cb07fa804c5e # master
github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90
github.com/blang/semver v3.1.0
github.com/containernetworking/cni v0.6.0
@@ -53,8 +53,6 @@ github.com/docker/distribution b38e5838b7b2f2ad48e06ec4b500011976080621
github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00
github.com/docker/spdystream 449fdfce4d962303d702fec724ef0ad181c92528
github.com/emicklei/go-restful v2.2.1
github.com/ghodss/yaml v1.0.0
github.com/golang/glog 44145f04b68cf362d9c4df2182967c2275eaefed
github.com/google/gofuzz 44d81051d367757e1c7c6a5a86423ece9afcf63c
github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55
github.com/hashicorp/go-multierror ed905158d87462226a13fe39ddf685ea65f1c11f
@@ -73,12 +71,14 @@ golang.org/x/oauth2 a6bd8cefa1811bd24b86f8902872e4e8225f74c4
golang.org/x/time f51c12702a4d776e4c1fa9b0fabab841babae631
gopkg.in/inf.v0 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
gopkg.in/yaml.v2 v2.2.1
k8s.io/api kubernetes-1.12.0
k8s.io/apimachinery kubernetes-1.12.0
k8s.io/apiserver kubernetes-1.12.0
k8s.io/client-go kubernetes-1.12.0
k8s.io/kubernetes v1.12.0
k8s.io/utils cd34563cd63c2bd7c6fe88a73c4dcf34ed8a67cb
k8s.io/api kubernetes-1.13.0
k8s.io/apimachinery kubernetes-1.13.0
k8s.io/apiserver kubernetes-1.13.0
k8s.io/client-go kubernetes-1.13.0
k8s.io/klog 8139d8cb77af419532b33dfa7dd09fbc5f1d344f
k8s.io/kubernetes v1.13.0
k8s.io/utils 0d26856f57b32ec3398579285e5c8a2bfe8c5243
sigs.k8s.io/yaml v1.1.0
# zfs dependencies
github.com/containerd/zfs 9f6ef3b1fe5144bd91fe5855b4eba81bc0d17d03

View File

@@ -50,3 +50,13 @@ TODO:
- [ ] Document protocol layout
- [ ] Add testing under concurrent load to ensure
- [ ] Verify connection error handling
# Project details
ttrpc is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
As a containerd sub-project, you will find the:
* [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
* [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
* and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
information in our [`containerd/project`](https://github.com/containerd/project) repository.

View File

@@ -24,6 +24,7 @@ import (
"strings"
"sync"
"syscall"
"time"
"github.com/gogo/protobuf/proto"
"github.com/pkg/errors"
@@ -86,6 +87,10 @@ func (c *Client) Call(ctx context.Context, service, method string, req, resp int
cresp = &Response{}
)
if dl, ok := ctx.Deadline(); ok {
creq.TimeoutNano = dl.Sub(time.Now()).Nanoseconds()
}
if err := c.dispatch(ctx, creq, cresp); err != nil {
return err
}
@@ -104,6 +109,7 @@ func (c *Client) Call(ctx context.Context, service, method string, req, resp int
func (c *Client) dispatch(ctx context.Context, req *Request, resp *Response) error {
errs := make(chan error, 1)
call := &callRequest{
ctx: ctx,
req: req,
resp: resp,
errs: errs,

View File

@@ -414,6 +414,9 @@ func (c *serverConn) run(sctx context.Context) {
case request := <-requests:
active++
go func(id uint32) {
ctx, cancel := getRequestContext(ctx, request.req)
defer cancel()
p, status := c.server.services.call(ctx, request.req.Service, request.req.Method, request.req.Payload)
resp := &Response{
Status: status.Proto(),
@@ -454,3 +457,15 @@ func (c *serverConn) run(sctx context.Context) {
}
}
}
var noopFunc = func() {}
func getRequestContext(ctx context.Context, req *Request) (retCtx context.Context, cancel func()) {
cancel = noopFunc
if req.TimeoutNano == 0 {
return ctx, cancel
}
ctx, cancel = context.WithTimeout(ctx, time.Duration(req.TimeoutNano))
return ctx, cancel
}

Some files were not shown because too many files have changed in this diff Show More