mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-09 21:17:09 +08:00
1
vendor/github.com/containerd/containerd/.appveyor.yml
generated
vendored
1
vendor/github.com/containerd/containerd/.appveyor.yml
generated
vendored
@ -7,7 +7,6 @@ clone_folder: c:\gopath\src\github.com\containerd\containerd
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- release/1.2
|
||||
|
||||
environment:
|
||||
GOPATH: C:\gopath
|
||||
|
3
vendor/github.com/containerd/containerd/.mailmap
generated
vendored
3
vendor/github.com/containerd/containerd/.mailmap
generated
vendored
@ -25,6 +25,3 @@ Jian Liao <jliao@alauda.io> liaoj <jliao@alauda.io>
|
||||
Jian Liao <jliao@alauda.io> liaojian <liaojian@Dabllo.local>
|
||||
Rui Cao <ruicao@alauda.io> ruicao <ruicao@alauda.io>
|
||||
Xuean Yan <yan.xuean@zte.com.cn> yanxuean <yan.xuean@zte.com.cn>
|
||||
Mike Brown <brownwm@us.ibm.com> Mike Brown <mikebrow@users.noreply.github.com>
|
||||
Ace-Tang <aceapril@126.com>
|
||||
Wei Fu <fuweid89@gmail.com>
|
||||
|
6
vendor/github.com/containerd/containerd/.travis.yml
generated
vendored
6
vendor/github.com/containerd/containerd/.travis.yml
generated
vendored
@ -1,4 +1,4 @@
|
||||
dist: trusty
|
||||
dist: xenial
|
||||
sudo: required
|
||||
# setup travis so that we can run containers for integration tests
|
||||
services:
|
||||
@ -25,16 +25,16 @@ addons:
|
||||
- libprotobuf-c0-dev
|
||||
- libprotobuf-dev
|
||||
- socat
|
||||
- libseccomp-dev
|
||||
|
||||
env:
|
||||
- TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runc.v1 TRAVIS_CGO_ENABLED=1
|
||||
- TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runc.v2 TRAVIS_CGO_ENABLED=1
|
||||
- TRAVIS_GOOS=linux TEST_RUNTIME=io.containerd.runtime.v1.linux TRAVIS_CGO_ENABLED=1
|
||||
- TRAVIS_GOOS=darwin TRAVIS_CGO_ENABLED=0
|
||||
|
||||
before_install:
|
||||
- uname -r
|
||||
- sudo apt-get -q update
|
||||
- sudo apt-get install -y libseccomp-dev/trusty-backports
|
||||
|
||||
install:
|
||||
- sudo PATH=$PATH GOPATH=$GOPATH script/setup/install-protobuf
|
||||
|
40
vendor/github.com/containerd/containerd/ADOPTERS.md
generated
vendored
Normal file
40
vendor/github.com/containerd/containerd/ADOPTERS.md
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
## containerd Adopters
|
||||
|
||||
A non-exhaustive list of containerd adopters is provided below.
|
||||
|
||||
**_Docker/Moby engine_** - Containerd began life prior to its CNCF adoption as a lower-layer
|
||||
runtime manager for `runc` processes below the Docker engine. Continuing today, containerd
|
||||
has extremely broad production usage as a component of the [Docker engine](https://github.com/docker/docker-ce)
|
||||
stack. Note that this includes any use of the open source [Moby engine project](https://github.com/moby/moby);
|
||||
including the Balena project listed below.
|
||||
|
||||
**_[IBM Cloud Kubernetes Service (IKS)](https://www.ibm.com/cloud/container-service)_** - offers containerd as the CRI runtime for v1.11 and higher versions.
|
||||
|
||||
**_[IBM Cloud Private (ICP)](https://www.ibm.com/cloud/private)_** - IBM's on-premises cloud offering has containerd as a "tech preview" CRI runtime for the Kubernetes offered within this product for the past two releases, and plans to fully migrate to containerd in a future release.
|
||||
|
||||
**_[Google Cloud Kubernetes Engine (GKE)](https://cloud.google.com/kubernetes-engine/)_** - offers containerd as the CRI runtime in **beta** for recent versions of Kubernetes.
|
||||
|
||||
**_Cloud Foundry_** - The [Guardian container manager](https://github.com/cloudfoundry/guardian) for CF has been using OCI runC directly with additional code from CF managing the container image and filesystem interactions, but have recently migrated to use containerd as a replacement for the extra code they had written around runC.
|
||||
|
||||
**_Alibaba's PouchContainer_** - The Alibaba [PouchContainer](https://github.com/alibaba/pouch) project uses containerd as its runtime for a cloud native offering that has unique isolation and image distribution capabilities.
|
||||
|
||||
**_Rancher's Rio project_** - Rancher Labs [Rio](https://github.com/rancher/rio) project uses containerd as the runtime for a combined Kubernetes, Istio, and container "Cloud Native Container Distribution" platform.
|
||||
|
||||
**_Eliot_** - The [Eliot](https://github.com/ernoaapa/eliot) container project for IoT device container management uses containerd as the runtime.
|
||||
|
||||
**_Balena_** - Resin's [Balena](https://github.com/resin-os/balena) container engine, based on moby/moby but for edge, embedded, and IoT use cases, uses the containerd and runc stack in the same way that the Docker engine uses containerd.
|
||||
|
||||
**_LinuxKit_** - the Moby project's [LinuxKit](https://github.com/linuxkit/linuxkit) for building secure, minimal Linux OS images in a container-native model uses containerd as the core runtime for system and service containers.
|
||||
|
||||
**_BuildKit_** - The Moby project's [BuildKit](https://github.com/moby/buildkit) can use either runC or containerd as build execution backends for building container images. BuildKit support has also been built into the Docker engine in recent releases, making BuildKit provide the backend to the `docker build` command.
|
||||
|
||||
**_Azure acs-engine_** - Microsoft Azure's [acs-engine](https://github.com/Azure/acs-engine) open source project has customizable deployment of Kubernetes clusters, where containerd is a selectable container runtime. At some point in the future Azure's AKS service will default to use containerd as the CRI runtime for deployed Kubernetes clusters.
|
||||
|
||||
**_Amazon Firecracker_** - The AWS [Firecracker VMM project](http://firecracker-microvm.io/) has extended containerd with a new snapshotter and v2 shim to allow containerd to drive virtualized container processes via their VMM implementation. More details on their containerd integration are available in [their GitHub project](https://github.com/firecracker-microvm/firecracker-containerd).
|
||||
|
||||
**_Kata Containers_** - The [Kata containers](https://katacontainers.io/) lightweight-virtualized container runtime project integrates with containerd via a custom v2 shim implementation that drives the Kata container runtime.
|
||||
|
||||
**_Other Projects_** - While the above list provides a cross-section of well known uses of containerd, the simplicity and clear API layer for containerd has inspired many smaller projects around providing simple container management platforms. Several examples of building higher layer functionality on top of the containerd base have come from various containerd community participants:
|
||||
- Michael Crosby's [boss](https://github.com/crosbymichael/boss) project,
|
||||
- Evan Hazlett's [stellar](https://github.com/ehazlett/stellar) project,
|
||||
- Paul Knopf's immutable Linux image builder project: [darch](https://github.com/godarch/darch).
|
7
vendor/github.com/containerd/containerd/BUILDING.md
generated
vendored
7
vendor/github.com/containerd/containerd/BUILDING.md
generated
vendored
@ -46,6 +46,7 @@ need to satisfy this dependencies in your system:
|
||||
|
||||
If you're building with seccomp, you'll need to install it with the following:
|
||||
|
||||
* CentOS/Fedora: `yum install libseccomp-devel`
|
||||
* Debian/Ubuntu: `apt install libseccomp-dev`
|
||||
|
||||
At this point you are ready to build `containerd` yourself!
|
||||
@ -79,7 +80,8 @@ result in undefined behavior.
|
||||
`containerd` uses `make` to create a repeatable build flow. It means that you
|
||||
can run:
|
||||
|
||||
```sudo
|
||||
```
|
||||
cd $GOPATH/src/github.com/containerd/containerd
|
||||
make
|
||||
```
|
||||
|
||||
@ -218,8 +220,7 @@ containerd --config config.toml
|
||||
During the automated CI the unit tests and integration tests are run as part of the PR validation. As a developer you can run these tests locally by using any of the following `Makefile` targets:
|
||||
- `make test`: run all non-integration tests that do not require `root` privileges
|
||||
- `make root-test`: run all non-integration tests which require `root`
|
||||
- `make integration`: run all tests, including integration tests and those which require `root`
|
||||
- `make integration-parallel`: run all tests (integration and root-required included) in parallel mode
|
||||
- `make integration`: run all tests, including integration tests and those which require `root`. `TESTFLAGS_PARALLEL` can be used to control parallelism. For example, `TESTFLAGS_PARALLEL=1 make integration` will lead a non-parallel execution. The default value of `TESTFLAGS_PARALLEL` is **8**.
|
||||
|
||||
To execute a specific test or set of tests you can use the `go test` capabilities
|
||||
without using the `Makefile` targets. The following examples show how to specify a test
|
||||
|
30
vendor/github.com/containerd/containerd/Makefile
generated
vendored
30
vendor/github.com/containerd/containerd/Makefile
generated
vendored
@ -22,6 +22,7 @@ DESTDIR=/usr/local
|
||||
# Used to populate variables in version package.
|
||||
VERSION=$(shell git describe --match 'v[0-9]*' --dirty='.m' --always)
|
||||
REVISION=$(shell git rev-parse HEAD)$(shell if ! git diff --no-ext-diff --quiet --exit-code; then echo .m; fi)
|
||||
PACKAGE=github.com/containerd/containerd
|
||||
|
||||
ifneq "$(strip $(shell command -v go 2>/dev/null))" ""
|
||||
GOOS ?= $(shell go env GOOS)
|
||||
@ -50,6 +51,15 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef GODEBUG
|
||||
EXTRA_LDFLAGS += -s -w
|
||||
DEBUG_GO_GCFLAGS :=
|
||||
DEBUG_TAGS :=
|
||||
else
|
||||
DEBUG_GO_GCFLAGS := -gcflags=all="-N -l"
|
||||
DEBUG_TAGS := static_build
|
||||
endif
|
||||
|
||||
WHALE = "🇩"
|
||||
ONI = "👹"
|
||||
|
||||
@ -74,11 +84,15 @@ TEST_REQUIRES_ROOT_PACKAGES=$(filter \
|
||||
COMMANDS=ctr containerd containerd-stress
|
||||
MANPAGES=ctr.1 containerd.1 containerd-config.1 containerd-config.toml.5
|
||||
|
||||
ifdef BUILDTAGS
|
||||
GO_BUILDTAGS = ${BUILDTAGS}
|
||||
endif
|
||||
# Build tags seccomp and apparmor are needed by CRI plugin.
|
||||
BUILDTAGS ?= seccomp apparmor
|
||||
GO_TAGS=$(if $(BUILDTAGS),-tags "$(BUILDTAGS)",)
|
||||
GO_LDFLAGS=-ldflags '-s -w -X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PKG) $(EXTRA_LDFLAGS)'
|
||||
SHIM_GO_LDFLAGS=-ldflags '-s -w -X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PKG) -extldflags "-static"'
|
||||
GO_BUILDTAGS ?= seccomp apparmor
|
||||
GO_BUILDTAGS += ${DEBUG_TAGS}
|
||||
GO_TAGS=$(if $(GO_BUILDTAGS),-tags "$(GO_BUILDTAGS)",)
|
||||
GO_LDFLAGS=-ldflags '-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) $(EXTRA_LDFLAGS)'
|
||||
SHIM_GO_LDFLAGS=-ldflags '-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) -extldflags "-static" $(EXTRA_LDFLAGS)'
|
||||
|
||||
#Replaces ":" (*nix), ";" (windows) with newline for easy parsing
|
||||
GOPATHS=$(shell echo ${GOPATH} | tr ":" "\n" | tr ";" "\n")
|
||||
@ -143,7 +157,7 @@ proto-fmt: ## check format of proto files
|
||||
|
||||
build: ## build the go packages
|
||||
@echo "$(WHALE) $@"
|
||||
@go build ${GO_GCFLAGS} ${GO_BUILD_FLAGS} ${EXTRA_FLAGS} ${GO_LDFLAGS} ${PACKAGES}
|
||||
@go build ${DEBUG_GO_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} ${EXTRA_FLAGS} ${GO_LDFLAGS} ${PACKAGES}
|
||||
|
||||
test: ## run tests, except integration tests and tests that require root
|
||||
@echo "$(WHALE) $@"
|
||||
@ -166,7 +180,7 @@ FORCE:
|
||||
# Build a binary from a cmd.
|
||||
bin/%: cmd/% FORCE
|
||||
@echo "$(WHALE) $@${BINARY_SUFFIX}"
|
||||
@go build ${GO_GCFLAGS} ${GO_BUILD_FLAGS} -o $@${BINARY_SUFFIX} ${GO_LDFLAGS} ${GO_TAGS} ./$<
|
||||
@go build ${DEBUG_GO_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} -o $@${BINARY_SUFFIX} ${GO_LDFLAGS} ${GO_TAGS} ./$<
|
||||
|
||||
bin/containerd-shim: cmd/containerd-shim FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220
|
||||
@echo "$(WHALE) bin/containerd-shim"
|
||||
@ -176,6 +190,10 @@ bin/containerd-shim-runc-v1: cmd/containerd-shim-runc-v1 FORCE # set !cgo and om
|
||||
@echo "$(WHALE) bin/containerd-shim-runc-v1"
|
||||
@CGO_ENABLED=0 go build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runc-v1 ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v1
|
||||
|
||||
bin/containerd-shim-runc-v2: cmd/containerd-shim-runc-v2 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220
|
||||
@echo "$(WHALE) bin/containerd-shim-runc-v2"
|
||||
@CGO_ENABLED=0 go build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runc-v2 ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v2
|
||||
|
||||
bin/containerd-shim-runhcs-v1: cmd/containerd-shim-runhcs-v1 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220
|
||||
@echo "$(WHALE) bin/containerd-shim-runhcs-v1${BINARY_SUFFIX}"
|
||||
@CGO_ENABLED=0 go build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runhcs-v1${BINARY_SUFFIX} ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runhcs-v1
|
||||
|
4
vendor/github.com/containerd/containerd/Makefile.linux
generated
vendored
4
vendor/github.com/containerd/containerd/Makefile.linux
generated
vendored
@ -14,7 +14,9 @@
|
||||
|
||||
|
||||
#linux specific settings
|
||||
COMMANDS += containerd-shim containerd-shim-runc-v1
|
||||
WHALE="+"
|
||||
ONI="-"
|
||||
COMMANDS += containerd-shim containerd-shim-runc-v1 containerd-shim-runc-v2
|
||||
|
||||
# check GOOS for cross compile builds
|
||||
ifeq ($(GOOS),linux)
|
||||
|
7
vendor/github.com/containerd/containerd/Makefile.windows
generated
vendored
7
vendor/github.com/containerd/containerd/Makefile.windows
generated
vendored
@ -24,10 +24,3 @@ BINARY_SUFFIX=".exe"
|
||||
ifeq ($(GOARCH),amd64)
|
||||
TESTFLAGS_RACE= -race
|
||||
endif
|
||||
|
||||
# add support for building the Windows v2 runtime
|
||||
# based on the containerd-shim-runhcs-v1 shim rather
|
||||
# than the existing runtime on hcsshim
|
||||
ifeq (${BUILD_WINDOWS_V2},1)
|
||||
BUILDTAGS += windows_v2
|
||||
endif
|
||||
|
23
vendor/github.com/containerd/containerd/README.md
generated
vendored
23
vendor/github.com/containerd/containerd/README.md
generated
vendored
@ -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.
|
||||
@ -224,7 +217,12 @@ This will be the best place to discuss design and implementation.
|
||||
|
||||
For sync communication we have a community slack with a #containerd channel that everyone is welcome to join and chat about development.
|
||||
|
||||
**Slack:** https://join.slack.com/t/dockercommunity/shared_invite/enQtNDM4NjAwNDMyOTUwLWZlMDZmYWRjZjk4Zjc5ZGQ5NWZkOWI1Yjk2NGE3ZWVlYjYxM2VhYjczOWIyZDFhZTE3NTUwZWQzMjhmNGYyZTg
|
||||
**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
|
||||
|
||||
@ -249,3 +247,8 @@ Please find all these core project documents, including the:
|
||||
* and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
|
||||
|
||||
information in our [`containerd/project`](https://github.com/containerd/project) repository.
|
||||
|
||||
## Adoption
|
||||
|
||||
Interested to see who is using containerd? Are you using containerd in a project?
|
||||
Please add yourself via pull request to our [ADOPTERS.md](./ADOPTERS.md) file.
|
||||
|
6
vendor/github.com/containerd/containerd/RELEASES.md
generated
vendored
6
vendor/github.com/containerd/containerd/RELEASES.md
generated
vendored
@ -93,9 +93,9 @@ The current state is available in the following table:
|
||||
| [0.0](https://github.com/containerd/containerd/releases/tag/0.0.5) | End of Life | Dec 4, 2015 | - |
|
||||
| [0.1](https://github.com/containerd/containerd/releases/tag/v0.1.0) | End of Life | Mar 21, 2016 | - |
|
||||
| [0.2](https://github.com/containerd/containerd/tree/v0.2.x) | End of Life | Apr 21, 2016 | December 5, 2017 |
|
||||
| [1.0](https://github.com/containerd/containerd/releases/tag/v1.0.0) | Active | December 5, 2017 | December 5, 2018 |
|
||||
| [1.1](https://github.com/containerd/containerd/releases/tag/v1.1.0) | Active | April 23, 2018 | max(April 23, 2019, release of 1.2.0, Kubernetes 1.10 EOL) |
|
||||
| [1.2](https://github.com/containerd/containerd/releases/tag/v1.2.0) | Active | October 24, 2018 | max(October 24, 2019, release of 1.3.0) |
|
||||
| [1.0](https://github.com/containerd/containerd/releases/tag/v1.0.3) | End of Life | December 5, 2017 | December 5, 2018 |
|
||||
| [1.1](https://github.com/containerd/containerd/releases/tag/v1.1.6) | Active | April 23, 2018 | max(April 23, 2019, Kubernetes 1.10 EOL) |
|
||||
| [1.2](https://github.com/containerd/containerd/releases/tag/v1.2.4) | Active | October 24, 2018 | max(October 24, 2019, release of 1.3.0) |
|
||||
| [1.3](https://github.com/containerd/containerd/milestone/20) | Next | TBD | max(TBD+1 year, release of 1.4.0) |
|
||||
|
||||
Note that branches and release from before 1.0 may not follow these rules.
|
||||
|
2
vendor/github.com/containerd/containerd/archive/time_unix.go
generated
vendored
2
vendor/github.com/containerd/containerd/archive/time_unix.go
generated
vendored
@ -1,4 +1,4 @@
|
||||
// +build freebsd linux openbsd solaris
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
72
vendor/github.com/containerd/containerd/cio/io.go
generated
vendored
72
vendor/github.com/containerd/containerd/cio/io.go
generated
vendored
@ -20,8 +20,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/containerd/defaults"
|
||||
@ -222,46 +222,76 @@ type DirectIO struct {
|
||||
cio
|
||||
}
|
||||
|
||||
var _ IO = &DirectIO{}
|
||||
var (
|
||||
_ IO = &DirectIO{}
|
||||
_ IO = &logURI{}
|
||||
)
|
||||
|
||||
// LogFile creates a file on disk that logs the task's STDOUT,STDERR.
|
||||
// If the log file already exists, the logs will be appended to the file.
|
||||
func LogFile(path string) Creator {
|
||||
// LogURI provides the raw logging URI
|
||||
func LogURI(uri *url.URL) Creator {
|
||||
return func(_ string) (IO, error) {
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Close()
|
||||
return &logIO{
|
||||
return &logURI{
|
||||
config: Config{
|
||||
Stdout: path,
|
||||
Stderr: path,
|
||||
Stdout: uri.String(),
|
||||
Stderr: uri.String(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type logIO struct {
|
||||
// BinaryIO forwards container STDOUT|STDERR directly to a logging binary
|
||||
func BinaryIO(binary string, args map[string]string) Creator {
|
||||
return func(_ string) (IO, error) {
|
||||
uri := &url.URL{
|
||||
Scheme: "binary",
|
||||
Host: binary,
|
||||
}
|
||||
for k, v := range args {
|
||||
uri.Query().Set(k, v)
|
||||
}
|
||||
return &logURI{
|
||||
config: Config{
|
||||
Stdout: uri.String(),
|
||||
Stderr: uri.String(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// LogFile creates a file on disk that logs the task's STDOUT,STDERR.
|
||||
// If the log file already exists, the logs will be appended to the file.
|
||||
func LogFile(path string) Creator {
|
||||
return func(_ string) (IO, error) {
|
||||
uri := &url.URL{
|
||||
Scheme: "file",
|
||||
Host: path,
|
||||
}
|
||||
return &logURI{
|
||||
config: Config{
|
||||
Stdout: uri.String(),
|
||||
Stderr: uri.String(),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type logURI struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
func (l *logIO) Config() Config {
|
||||
func (l *logURI) Config() Config {
|
||||
return l.config
|
||||
}
|
||||
|
||||
func (l *logIO) Cancel() {
|
||||
func (l *logURI) Cancel() {
|
||||
|
||||
}
|
||||
|
||||
func (l *logIO) Wait() {
|
||||
func (l *logURI) Wait() {
|
||||
|
||||
}
|
||||
|
||||
func (l *logIO) Close() error {
|
||||
func (l *logURI) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
6
vendor/github.com/containerd/containerd/cio/io_windows.go
generated
vendored
6
vendor/github.com/containerd/containerd/cio/io_windows.go
generated
vendored
@ -31,11 +31,15 @@ const pipeRoot = `\\.\pipe`
|
||||
|
||||
// NewFIFOSetInDir returns a new set of fifos for the task
|
||||
func NewFIFOSetInDir(_, id string, terminal bool) (*FIFOSet, error) {
|
||||
stderrPipe := ""
|
||||
if !terminal {
|
||||
stderrPipe = fmt.Sprintf(`%s\ctr-%s-stderr`, pipeRoot, id)
|
||||
}
|
||||
return NewFIFOSet(Config{
|
||||
Terminal: terminal,
|
||||
Stdin: fmt.Sprintf(`%s\ctr-%s-stdin`, pipeRoot, id),
|
||||
Stdout: fmt.Sprintf(`%s\ctr-%s-stdout`, pipeRoot, id),
|
||||
Stderr: fmt.Sprintf(`%s\ctr-%s-stderr`, pipeRoot, id),
|
||||
Stderr: stderrPipe,
|
||||
}, nil), nil
|
||||
}
|
||||
|
||||
|
241
vendor/github.com/containerd/containerd/client.go
generated
vendored
241
vendor/github.com/containerd/containerd/client.go
generated
vendored
@ -17,11 +17,14 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -40,7 +43,6 @@ import (
|
||||
"github.com/containerd/containerd/content"
|
||||
contentproxy "github.com/containerd/containerd/content/proxy"
|
||||
"github.com/containerd/containerd/defaults"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/events"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/leases"
|
||||
@ -51,7 +53,6 @@ import (
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
"github.com/containerd/containerd/remotes/docker/schema1"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
snproxy "github.com/containerd/containerd/snapshots/proxy"
|
||||
"github.com/containerd/typeurl"
|
||||
@ -280,6 +281,12 @@ type RemoteContext struct {
|
||||
// handlers.
|
||||
BaseHandlers []images.Handler
|
||||
|
||||
// HandlerWrapper wraps the handler which gets sent to dispatch.
|
||||
// Unlike BaseHandlers, this can run before and after the built
|
||||
// in handlers, allowing operations to run on the descriptor
|
||||
// after it has completed transferring.
|
||||
HandlerWrapper func(images.Handler) images.Handler
|
||||
|
||||
// ConvertSchema1 is whether to convert Docker registry schema 1
|
||||
// manifests. If this option is false then any image which resolves
|
||||
// to schema 1 will return an error since schema 1 is not supported.
|
||||
@ -290,6 +297,13 @@ 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
|
||||
|
||||
// AppendDistributionSourceLabel allows fetcher to add distribute source
|
||||
// label for each blob content, which doesn't work for legacy schema1.
|
||||
AppendDistributionSourceLabel bool
|
||||
}
|
||||
|
||||
func defaultRemoteContext() *RemoteContext {
|
||||
@ -341,157 +355,6 @@ func (c *Client) Fetch(ctx context.Context, ref string, opts ...RemoteOpt) (imag
|
||||
return c.fetch(ctx, fetchCtx, ref, 0)
|
||||
}
|
||||
|
||||
// Pull downloads the provided content into containerd's content store
|
||||
// and returns a platform specific image object
|
||||
func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image, error) {
|
||||
pullCtx := defaultRemoteContext()
|
||||
for _, o := range opts {
|
||||
if err := o(c, pullCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if pullCtx.PlatformMatcher == nil {
|
||||
if len(pullCtx.Platforms) > 1 {
|
||||
return nil, errors.New("cannot pull multiplatform image locally, try Fetch")
|
||||
} else if len(pullCtx.Platforms) == 0 {
|
||||
pullCtx.PlatformMatcher = platforms.Default()
|
||||
} else {
|
||||
p, err := platforms.Parse(pullCtx.Platforms[0])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "invalid platform %s", pullCtx.Platforms[0])
|
||||
}
|
||||
|
||||
pullCtx.PlatformMatcher = platforms.Only(p)
|
||||
}
|
||||
}
|
||||
|
||||
ctx, done, err := c.WithLease(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer done(ctx)
|
||||
|
||||
img, err := c.fetch(ctx, pullCtx, ref, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i := NewImageWithPlatform(c, img, pullCtx.PlatformMatcher)
|
||||
|
||||
if pullCtx.Unpack {
|
||||
if err := i.Unpack(ctx, pullCtx.Snapshotter); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter)
|
||||
}
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, limit int) (images.Image, error) {
|
||||
store := c.ContentStore()
|
||||
name, desc, err := rCtx.Resolver.Resolve(ctx, ref)
|
||||
if err != nil {
|
||||
return images.Image{}, errors.Wrapf(err, "failed to resolve reference %q", ref)
|
||||
}
|
||||
|
||||
fetcher, err := rCtx.Resolver.Fetcher(ctx, name)
|
||||
if err != nil {
|
||||
return images.Image{}, errors.Wrapf(err, "failed to get fetcher for %q", name)
|
||||
}
|
||||
|
||||
var (
|
||||
handler images.Handler
|
||||
|
||||
isConvertible bool
|
||||
converterFunc func(context.Context, ocispec.Descriptor) (ocispec.Descriptor, error)
|
||||
)
|
||||
|
||||
if desc.MediaType == images.MediaTypeDockerSchema1Manifest && rCtx.ConvertSchema1 {
|
||||
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)
|
||||
// Set any children labels for that content
|
||||
childrenHandler = images.SetChildrenLabels(store, childrenHandler)
|
||||
// Filter children by platforms
|
||||
childrenHandler = images.FilterPlatforms(childrenHandler, rCtx.PlatformMatcher)
|
||||
// Sort and limit manifests if a finite number is needed
|
||||
if limit > 0 {
|
||||
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 {
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
if isConvertible {
|
||||
if desc, err = converterFunc(ctx, desc); err != nil {
|
||||
return images.Image{}, err
|
||||
}
|
||||
}
|
||||
|
||||
img := images.Image{
|
||||
Name: name,
|
||||
Target: desc,
|
||||
Labels: rCtx.Labels,
|
||||
}
|
||||
|
||||
is := c.ImageService()
|
||||
for {
|
||||
if created, err := is.Create(ctx, img); err != nil {
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
updated, err := is.Update(ctx, img)
|
||||
if err != nil {
|
||||
// if image was removed, try create again
|
||||
if errdefs.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
img = updated
|
||||
} else {
|
||||
img = created
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Push uploads the provided content to a remote resource
|
||||
func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor, opts ...RemoteOpt) error {
|
||||
pushCtx := defaultRemoteContext()
|
||||
@ -521,7 +384,21 @@ func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor,
|
||||
return err
|
||||
}
|
||||
|
||||
return remotes.PushContent(ctx, pusher, desc, c.ContentStore(), pushCtx.PlatformMatcher, pushCtx.BaseHandlers...)
|
||||
var wrapper func(images.Handler) images.Handler
|
||||
|
||||
if len(pushCtx.BaseHandlers) > 0 {
|
||||
wrapper = func(h images.Handler) images.Handler {
|
||||
h = images.Handlers(append(pushCtx.BaseHandlers, h)...)
|
||||
if pushCtx.HandlerWrapper != nil {
|
||||
h = pushCtx.HandlerWrapper(h)
|
||||
}
|
||||
return h
|
||||
}
|
||||
} else if pushCtx.HandlerWrapper != nil {
|
||||
wrapper = pushCtx.HandlerWrapper
|
||||
}
|
||||
|
||||
return remotes.PushContent(ctx, pusher, desc, c.ContentStore(), pushCtx.PlatformMatcher, wrapper)
|
||||
}
|
||||
|
||||
// GetImage returns an existing image
|
||||
@ -546,6 +423,45 @@ func (c *Client) ListImages(ctx context.Context, filters ...string) ([]Image, er
|
||||
return images, nil
|
||||
}
|
||||
|
||||
// Restore restores a container from a checkpoint
|
||||
func (c *Client) Restore(ctx context.Context, id string, checkpoint Image, opts ...RestoreOpts) (Container, error) {
|
||||
store := c.ContentStore()
|
||||
index, err := decodeIndex(ctx, store, checkpoint.Target())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, done, err := c.WithLease(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer done(ctx)
|
||||
|
||||
copts := []NewContainerOpts{}
|
||||
for _, o := range opts {
|
||||
copts = append(copts, o(ctx, id, c, checkpoint, index))
|
||||
}
|
||||
|
||||
ctr, err := c.NewContainer(ctx, id, copts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ctr, nil
|
||||
}
|
||||
|
||||
func writeIndex(ctx context.Context, index *ocispec.Index, client *Client, ref string) (d ocispec.Descriptor, err error) {
|
||||
labels := map[string]string{}
|
||||
for i, m := range index.Manifests {
|
||||
labels[fmt.Sprintf("containerd.io/gc.ref.content.%d", i)] = m.Digest.String()
|
||||
}
|
||||
data, err := json.Marshal(index)
|
||||
if err != nil {
|
||||
return ocispec.Descriptor{}, err
|
||||
}
|
||||
return writeContent(ctx, client.ContentStore(), ocispec.MediaTypeImageIndex, ref, bytes.NewReader(data), content.WithLabels(labels))
|
||||
}
|
||||
|
||||
// Subscribe to events that match one or more of the provided filters.
|
||||
//
|
||||
// Callers should listen on both the envelope and errs channels. If the errs
|
||||
@ -703,3 +619,20 @@ func (c *Client) Version(ctx context.Context) (Version, error) {
|
||||
Revision: response.Revision,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CheckRuntime returns true if the current runtime matches the expected
|
||||
// runtime. Providing various parts of the runtime schema will match those
|
||||
// parts of the expected runtime
|
||||
func CheckRuntime(current, expected string) bool {
|
||||
cp := strings.Split(current, ".")
|
||||
l := len(cp)
|
||||
for i, p := range strings.Split(expected, ".") {
|
||||
if i > l {
|
||||
return false
|
||||
}
|
||||
if p != cp[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
25
vendor/github.com/containerd/containerd/client_opts.go
generated
vendored
25
vendor/github.com/containerd/containerd/client_opts.go
generated
vendored
@ -178,3 +178,28 @@ func WithImageHandler(h images.Handler) RemoteOpt {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithImageHandlerWrapper wraps the handlers to be called on dispatch.
|
||||
func WithImageHandlerWrapper(w func(images.Handler) images.Handler) RemoteOpt {
|
||||
return func(client *Client, c *RemoteContext) error {
|
||||
c.HandlerWrapper = w
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// WithAppendDistributionSourceLabel allows fetcher to add distribute source
|
||||
// label for each blob content, which doesn't work for legacy schema1.
|
||||
func WithAppendDistributionSourceLabel() RemoteOpt {
|
||||
return func(_ *Client, c *RemoteContext) error {
|
||||
c.AppendDistributionSourceLabel = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
80
vendor/github.com/containerd/containerd/container.go
generated
vendored
80
vendor/github.com/containerd/containerd/container.go
generated
vendored
@ -28,12 +28,22 @@ import (
|
||||
"github.com/containerd/containerd/cio"
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/containerd/runtime/v2/runc/options"
|
||||
"github.com/containerd/typeurl"
|
||||
prototypes "github.com/gogo/protobuf/types"
|
||||
ver "github.com/opencontainers/image-spec/specs-go"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
checkpointImageNameLabel = "org.opencontainers.image.ref.name"
|
||||
checkpointRuntimeNameLabel = "io.containerd.checkpoint.runtime"
|
||||
checkpointSnapshotterNameLabel = "io.containerd.checkpoint.snapshotter"
|
||||
)
|
||||
|
||||
// Container is a metadata object for container resources and task creation
|
||||
type Container interface {
|
||||
// ID identifies the container
|
||||
@ -64,6 +74,8 @@ type Container interface {
|
||||
Extensions(context.Context) (map[string]prototypes.Any, error)
|
||||
// Update a container
|
||||
Update(context.Context, ...UpdateContainerOpts) error
|
||||
// Checkpoint creates a checkpoint image of the current container
|
||||
Checkpoint(context.Context, string, ...CheckpointOpts) (Image, error)
|
||||
}
|
||||
|
||||
func containerFromRecord(client *Client, c containers.Container) *container {
|
||||
@ -217,7 +229,9 @@ func (c *container) NewTask(ctx context.Context, ioCreate cio.Creator, opts ...N
|
||||
})
|
||||
}
|
||||
}
|
||||
var info TaskInfo
|
||||
info := TaskInfo{
|
||||
runtime: r.Runtime.Name,
|
||||
}
|
||||
for _, o := range opts {
|
||||
if err := o(ctx, c.client, &info); err != nil {
|
||||
return nil, err
|
||||
@ -272,6 +286,70 @@ func (c *container) Update(ctx context.Context, opts ...UpdateContainerOpts) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *container) Checkpoint(ctx context.Context, ref string, opts ...CheckpointOpts) (Image, error) {
|
||||
index := &ocispec.Index{
|
||||
Versioned: ver.Versioned{
|
||||
SchemaVersion: 2,
|
||||
},
|
||||
Annotations: make(map[string]string),
|
||||
}
|
||||
copts := &options.CheckpointOptions{
|
||||
Exit: false,
|
||||
OpenTcp: false,
|
||||
ExternalUnixSockets: false,
|
||||
Terminal: false,
|
||||
FileLocks: true,
|
||||
EmptyNamespaces: nil,
|
||||
}
|
||||
info, err := c.Info(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img, err := c.Image(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, done, err := c.client.WithLease(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer done(ctx)
|
||||
|
||||
// add image name to manifest
|
||||
index.Annotations[checkpointImageNameLabel] = img.Name()
|
||||
// add runtime info to index
|
||||
index.Annotations[checkpointRuntimeNameLabel] = info.Runtime.Name
|
||||
// add snapshotter info to index
|
||||
index.Annotations[checkpointSnapshotterNameLabel] = info.Snapshotter
|
||||
|
||||
// process remaining opts
|
||||
for _, o := range opts {
|
||||
if err := o(ctx, c.client, &info, index, copts); err != nil {
|
||||
err = errdefs.FromGRPC(err)
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
desc, err := writeIndex(ctx, index, c.client, c.ID()+"index")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i := images.Image{
|
||||
Name: ref,
|
||||
Target: desc,
|
||||
}
|
||||
checkpoint, err := c.client.ImageService().Create(ctx, i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewImage(c.client, checkpoint), nil
|
||||
}
|
||||
|
||||
func (c *container) loadTask(ctx context.Context, ioAttach cio.Attach) (Task, error) {
|
||||
response, err := c.client.TaskService().Get(ctx, &tasks.GetRequest{
|
||||
ContainerID: c.id,
|
||||
|
155
vendor/github.com/containerd/containerd/container_checkpoint_opts.go
generated
vendored
Normal file
155
vendor/github.com/containerd/containerd/container_checkpoint_opts.go
generated
vendored
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
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 containerd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
tasks "github.com/containerd/containerd/api/services/tasks/v1"
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/diff"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/rootfs"
|
||||
"github.com/containerd/containerd/runtime/v2/runc/options"
|
||||
"github.com/containerd/typeurl"
|
||||
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrCheckpointRWUnsupported is returned if the container runtime does not support checkpoint
|
||||
ErrCheckpointRWUnsupported = errors.New("rw checkpoint is only supported on v2 runtimes")
|
||||
// ErrMediaTypeNotFound returns an error when a media type in the manifest is unknown
|
||||
ErrMediaTypeNotFound = errors.New("media type not found")
|
||||
)
|
||||
|
||||
// CheckpointOpts are options to manage the checkpoint operation
|
||||
type CheckpointOpts func(context.Context, *Client, *containers.Container, *imagespec.Index, *options.CheckpointOptions) error
|
||||
|
||||
// WithCheckpointImage includes the container image in the checkpoint
|
||||
func WithCheckpointImage(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
|
||||
ir, err := client.ImageService().Get(ctx, c.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
index.Manifests = append(index.Manifests, ir.Target)
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithCheckpointTask includes the running task
|
||||
func WithCheckpointTask(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
|
||||
any, err := typeurl.MarshalAny(copts)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
task, err := client.TaskService().Checkpoint(ctx, &tasks.CheckpointTaskRequest{
|
||||
ContainerID: c.ID,
|
||||
Options: any,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, d := range task.Descriptors {
|
||||
platformSpec := platforms.DefaultSpec()
|
||||
index.Manifests = append(index.Manifests, imagespec.Descriptor{
|
||||
MediaType: d.MediaType,
|
||||
Size: d.Size_,
|
||||
Digest: d.Digest,
|
||||
Platform: &platformSpec,
|
||||
})
|
||||
}
|
||||
// save copts
|
||||
data, err := any.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r := bytes.NewReader(data)
|
||||
desc, err := writeContent(ctx, client.ContentStore(), images.MediaTypeContainerd1CheckpointOptions, c.ID+"-checkpoint-options", r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
desc.Platform = &imagespec.Platform{
|
||||
OS: runtime.GOOS,
|
||||
Architecture: runtime.GOARCH,
|
||||
}
|
||||
index.Manifests = append(index.Manifests, desc)
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithCheckpointRuntime includes the container runtime info
|
||||
func WithCheckpointRuntime(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
|
||||
if c.Runtime.Options != nil {
|
||||
data, err := c.Runtime.Options.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r := bytes.NewReader(data)
|
||||
desc, err := writeContent(ctx, client.ContentStore(), images.MediaTypeContainerd1CheckpointRuntimeOptions, c.ID+"-runtime-options", r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
desc.Platform = &imagespec.Platform{
|
||||
OS: runtime.GOOS,
|
||||
Architecture: runtime.GOARCH,
|
||||
}
|
||||
index.Manifests = append(index.Manifests, desc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithCheckpointRW includes the rw in the checkpoint
|
||||
func WithCheckpointRW(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
|
||||
diffOpts := []diff.Opt{
|
||||
diff.WithReference(fmt.Sprintf("checkpoint-rw-%s", c.SnapshotKey)),
|
||||
}
|
||||
rw, err := rootfs.CreateDiff(ctx,
|
||||
c.SnapshotKey,
|
||||
client.SnapshotService(c.Snapshotter),
|
||||
client.DiffService(),
|
||||
diffOpts...,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
rw.Platform = &imagespec.Platform{
|
||||
OS: runtime.GOOS,
|
||||
Architecture: runtime.GOARCH,
|
||||
}
|
||||
index.Manifests = append(index.Manifests, rw)
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithCheckpointTaskExit causes the task to exit after checkpoint
|
||||
func WithCheckpointTaskExit(ctx context.Context, client *Client, c *containers.Container, index *imagespec.Index, copts *options.CheckpointOptions) error {
|
||||
copts.Exit = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetIndexByMediaType returns the index in a manifest for the specified media type
|
||||
func GetIndexByMediaType(index *imagespec.Index, mt string) (*imagespec.Descriptor, error) {
|
||||
for _, d := range index.Manifests {
|
||||
if d.MediaType == mt {
|
||||
return &d, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrMediaTypeNotFound
|
||||
}
|
9
vendor/github.com/containerd/containerd/container_opts.go
generated
vendored
9
vendor/github.com/containerd/containerd/container_opts.go
generated
vendored
@ -23,6 +23,7 @@ import (
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/snapshots"
|
||||
"github.com/containerd/typeurl"
|
||||
"github.com/gogo/protobuf/types"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
@ -118,7 +119,7 @@ func WithSnapshot(id string) NewContainerOpts {
|
||||
|
||||
// WithNewSnapshot allocates a new snapshot to be used by the container as the
|
||||
// root filesystem in read-write mode
|
||||
func WithNewSnapshot(id string, i Image) NewContainerOpts {
|
||||
func WithNewSnapshot(id string, i Image, opts ...snapshots.Opt) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default())
|
||||
if err != nil {
|
||||
@ -126,7 +127,7 @@ func WithNewSnapshot(id string, i Image) NewContainerOpts {
|
||||
}
|
||||
setSnapshotterIfEmpty(c)
|
||||
parent := identity.ChainID(diffIDs).String()
|
||||
if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, id, parent); err != nil {
|
||||
if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, id, parent, opts...); err != nil {
|
||||
return err
|
||||
}
|
||||
c.SnapshotKey = id
|
||||
@ -148,7 +149,7 @@ func WithSnapshotCleanup(ctx context.Context, client *Client, c containers.Conta
|
||||
|
||||
// WithNewSnapshotView allocates a new snapshot to be used by the container as the
|
||||
// root filesystem in read-only mode
|
||||
func WithNewSnapshotView(id string, i Image) NewContainerOpts {
|
||||
func WithNewSnapshotView(id string, i Image, opts ...snapshots.Opt) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default())
|
||||
if err != nil {
|
||||
@ -156,7 +157,7 @@ func WithNewSnapshotView(id string, i Image) NewContainerOpts {
|
||||
}
|
||||
setSnapshotterIfEmpty(c)
|
||||
parent := identity.ChainID(diffIDs).String()
|
||||
if _, err := client.SnapshotService(c.Snapshotter).View(ctx, id, parent); err != nil {
|
||||
if _, err := client.SnapshotService(c.Snapshotter).View(ctx, id, parent, opts...); err != nil {
|
||||
return err
|
||||
}
|
||||
c.SnapshotKey = id
|
||||
|
69
vendor/github.com/containerd/containerd/container_opts_unix.go
generated
vendored
69
vendor/github.com/containerd/containerd/container_opts_unix.go
generated
vendored
@ -26,81 +26,12 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
protobuf "github.com/gogo/protobuf/types"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// WithCheckpoint allows a container to be created from the checkpointed information
|
||||
// provided by the descriptor. The image, snapshot, and runtime specifications are
|
||||
// restored on the container
|
||||
func WithCheckpoint(im Image, snapshotKey string) NewContainerOpts {
|
||||
// set image and rw, and spec
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
var (
|
||||
desc = im.Target()
|
||||
store = client.ContentStore()
|
||||
)
|
||||
index, err := decodeIndex(ctx, store, desc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var rw *v1.Descriptor
|
||||
for _, m := range index.Manifests {
|
||||
switch m.MediaType {
|
||||
case v1.MediaTypeImageLayer:
|
||||
fk := m
|
||||
rw = &fk
|
||||
case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList:
|
||||
config, err := images.Config(ctx, store, m, platforms.Default())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to resolve image config")
|
||||
}
|
||||
diffIDs, err := images.RootFS(ctx, store, config)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to get rootfs")
|
||||
}
|
||||
setSnapshotterIfEmpty(c)
|
||||
if _, err := client.SnapshotService(c.Snapshotter).Prepare(ctx, snapshotKey, identity.ChainID(diffIDs).String()); err != nil {
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
c.Image = index.Annotations["image.name"]
|
||||
case images.MediaTypeContainerd1CheckpointConfig:
|
||||
data, err := content.ReadBlob(ctx, store, m)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to read checkpoint config")
|
||||
}
|
||||
var any protobuf.Any
|
||||
if err := proto.Unmarshal(data, &any); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Spec = &any
|
||||
}
|
||||
}
|
||||
if rw != nil {
|
||||
// apply the rw snapshot to the new rw layer
|
||||
mounts, err := client.SnapshotService(c.Snapshotter).Mounts(ctx, snapshotKey)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to get mounts for %s", snapshotKey)
|
||||
}
|
||||
if _, err := client.DiffService().Apply(ctx, *rw, mounts); err != nil {
|
||||
return errors.Wrap(err, "unable to apply rw diff")
|
||||
}
|
||||
}
|
||||
c.SnapshotKey = snapshotKey
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithRemappedSnapshot creates a new snapshot and remaps the uid/gid for the
|
||||
// filesystem to be used by a container with user namespaces
|
||||
func WithRemappedSnapshot(id string, i Image, uid, gid uint32) NewContainerOpts {
|
||||
|
150
vendor/github.com/containerd/containerd/container_restore_opts.go
generated
vendored
Normal file
150
vendor/github.com/containerd/containerd/container_restore_opts.go
generated
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
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 containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
ptypes "github.com/gogo/protobuf/types"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrImageNameNotFoundInIndex is returned when the image name is not found in the index
|
||||
ErrImageNameNotFoundInIndex = errors.New("image name not found in index")
|
||||
// ErrRuntimeNameNotFoundInIndex is returned when the runtime is not found in the index
|
||||
ErrRuntimeNameNotFoundInIndex = errors.New("runtime not found in index")
|
||||
// ErrSnapshotterNameNotFoundInIndex is returned when the snapshotter is not found in the index
|
||||
ErrSnapshotterNameNotFoundInIndex = errors.New("snapshotter not found in index")
|
||||
)
|
||||
|
||||
// RestoreOpts are options to manage the restore operation
|
||||
type RestoreOpts func(context.Context, string, *Client, Image, *imagespec.Index) NewContainerOpts
|
||||
|
||||
// WithRestoreImage restores the image for the container
|
||||
func WithRestoreImage(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
name, ok := index.Annotations[checkpointImageNameLabel]
|
||||
if !ok || name == "" {
|
||||
return ErrRuntimeNameNotFoundInIndex
|
||||
}
|
||||
snapshotter, ok := index.Annotations[checkpointSnapshotterNameLabel]
|
||||
if !ok || name == "" {
|
||||
return ErrSnapshotterNameNotFoundInIndex
|
||||
}
|
||||
i, err := client.GetImage(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
diffIDs, err := i.(*image).i.RootFS(ctx, client.ContentStore(), platforms.Default())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parent := identity.ChainID(diffIDs).String()
|
||||
if _, err := client.SnapshotService(snapshotter).Prepare(ctx, id, parent); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Image = i.Name()
|
||||
c.SnapshotKey = id
|
||||
c.Snapshotter = snapshotter
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithRestoreRuntime restores the runtime for the container
|
||||
func WithRestoreRuntime(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
name, ok := index.Annotations[checkpointRuntimeNameLabel]
|
||||
if !ok {
|
||||
return ErrRuntimeNameNotFoundInIndex
|
||||
}
|
||||
|
||||
// restore options if present
|
||||
m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointRuntimeOptions)
|
||||
if err != nil {
|
||||
if err != ErrMediaTypeNotFound {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var options *ptypes.Any
|
||||
if m != nil {
|
||||
store := client.ContentStore()
|
||||
data, err := content.ReadBlob(ctx, store, *m)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to read checkpoint runtime")
|
||||
}
|
||||
if err := proto.Unmarshal(data, options); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
c.Runtime = containers.RuntimeInfo{
|
||||
Name: name,
|
||||
Options: options,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithRestoreSpec restores the spec from the checkpoint for the container
|
||||
func WithRestoreSpec(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
m, err := GetIndexByMediaType(index, images.MediaTypeContainerd1CheckpointConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
store := client.ContentStore()
|
||||
data, err := content.ReadBlob(ctx, store, *m)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to read checkpoint config")
|
||||
}
|
||||
var any ptypes.Any
|
||||
if err := proto.Unmarshal(data, &any); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Spec = &any
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithRestoreRW restores the rw layer from the checkpoint for the container
|
||||
func WithRestoreRW(ctx context.Context, id string, client *Client, checkpoint Image, index *imagespec.Index) NewContainerOpts {
|
||||
return func(ctx context.Context, client *Client, c *containers.Container) error {
|
||||
// apply rw layer
|
||||
rw, err := GetIndexByMediaType(index, imagespec.MediaTypeImageLayerGzip)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mounts, err := client.SnapshotService(c.Snapshotter).Mounts(ctx, c.SnapshotKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := client.DiffService().Apply(ctx, *rw, mounts); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
4
vendor/github.com/containerd/containerd/containers/containers.go
generated
vendored
4
vendor/github.com/containerd/containerd/containers/containers.go
generated
vendored
@ -86,6 +86,10 @@ type RuntimeInfo struct {
|
||||
|
||||
// Store interacts with the underlying container storage
|
||||
type Store interface {
|
||||
// Get a container using the id.
|
||||
//
|
||||
// Container object is returned on success. If the id is not known to the
|
||||
// store, an error will be returned.
|
||||
Get(ctx context.Context, id string) (Container, error)
|
||||
|
||||
// List returns containers that match one or more of the provided filters.
|
||||
|
51
vendor/github.com/containerd/containerd/content/local/locks.go
generated
vendored
Normal file
51
vendor/github.com/containerd/containerd/content/local/locks.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
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 local
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Handles locking references
|
||||
|
||||
var (
|
||||
// locks lets us lock in process
|
||||
locks = map[string]struct{}{}
|
||||
locksMu sync.Mutex
|
||||
)
|
||||
|
||||
func tryLock(ref string) error {
|
||||
locksMu.Lock()
|
||||
defer locksMu.Unlock()
|
||||
|
||||
if _, ok := locks[ref]; ok {
|
||||
return errors.Wrapf(errdefs.ErrUnavailable, "ref %s locked", ref)
|
||||
}
|
||||
|
||||
locks[ref] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unlock(ref string) {
|
||||
locksMu.Lock()
|
||||
defer locksMu.Unlock()
|
||||
|
||||
delete(locks, ref)
|
||||
}
|
40
vendor/github.com/containerd/containerd/content/local/readerat.go
generated
vendored
Normal file
40
vendor/github.com/containerd/containerd/content/local/readerat.go
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
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 local
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// readerat implements io.ReaderAt in a completely stateless manner by opening
|
||||
// the referenced file for each call to ReadAt.
|
||||
type sizeReaderAt struct {
|
||||
size int64
|
||||
fp *os.File
|
||||
}
|
||||
|
||||
func (ra sizeReaderAt) ReadAt(p []byte, offset int64) (int, error) {
|
||||
return ra.fp.ReadAt(p, offset)
|
||||
}
|
||||
|
||||
func (ra sizeReaderAt) Size() int64 {
|
||||
return ra.size
|
||||
}
|
||||
|
||||
func (ra sizeReaderAt) Close() error {
|
||||
return ra.fp.Close()
|
||||
}
|
656
vendor/github.com/containerd/containerd/content/local/store.go
generated
vendored
Normal file
656
vendor/github.com/containerd/containerd/content/local/store.go
generated
vendored
Normal file
@ -0,0 +1,656 @@
|
||||
/*
|
||||
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 local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/filters"
|
||||
"github.com/containerd/containerd/log"
|
||||
|
||||
"github.com/containerd/continuity"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var bufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
buffer := make([]byte, 1<<20)
|
||||
return &buffer
|
||||
},
|
||||
}
|
||||
|
||||
// LabelStore is used to store mutable labels for digests
|
||||
type LabelStore interface {
|
||||
// Get returns all the labels for the given digest
|
||||
Get(digest.Digest) (map[string]string, error)
|
||||
|
||||
// Set sets all the labels for a given digest
|
||||
Set(digest.Digest, map[string]string) error
|
||||
|
||||
// Update replaces the given labels for a digest,
|
||||
// a key with an empty value removes a label.
|
||||
Update(digest.Digest, map[string]string) (map[string]string, error)
|
||||
}
|
||||
|
||||
// Store is digest-keyed store for content. All data written into the store is
|
||||
// stored under a verifiable digest.
|
||||
//
|
||||
// Store can generally support multi-reader, single-writer ingest of data,
|
||||
// including resumable ingest.
|
||||
type store struct {
|
||||
root string
|
||||
ls LabelStore
|
||||
}
|
||||
|
||||
// NewStore returns a local content store
|
||||
func NewStore(root string) (content.Store, error) {
|
||||
return NewLabeledStore(root, nil)
|
||||
}
|
||||
|
||||
// NewLabeledStore returns a new content store using the provided label store
|
||||
//
|
||||
// Note: content stores which are used underneath a metadata store may not
|
||||
// require labels and should use `NewStore`. `NewLabeledStore` is primarily
|
||||
// useful for tests or standalone implementations.
|
||||
func NewLabeledStore(root string, ls LabelStore) (content.Store, error) {
|
||||
if err := os.MkdirAll(filepath.Join(root, "ingest"), 0777); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &store{
|
||||
root: root,
|
||||
ls: ls,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *store) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) {
|
||||
p := s.blobPath(dgst)
|
||||
fi, err := os.Stat(p)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = errors.Wrapf(errdefs.ErrNotFound, "content %v", dgst)
|
||||
}
|
||||
|
||||
return content.Info{}, err
|
||||
}
|
||||
var labels map[string]string
|
||||
if s.ls != nil {
|
||||
labels, err = s.ls.Get(dgst)
|
||||
if err != nil {
|
||||
return content.Info{}, err
|
||||
}
|
||||
}
|
||||
return s.info(dgst, fi, labels), nil
|
||||
}
|
||||
|
||||
func (s *store) info(dgst digest.Digest, fi os.FileInfo, labels map[string]string) content.Info {
|
||||
return content.Info{
|
||||
Digest: dgst,
|
||||
Size: fi.Size(),
|
||||
CreatedAt: fi.ModTime(),
|
||||
UpdatedAt: getATime(fi),
|
||||
Labels: labels,
|
||||
}
|
||||
}
|
||||
|
||||
// ReaderAt returns an io.ReaderAt for the blob.
|
||||
func (s *store) ReaderAt(ctx context.Context, desc ocispec.Descriptor) (content.ReaderAt, error) {
|
||||
p := s.blobPath(desc.Digest)
|
||||
fi, err := os.Stat(p)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, errors.Wrapf(errdefs.ErrNotFound, "blob %s expected at %s", desc.Digest, p)
|
||||
}
|
||||
|
||||
fp, err := os.Open(p)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, errors.Wrapf(errdefs.ErrNotFound, "blob %s expected at %s", desc.Digest, p)
|
||||
}
|
||||
|
||||
return sizeReaderAt{size: fi.Size(), fp: fp}, nil
|
||||
}
|
||||
|
||||
// Delete removes a blob by its digest.
|
||||
//
|
||||
// While this is safe to do concurrently, safe exist-removal logic must hold
|
||||
// some global lock on the store.
|
||||
func (s *store) Delete(ctx context.Context, dgst digest.Digest) error {
|
||||
if err := os.RemoveAll(s.blobPath(dgst)); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "content %v", dgst)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *store) Update(ctx context.Context, info content.Info, fieldpaths ...string) (content.Info, error) {
|
||||
if s.ls == nil {
|
||||
return content.Info{}, errors.Wrapf(errdefs.ErrFailedPrecondition, "update not supported on immutable content store")
|
||||
}
|
||||
|
||||
p := s.blobPath(info.Digest)
|
||||
fi, err := os.Stat(p)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = errors.Wrapf(errdefs.ErrNotFound, "content %v", info.Digest)
|
||||
}
|
||||
|
||||
return content.Info{}, err
|
||||
}
|
||||
|
||||
var (
|
||||
all bool
|
||||
labels map[string]string
|
||||
)
|
||||
if len(fieldpaths) > 0 {
|
||||
for _, path := range fieldpaths {
|
||||
if strings.HasPrefix(path, "labels.") {
|
||||
if labels == nil {
|
||||
labels = map[string]string{}
|
||||
}
|
||||
|
||||
key := strings.TrimPrefix(path, "labels.")
|
||||
labels[key] = info.Labels[key]
|
||||
continue
|
||||
}
|
||||
|
||||
switch path {
|
||||
case "labels":
|
||||
all = true
|
||||
labels = info.Labels
|
||||
default:
|
||||
return content.Info{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on content info %q", path, info.Digest)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
all = true
|
||||
labels = info.Labels
|
||||
}
|
||||
|
||||
if all {
|
||||
err = s.ls.Set(info.Digest, labels)
|
||||
} else {
|
||||
labels, err = s.ls.Update(info.Digest, labels)
|
||||
}
|
||||
if err != nil {
|
||||
return content.Info{}, err
|
||||
}
|
||||
|
||||
info = s.info(info.Digest, fi, labels)
|
||||
info.UpdatedAt = time.Now()
|
||||
|
||||
if err := os.Chtimes(p, info.UpdatedAt, info.CreatedAt); err != nil {
|
||||
log.G(ctx).WithError(err).Warnf("could not change access time for %s", info.Digest)
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (s *store) Walk(ctx context.Context, fn content.WalkFunc, filters ...string) error {
|
||||
// TODO: Support filters
|
||||
root := filepath.Join(s.root, "blobs")
|
||||
var alg digest.Algorithm
|
||||
return filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !fi.IsDir() && !alg.Available() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO(stevvooe): There are few more cases with subdirs that should be
|
||||
// handled in case the layout gets corrupted. This isn't strict enough
|
||||
// and may spew bad data.
|
||||
|
||||
if path == root {
|
||||
return nil
|
||||
}
|
||||
if filepath.Dir(path) == root {
|
||||
alg = digest.Algorithm(filepath.Base(path))
|
||||
|
||||
if !alg.Available() {
|
||||
alg = ""
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
// descending into a hash directory
|
||||
return nil
|
||||
}
|
||||
|
||||
dgst := digest.NewDigestFromHex(alg.String(), filepath.Base(path))
|
||||
if err := dgst.Validate(); err != nil {
|
||||
// log error but don't report
|
||||
log.L.WithError(err).WithField("path", path).Error("invalid digest for blob path")
|
||||
// if we see this, it could mean some sort of corruption of the
|
||||
// store or extra paths not expected previously.
|
||||
}
|
||||
|
||||
var labels map[string]string
|
||||
if s.ls != nil {
|
||||
labels, err = s.ls.Get(dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return fn(s.info(dgst, fi, labels))
|
||||
})
|
||||
}
|
||||
|
||||
func (s *store) Status(ctx context.Context, ref string) (content.Status, error) {
|
||||
return s.status(s.ingestRoot(ref))
|
||||
}
|
||||
|
||||
func (s *store) ListStatuses(ctx context.Context, fs ...string) ([]content.Status, error) {
|
||||
fp, err := os.Open(filepath.Join(s.root, "ingest"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer fp.Close()
|
||||
|
||||
fis, err := fp.Readdir(-1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filter, err := filters.ParseAll(fs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var active []content.Status
|
||||
for _, fi := range fis {
|
||||
p := filepath.Join(s.root, "ingest", fi.Name())
|
||||
stat, err := s.status(p)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(stevvooe): This is a common error if uploads are being
|
||||
// completed while making this listing. Need to consider taking a
|
||||
// lock on the whole store to coordinate this aspect.
|
||||
//
|
||||
// Another option is to cleanup downloads asynchronously and
|
||||
// coordinate this method with the cleanup process.
|
||||
//
|
||||
// For now, we just skip them, as they really don't exist.
|
||||
continue
|
||||
}
|
||||
|
||||
if filter.Match(adaptStatus(stat)) {
|
||||
active = append(active, stat)
|
||||
}
|
||||
}
|
||||
|
||||
return active, nil
|
||||
}
|
||||
|
||||
// WalkStatusRefs is used to walk all status references
|
||||
// Failed status reads will be logged and ignored, if
|
||||
// this function is called while references are being altered,
|
||||
// these error messages may be produced.
|
||||
func (s *store) WalkStatusRefs(ctx context.Context, fn func(string) error) error {
|
||||
fp, err := os.Open(filepath.Join(s.root, "ingest"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer fp.Close()
|
||||
|
||||
fis, err := fp.Readdir(-1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, fi := range fis {
|
||||
rf := filepath.Join(s.root, "ingest", fi.Name(), "ref")
|
||||
|
||||
ref, err := readFileString(rf)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).WithField("path", rf).Error("failed to read ingest ref")
|
||||
continue
|
||||
}
|
||||
|
||||
if err := fn(ref); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// status works like stat above except uses the path to the ingest.
|
||||
func (s *store) status(ingestPath string) (content.Status, error) {
|
||||
dp := filepath.Join(ingestPath, "data")
|
||||
fi, err := os.Stat(dp)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = errors.Wrap(errdefs.ErrNotFound, err.Error())
|
||||
}
|
||||
return content.Status{}, err
|
||||
}
|
||||
|
||||
ref, err := readFileString(filepath.Join(ingestPath, "ref"))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = errors.Wrap(errdefs.ErrNotFound, err.Error())
|
||||
}
|
||||
return content.Status{}, err
|
||||
}
|
||||
|
||||
startedAt, err := readFileTimestamp(filepath.Join(ingestPath, "startedat"))
|
||||
if err != nil {
|
||||
return content.Status{}, errors.Wrapf(err, "could not read startedat")
|
||||
}
|
||||
|
||||
updatedAt, err := readFileTimestamp(filepath.Join(ingestPath, "updatedat"))
|
||||
if err != nil {
|
||||
return content.Status{}, errors.Wrapf(err, "could not read updatedat")
|
||||
}
|
||||
|
||||
// because we don't write updatedat on every write, the mod time may
|
||||
// actually be more up to date.
|
||||
if fi.ModTime().After(updatedAt) {
|
||||
updatedAt = fi.ModTime()
|
||||
}
|
||||
|
||||
return content.Status{
|
||||
Ref: ref,
|
||||
Offset: fi.Size(),
|
||||
Total: s.total(ingestPath),
|
||||
UpdatedAt: updatedAt,
|
||||
StartedAt: startedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func adaptStatus(status content.Status) filters.Adaptor {
|
||||
return filters.AdapterFunc(func(fieldpath []string) (string, bool) {
|
||||
if len(fieldpath) == 0 {
|
||||
return "", false
|
||||
}
|
||||
switch fieldpath[0] {
|
||||
case "ref":
|
||||
return status.Ref, true
|
||||
}
|
||||
|
||||
return "", false
|
||||
})
|
||||
}
|
||||
|
||||
// total attempts to resolve the total expected size for the write.
|
||||
func (s *store) total(ingestPath string) int64 {
|
||||
totalS, err := readFileString(filepath.Join(ingestPath, "total"))
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
total, err := strconv.ParseInt(totalS, 10, 64)
|
||||
if err != nil {
|
||||
// represents a corrupted file, should probably remove.
|
||||
return 0
|
||||
}
|
||||
|
||||
return total
|
||||
}
|
||||
|
||||
// Writer begins or resumes the active writer identified by ref. If the writer
|
||||
// is already in use, an error is returned. Only one writer may be in use per
|
||||
// ref at a time.
|
||||
//
|
||||
// The argument `ref` is used to uniquely identify a long-lived writer transaction.
|
||||
func (s *store) Writer(ctx context.Context, opts ...content.WriterOpt) (content.Writer, error) {
|
||||
var wOpts content.WriterOpts
|
||||
for _, opt := range opts {
|
||||
if err := opt(&wOpts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// TODO(AkihiroSuda): we could create a random string or one calculated based on the context
|
||||
// https://github.com/containerd/containerd/issues/2129#issuecomment-380255019
|
||||
if wOpts.Ref == "" {
|
||||
return nil, errors.Wrap(errdefs.ErrInvalidArgument, "ref must not be empty")
|
||||
}
|
||||
var lockErr error
|
||||
for count := uint64(0); count < 10; count++ {
|
||||
time.Sleep(time.Millisecond * time.Duration(rand.Intn(1<<count)))
|
||||
if err := tryLock(wOpts.Ref); err != nil {
|
||||
if !errdefs.IsUnavailable(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lockErr = err
|
||||
} else {
|
||||
lockErr = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if lockErr != nil {
|
||||
return nil, lockErr
|
||||
}
|
||||
|
||||
w, err := s.writer(ctx, wOpts.Ref, wOpts.Desc.Size, wOpts.Desc.Digest)
|
||||
if err != nil {
|
||||
unlock(wOpts.Ref)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w, nil // lock is now held by w.
|
||||
}
|
||||
|
||||
// writer provides the main implementation of the Writer method. The caller
|
||||
// must hold the lock correctly and release on error if there is a problem.
|
||||
func (s *store) writer(ctx context.Context, ref string, total int64, expected digest.Digest) (content.Writer, error) {
|
||||
// TODO(stevvooe): Need to actually store expected here. We have
|
||||
// code in the service that shouldn't be dealing with this.
|
||||
if expected != "" {
|
||||
p := s.blobPath(expected)
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", expected)
|
||||
}
|
||||
}
|
||||
|
||||
path, refp, data := s.ingestPaths(ref)
|
||||
|
||||
var (
|
||||
digester = digest.Canonical.Digester()
|
||||
offset int64
|
||||
startedAt time.Time
|
||||
updatedAt time.Time
|
||||
)
|
||||
|
||||
// ensure that the ingest path has been created.
|
||||
if err := os.Mkdir(path, 0755); err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
status, err := s.status(path)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed reading status of resume write")
|
||||
}
|
||||
|
||||
if ref != status.Ref {
|
||||
// NOTE(stevvooe): This is fairly catastrophic. Either we have some
|
||||
// layout corruption or a hash collision for the ref key.
|
||||
return nil, errors.Wrapf(err, "ref key does not match: %v != %v", ref, status.Ref)
|
||||
}
|
||||
|
||||
if total > 0 && status.Total > 0 && total != status.Total {
|
||||
return nil, errors.Errorf("provided total differs from status: %v != %v", total, status.Total)
|
||||
}
|
||||
|
||||
// TODO(stevvooe): slow slow slow!!, send to goroutine or use resumable hashes
|
||||
fp, err := os.Open(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := bufPool.Get().(*[]byte)
|
||||
offset, err = io.CopyBuffer(digester.Hash(), fp, *p)
|
||||
bufPool.Put(p)
|
||||
fp.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
updatedAt = status.UpdatedAt
|
||||
startedAt = status.StartedAt
|
||||
total = status.Total
|
||||
} else {
|
||||
startedAt = time.Now()
|
||||
updatedAt = startedAt
|
||||
|
||||
// the ingest is new, we need to setup the target location.
|
||||
// write the ref to a file for later use
|
||||
if err := ioutil.WriteFile(refp, []byte(ref), 0666); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if writeTimestampFile(filepath.Join(path, "startedat"), startedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if writeTimestampFile(filepath.Join(path, "updatedat"), startedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if total > 0 {
|
||||
if err := ioutil.WriteFile(filepath.Join(path, "total"), []byte(fmt.Sprint(total)), 0666); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fp, err := os.OpenFile(data, os.O_WRONLY|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to open data file")
|
||||
}
|
||||
|
||||
if _, err := fp.Seek(offset, io.SeekStart); err != nil {
|
||||
return nil, errors.Wrap(err, "could not seek to current write offset")
|
||||
}
|
||||
|
||||
return &writer{
|
||||
s: s,
|
||||
fp: fp,
|
||||
ref: ref,
|
||||
path: path,
|
||||
offset: offset,
|
||||
total: total,
|
||||
digester: digester,
|
||||
startedAt: startedAt,
|
||||
updatedAt: updatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Abort an active transaction keyed by ref. If the ingest is active, it will
|
||||
// be cancelled. Any resources associated with the ingest will be cleaned.
|
||||
func (s *store) Abort(ctx context.Context, ref string) error {
|
||||
root := s.ingestRoot(ref)
|
||||
if err := os.RemoveAll(root); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "ingest ref %q", ref)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *store) blobPath(dgst digest.Digest) string {
|
||||
return filepath.Join(s.root, "blobs", dgst.Algorithm().String(), dgst.Hex())
|
||||
}
|
||||
|
||||
func (s *store) ingestRoot(ref string) string {
|
||||
dgst := digest.FromString(ref)
|
||||
return filepath.Join(s.root, "ingest", dgst.Hex())
|
||||
}
|
||||
|
||||
// ingestPaths are returned. The paths are the following:
|
||||
//
|
||||
// - root: entire ingest directory
|
||||
// - ref: name of the starting ref, must be unique
|
||||
// - data: file where data is written
|
||||
//
|
||||
func (s *store) ingestPaths(ref string) (string, string, string) {
|
||||
var (
|
||||
fp = s.ingestRoot(ref)
|
||||
rp = filepath.Join(fp, "ref")
|
||||
dp = filepath.Join(fp, "data")
|
||||
)
|
||||
|
||||
return fp, rp, dp
|
||||
}
|
||||
|
||||
func readFileString(path string) (string, error) {
|
||||
p, err := ioutil.ReadFile(path)
|
||||
return string(p), err
|
||||
}
|
||||
|
||||
// readFileTimestamp reads a file with just a timestamp present.
|
||||
func readFileTimestamp(p string) (time.Time, error) {
|
||||
b, err := ioutil.ReadFile(p)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = errors.Wrap(errdefs.ErrNotFound, err.Error())
|
||||
}
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
var t time.Time
|
||||
if err := t.UnmarshalText(b); err != nil {
|
||||
return time.Time{}, errors.Wrapf(err, "could not parse timestamp file %v", p)
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func writeTimestampFile(p string, t time.Time) error {
|
||||
b, err := t.MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return continuity.AtomicWriteFile(p, b, 0666)
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
// +build linux solaris darwin freebsd
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
@ -14,17 +16,20 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package archive
|
||||
package local
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/containerd/containerd/sys"
|
||||
)
|
||||
|
||||
// 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 getATime(fi os.FileInfo) time.Time {
|
||||
if st, ok := fi.Sys().(*syscall.Stat_t); ok {
|
||||
return sys.StatATimeAsTime(st)
|
||||
}
|
||||
|
||||
return fi.ModTime()
|
||||
}
|
26
vendor/github.com/containerd/containerd/content/local/store_windows.go
generated
vendored
Normal file
26
vendor/github.com/containerd/containerd/content/local/store_windows.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
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 local
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func getATime(fi os.FileInfo) time.Time {
|
||||
return fi.ModTime()
|
||||
}
|
206
vendor/github.com/containerd/containerd/content/local/writer.go
generated
vendored
Normal file
206
vendor/github.com/containerd/containerd/content/local/writer.go
generated
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
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 local
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// writer represents a write transaction against the blob store.
|
||||
type writer struct {
|
||||
s *store
|
||||
fp *os.File // opened data file
|
||||
path string // path to writer dir
|
||||
ref string // ref key
|
||||
offset int64
|
||||
total int64
|
||||
digester digest.Digester
|
||||
startedAt time.Time
|
||||
updatedAt time.Time
|
||||
}
|
||||
|
||||
func (w *writer) Status() (content.Status, error) {
|
||||
return content.Status{
|
||||
Ref: w.ref,
|
||||
Offset: w.offset,
|
||||
Total: w.total,
|
||||
StartedAt: w.startedAt,
|
||||
UpdatedAt: w.updatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Digest returns the current digest of the content, up to the current write.
|
||||
//
|
||||
// Cannot be called concurrently with `Write`.
|
||||
func (w *writer) Digest() digest.Digest {
|
||||
return w.digester.Digest()
|
||||
}
|
||||
|
||||
// Write p to the transaction.
|
||||
//
|
||||
// Note that writes are unbuffered to the backing file. When writing, it is
|
||||
// recommended to wrap in a bufio.Writer or, preferably, use io.CopyBuffer.
|
||||
func (w *writer) Write(p []byte) (n int, err error) {
|
||||
n, err = w.fp.Write(p)
|
||||
w.digester.Hash().Write(p[:n])
|
||||
w.offset += int64(len(p))
|
||||
w.updatedAt = time.Now()
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (w *writer) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error {
|
||||
var base content.Info
|
||||
for _, opt := range opts {
|
||||
if err := opt(&base); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure even on error the writer is fully closed
|
||||
defer unlock(w.ref)
|
||||
fp := w.fp
|
||||
w.fp = nil
|
||||
|
||||
if fp == nil {
|
||||
return errors.Wrap(errdefs.ErrFailedPrecondition, "cannot commit on closed writer")
|
||||
}
|
||||
|
||||
if err := fp.Sync(); err != nil {
|
||||
fp.Close()
|
||||
return errors.Wrap(err, "sync failed")
|
||||
}
|
||||
|
||||
fi, err := fp.Stat()
|
||||
closeErr := fp.Close()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "stat on ingest file failed")
|
||||
}
|
||||
if closeErr != nil {
|
||||
return errors.Wrap(err, "failed to close ingest file")
|
||||
}
|
||||
|
||||
if size > 0 && size != fi.Size() {
|
||||
return errors.Wrapf(errdefs.ErrFailedPrecondition, "unexpected commit size %d, expected %d", fi.Size(), size)
|
||||
}
|
||||
|
||||
dgst := w.digester.Digest()
|
||||
if expected != "" && expected != dgst {
|
||||
return errors.Wrapf(errdefs.ErrFailedPrecondition, "unexpected commit digest %s, expected %s", dgst, expected)
|
||||
}
|
||||
|
||||
var (
|
||||
ingest = filepath.Join(w.path, "data")
|
||||
target = w.s.blobPath(dgst)
|
||||
)
|
||||
|
||||
// make sure parent directories of blob exist
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(target); err == nil {
|
||||
// collision with the target file!
|
||||
if err := os.RemoveAll(w.path); err != nil {
|
||||
log.G(ctx).WithField("ref", w.ref).WithField("path", w.path).Errorf("failed to remove ingest directory")
|
||||
}
|
||||
return errors.Wrapf(errdefs.ErrAlreadyExists, "content %v", dgst)
|
||||
}
|
||||
|
||||
if err := os.Rename(ingest, target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ingest has now been made available in the content store, attempt to complete
|
||||
// setting metadata but errors should only be logged and not returned since
|
||||
// the content store cannot be cleanly rolled back.
|
||||
|
||||
commitTime := time.Now()
|
||||
if err := os.Chtimes(target, commitTime, commitTime); err != nil {
|
||||
log.G(ctx).WithField("digest", dgst).Errorf("failed to change file time to commit time")
|
||||
}
|
||||
|
||||
// clean up!!
|
||||
if err := os.RemoveAll(w.path); err != nil {
|
||||
log.G(ctx).WithField("ref", w.ref).WithField("path", w.path).Errorf("failed to remove ingest directory")
|
||||
}
|
||||
|
||||
if w.s.ls != nil && base.Labels != nil {
|
||||
if err := w.s.ls.Set(dgst, base.Labels); err != nil {
|
||||
log.G(ctx).WithField("digest", dgst).Errorf("failed to set labels")
|
||||
}
|
||||
}
|
||||
|
||||
// change to readonly, more important for read, but provides _some_
|
||||
// protection from this point on. We use the existing perms with a mask
|
||||
// only allowing reads honoring the umask on creation.
|
||||
//
|
||||
// This removes write and exec, only allowing read per the creation umask.
|
||||
//
|
||||
// NOTE: Windows does not support this operation
|
||||
if runtime.GOOS != "windows" {
|
||||
if err := os.Chmod(target, (fi.Mode()&os.ModePerm)&^0333); err != nil {
|
||||
log.G(ctx).WithField("ref", w.ref).Errorf("failed to make readonly")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close the writer, flushing any unwritten data and leaving the progress in
|
||||
// tact.
|
||||
//
|
||||
// If one needs to resume the transaction, a new writer can be obtained from
|
||||
// `Ingester.Writer` using the same key. The write can then be continued
|
||||
// from it was left off.
|
||||
//
|
||||
// To abandon a transaction completely, first call close then `IngestManager.Abort` to
|
||||
// clean up the associated resources.
|
||||
func (w *writer) Close() (err error) {
|
||||
if w.fp != nil {
|
||||
w.fp.Sync()
|
||||
err = w.fp.Close()
|
||||
writeTimestampFile(filepath.Join(w.path, "updatedat"), w.updatedAt)
|
||||
w.fp = nil
|
||||
unlock(w.ref)
|
||||
return
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *writer) Truncate(size int64) error {
|
||||
if size != 0 {
|
||||
return errors.New("Truncate: unsupported size")
|
||||
}
|
||||
w.offset = 0
|
||||
w.digester.Hash().Reset()
|
||||
if _, err := w.fp.Seek(0, io.SeekStart); err != nil {
|
||||
return err
|
||||
}
|
||||
return w.fp.Truncate(0)
|
||||
}
|
2
vendor/github.com/containerd/containerd/errdefs/grpc.go
generated
vendored
2
vendor/github.com/containerd/containerd/errdefs/grpc.go
generated
vendored
@ -95,7 +95,7 @@ func FromGRPC(err error) error {
|
||||
|
||||
msg := rebaseMessage(cls, err)
|
||||
if msg != "" {
|
||||
err = errors.Wrapf(cls, msg)
|
||||
err = errors.Wrap(cls, msg)
|
||||
} else {
|
||||
err = errors.WithStack(cls)
|
||||
}
|
||||
|
8
vendor/github.com/containerd/containerd/events/exchange/exchange.go
generated
vendored
8
vendor/github.com/containerd/containerd/events/exchange/exchange.go
generated
vendored
@ -138,10 +138,10 @@ func (e *Exchange) Subscribe(ctx context.Context, fs ...string) (ch <-chan *even
|
||||
)
|
||||
|
||||
closeAll := func() {
|
||||
defer close(errq)
|
||||
defer e.broadcaster.Remove(dst)
|
||||
defer queue.Close()
|
||||
defer channel.Close()
|
||||
channel.Close()
|
||||
queue.Close()
|
||||
e.broadcaster.Remove(dst)
|
||||
close(errq)
|
||||
}
|
||||
|
||||
ch = evch
|
||||
|
25
vendor/github.com/containerd/containerd/export.go
generated
vendored
25
vendor/github.com/containerd/containerd/export.go
generated
vendored
@ -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"))
|
||||
|
2
vendor/github.com/containerd/containerd/filters/parser.go
generated
vendored
2
vendor/github.com/containerd/containerd/filters/parser.go
generated
vendored
@ -71,7 +71,7 @@ func ParseAll(ss ...string) (Filter, error) {
|
||||
for _, s := range ss {
|
||||
f, err := Parse(s)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error())
|
||||
return nil, errors.Wrap(errdefs.ErrInvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
fs = append(fs, f)
|
||||
|
2
vendor/github.com/containerd/containerd/identifiers/validate.go
generated
vendored
2
vendor/github.com/containerd/containerd/identifiers/validate.go
generated
vendored
@ -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.
|
||||
|
16
vendor/github.com/containerd/containerd/images/handlers.go
generated
vendored
16
vendor/github.com/containerd/containerd/images/handlers.go
generated
vendored
@ -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
|
||||
|
13
vendor/github.com/containerd/containerd/images/mediatypes.go
generated
vendored
13
vendor/github.com/containerd/containerd/images/mediatypes.go
generated
vendored
@ -29,11 +29,14 @@ const (
|
||||
MediaTypeDockerSchema2Manifest = "application/vnd.docker.distribution.manifest.v2+json"
|
||||
MediaTypeDockerSchema2ManifestList = "application/vnd.docker.distribution.manifest.list.v2+json"
|
||||
// Checkpoint/Restore Media Types
|
||||
MediaTypeContainerd1Checkpoint = "application/vnd.containerd.container.criu.checkpoint.criu.tar"
|
||||
MediaTypeContainerd1CheckpointPreDump = "application/vnd.containerd.container.criu.checkpoint.predump.tar"
|
||||
MediaTypeContainerd1Resource = "application/vnd.containerd.container.resource.tar"
|
||||
MediaTypeContainerd1RW = "application/vnd.containerd.container.rw.tar"
|
||||
MediaTypeContainerd1CheckpointConfig = "application/vnd.containerd.container.checkpoint.config.v1+proto"
|
||||
MediaTypeContainerd1Checkpoint = "application/vnd.containerd.container.criu.checkpoint.criu.tar"
|
||||
MediaTypeContainerd1CheckpointPreDump = "application/vnd.containerd.container.criu.checkpoint.predump.tar"
|
||||
MediaTypeContainerd1Resource = "application/vnd.containerd.container.resource.tar"
|
||||
MediaTypeContainerd1RW = "application/vnd.containerd.container.rw.tar"
|
||||
MediaTypeContainerd1CheckpointConfig = "application/vnd.containerd.container.checkpoint.config.v1+proto"
|
||||
MediaTypeContainerd1CheckpointOptions = "application/vnd.containerd.container.checkpoint.options.v1+proto"
|
||||
MediaTypeContainerd1CheckpointRuntimeName = "application/vnd.containerd.container.checkpoint.runtime.name"
|
||||
MediaTypeContainerd1CheckpointRuntimeOptions = "application/vnd.containerd.container.checkpoint.runtime.options+proto"
|
||||
// Legacy Docker schema1 manifest
|
||||
MediaTypeDockerSchema1Manifest = "application/vnd.docker.distribution.manifest.v1+prettyjws"
|
||||
)
|
||||
|
241
vendor/github.com/containerd/containerd/images/oci/exporter.go
generated
vendored
Normal file
241
vendor/github.com/containerd/containerd/images/oci/exporter.go
generated
vendored
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
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 (
|
||||
"archive/tar"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"sort"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
// V1Exporter implements OCI Image Spec v1.
|
||||
// It is up to caller to put "org.opencontainers.image.ref.name" annotation to desc.
|
||||
//
|
||||
// TODO(AkihiroSuda): add V1Exporter{TranslateMediaTypes: true} that transforms media types,
|
||||
// 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.
|
||||
func (oe *V1Exporter) Export(ctx context.Context, store content.Provider, desc ocispec.Descriptor, writer io.Writer) error {
|
||||
tw := tar.NewWriter(writer)
|
||||
defer tw.Close()
|
||||
|
||||
records := []tarRecord{
|
||||
ociLayoutFile(""),
|
||||
ociIndexRecord(desc),
|
||||
}
|
||||
|
||||
algorithms := map[string]struct{}{}
|
||||
exportHandler := func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
records = append(records, blobRecord(store, desc))
|
||||
algorithms[desc.Digest.Algorithm().String()] = struct{}{}
|
||||
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(
|
||||
childrenHandler,
|
||||
images.HandlerFunc(exportHandler),
|
||||
)
|
||||
|
||||
// Walk sequentially since the number of fetchs is likely one and doing in
|
||||
// parallel requires locking the export handler
|
||||
if err := images.Walk(ctx, handlers, desc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(algorithms) > 0 {
|
||||
records = append(records, directoryRecord("blobs/", 0755))
|
||||
for alg := range algorithms {
|
||||
records = append(records, directoryRecord("blobs/"+alg+"/", 0755))
|
||||
}
|
||||
}
|
||||
|
||||
return writeTar(ctx, tw, records)
|
||||
}
|
||||
|
||||
type tarRecord struct {
|
||||
Header *tar.Header
|
||||
CopyTo func(context.Context, io.Writer) (int64, error)
|
||||
}
|
||||
|
||||
func blobRecord(cs content.Provider, desc ocispec.Descriptor) tarRecord {
|
||||
path := "blobs/" + desc.Digest.Algorithm().String() + "/" + desc.Digest.Hex()
|
||||
return tarRecord{
|
||||
Header: &tar.Header{
|
||||
Name: path,
|
||||
Mode: 0444,
|
||||
Size: desc.Size,
|
||||
Typeflag: tar.TypeReg,
|
||||
},
|
||||
CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
|
||||
r, err := cs.ReaderAt(ctx, desc)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to get reader")
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
// Verify digest
|
||||
dgstr := desc.Digest.Algorithm().Digester()
|
||||
|
||||
n, err := io.Copy(io.MultiWriter(w, dgstr.Hash()), content.NewReader(r))
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to copy to tar")
|
||||
}
|
||||
if dgstr.Digest() != desc.Digest {
|
||||
return 0, errors.Errorf("unexpected digest %s copied", dgstr.Digest())
|
||||
}
|
||||
return n, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func directoryRecord(name string, mode int64) tarRecord {
|
||||
return tarRecord{
|
||||
Header: &tar.Header{
|
||||
Name: name,
|
||||
Mode: mode,
|
||||
Typeflag: tar.TypeDir,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func ociLayoutFile(version string) tarRecord {
|
||||
if version == "" {
|
||||
version = ocispec.ImageLayoutVersion
|
||||
}
|
||||
layout := ocispec.ImageLayout{
|
||||
Version: version,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(layout)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return tarRecord{
|
||||
Header: &tar.Header{
|
||||
Name: ocispec.ImageLayoutFile,
|
||||
Mode: 0444,
|
||||
Size: int64(len(b)),
|
||||
Typeflag: tar.TypeReg,
|
||||
},
|
||||
CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
|
||||
n, err := w.Write(b)
|
||||
return int64(n), err
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func ociIndexRecord(manifests ...ocispec.Descriptor) tarRecord {
|
||||
index := ocispec.Index{
|
||||
Versioned: ocispecs.Versioned{
|
||||
SchemaVersion: 2,
|
||||
},
|
||||
Manifests: manifests,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(index)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return tarRecord{
|
||||
Header: &tar.Header{
|
||||
Name: "index.json",
|
||||
Mode: 0644,
|
||||
Size: int64(len(b)),
|
||||
Typeflag: tar.TypeReg,
|
||||
},
|
||||
CopyTo: func(ctx context.Context, w io.Writer) (int64, error) {
|
||||
n, err := w.Write(b)
|
||||
return int64(n), err
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func writeTar(ctx context.Context, tw *tar.Writer, records []tarRecord) error {
|
||||
sort.Slice(records, func(i, j int) bool {
|
||||
return records[i].Header.Name < records[j].Header.Name
|
||||
})
|
||||
|
||||
for _, record := range records {
|
||||
if err := tw.WriteHeader(record.Header); err != nil {
|
||||
return err
|
||||
}
|
||||
if record.CopyTo != nil {
|
||||
n, err := record.CopyTo(ctx, tw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != record.Header.Size {
|
||||
return errors.Errorf("unexpected copy size for %s", record.Header.Name)
|
||||
}
|
||||
} else if record.Header.Size > 0 {
|
||||
return errors.Errorf("no content to write to record with non-zero size for %s", record.Header.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
21
vendor/github.com/containerd/containerd/import.go
generated
vendored
21
vendor/github.com/containerd/containerd/import.go
generated
vendored
@ -25,14 +25,16 @@ import (
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/images/archive"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
type importOpts struct {
|
||||
indexName string
|
||||
imageRefT func(string) string
|
||||
dgstRefT func(digest.Digest) string
|
||||
indexName string
|
||||
imageRefT func(string) string
|
||||
dgstRefT func(digest.Digest) string
|
||||
allPlatforms bool
|
||||
}
|
||||
|
||||
// ImportOpt allows the caller to specify import specific options
|
||||
@ -64,6 +66,14 @@ func WithIndexName(name string) ImportOpt {
|
||||
}
|
||||
}
|
||||
|
||||
// WithAllPlatforms is used to import content for all platforms.
|
||||
func WithAllPlatforms(allPlatforms bool) ImportOpt {
|
||||
return func(c *importOpts) error {
|
||||
c.allPlatforms = allPlatforms
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Import imports an image from a Tar stream using reader.
|
||||
// Caller needs to specify importer. Future version may use oci.v1 as the default.
|
||||
// Note that unreferrenced blobs may be imported to the content store as well.
|
||||
@ -98,6 +108,10 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt
|
||||
Target: index,
|
||||
})
|
||||
}
|
||||
var platformMatcher = platforms.All
|
||||
if !iopts.allPlatforms {
|
||||
platformMatcher = platforms.Default()
|
||||
}
|
||||
|
||||
var handler images.HandlerFunc = func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
// Only save images at top level
|
||||
@ -141,6 +155,7 @@ func (c *Client) Import(ctx context.Context, reader io.Reader, opts ...ImportOpt
|
||||
return idx.Manifests, nil
|
||||
}
|
||||
|
||||
handler = images.FilterPlatforms(handler, platformMatcher)
|
||||
handler = images.SetChildrenLabels(cs, handler)
|
||||
if err := images.Walk(ctx, handler, index); err != nil {
|
||||
return nil, err
|
||||
|
3
vendor/github.com/containerd/containerd/install.go
generated
vendored
3
vendor/github.com/containerd/containerd/install.go
generated
vendored
@ -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
|
||||
}
|
||||
|
37
vendor/github.com/containerd/containerd/labels/validate.go
generated
vendored
Normal file
37
vendor/github.com/containerd/containerd/labels/validate.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
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 labels
|
||||
|
||||
import (
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
maxSize = 4096
|
||||
)
|
||||
|
||||
// Validate a label's key and value are under 4096 bytes
|
||||
func Validate(k, v string) error {
|
||||
if (len(k) + len(v)) > maxSize {
|
||||
if len(k) > 10 {
|
||||
k = k[:10]
|
||||
}
|
||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "label key and value greater than maximum size (%d bytes), key: %s", maxSize, k)
|
||||
}
|
||||
return nil
|
||||
}
|
11
vendor/github.com/containerd/containerd/oci/spec.go
generated
vendored
11
vendor/github.com/containerd/containerd/oci/spec.go
generated
vendored
@ -247,17 +247,8 @@ func populateDefaultWindowsSpec(ctx context.Context, s *Spec, id string) error {
|
||||
Root: &specs.Root{},
|
||||
Process: &specs.Process{
|
||||
Cwd: `C:\`,
|
||||
ConsoleSize: &specs.Box{
|
||||
Width: 80,
|
||||
Height: 20,
|
||||
},
|
||||
},
|
||||
Windows: &specs.Windows{
|
||||
IgnoreFlushesDuringBoot: true,
|
||||
Network: &specs.WindowsNetwork{
|
||||
AllowUnqualifiedDNSQuery: true,
|
||||
},
|
||||
},
|
||||
Windows: &specs.Windows{},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
134
vendor/github.com/containerd/containerd/oci/spec_opts.go
generated
vendored
134
vendor/github.com/containerd/containerd/oci/spec_opts.go
generated
vendored
@ -33,7 +33,7 @@ import (
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/continuity/fs"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/opencontainers/runc/libcontainer/user"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
@ -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,
|
||||
}
|
||||
@ -733,9 +741,11 @@ func WithCapabilities(caps []string) SpecOpts {
|
||||
}
|
||||
|
||||
// WithAllCapabilities sets all linux capabilities for the process
|
||||
var WithAllCapabilities = WithCapabilities(getAllCapabilities())
|
||||
var WithAllCapabilities = WithCapabilities(GetAllCapabilities())
|
||||
|
||||
func getAllCapabilities() []string {
|
||||
// GetAllCapabilities returns all caps up to CAP_LAST_CAP
|
||||
// or CAP_BLOCK_SUSPEND on RHEL6
|
||||
func GetAllCapabilities() []string {
|
||||
last := capability.CAP_LAST_CAP
|
||||
// hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap
|
||||
if last == capability.Cap(63) {
|
||||
@ -751,6 +761,61 @@ func getAllCapabilities() []string {
|
||||
return caps
|
||||
}
|
||||
|
||||
func capsContain(caps []string, s string) bool {
|
||||
for _, c := range caps {
|
||||
if c == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func removeCap(caps *[]string, s string) {
|
||||
for i, c := range *caps {
|
||||
if c == s {
|
||||
*caps = append((*caps)[:i], (*caps)[i+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithAddedCapabilities adds the provided capabilities
|
||||
func WithAddedCapabilities(caps []string) SpecOpts {
|
||||
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
|
||||
setCapabilities(s)
|
||||
for _, c := range caps {
|
||||
for _, cl := range []*[]string{
|
||||
&s.Process.Capabilities.Bounding,
|
||||
&s.Process.Capabilities.Effective,
|
||||
&s.Process.Capabilities.Permitted,
|
||||
&s.Process.Capabilities.Inheritable,
|
||||
} {
|
||||
if !capsContain(*cl, c) {
|
||||
*cl = append(*cl, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithDroppedCapabilities removes the provided capabilities
|
||||
func WithDroppedCapabilities(caps []string) SpecOpts {
|
||||
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
|
||||
setCapabilities(s)
|
||||
for _, c := range caps {
|
||||
for _, cl := range []*[]string{
|
||||
&s.Process.Capabilities.Bounding,
|
||||
&s.Process.Capabilities.Effective,
|
||||
&s.Process.Capabilities.Permitted,
|
||||
&s.Process.Capabilities.Inheritable,
|
||||
} {
|
||||
removeCap(cl, c)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithAmbientCapabilities set the Linux ambient capabilities for the process
|
||||
// Ambient capabilities should only be set for non-root users or the caller should
|
||||
// understand how these capabilities are used and set
|
||||
@ -1026,3 +1091,46 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
// WithAnnotations appends or replaces the annotations on the spec with the
|
||||
// provided annotations
|
||||
func WithAnnotations(annotations map[string]string) SpecOpts {
|
||||
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
|
||||
if s.Annotations == nil {
|
||||
s.Annotations = make(map[string]string)
|
||||
}
|
||||
for k, v := range annotations {
|
||||
s.Annotations[k] = v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
67
vendor/github.com/containerd/containerd/oci/spec_opts_windows.go
generated
vendored
Normal file
67
vendor/github.com/containerd/containerd/oci/spec_opts_windows.go
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
// +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
|
||||
}
|
||||
}
|
||||
|
||||
// WithWindowsIgnoreFlushesDuringBoot sets `Windows.IgnoreFlushesDuringBoot`.
|
||||
func WithWindowsIgnoreFlushesDuringBoot() SpecOpts {
|
||||
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
|
||||
if s.Windows == nil {
|
||||
s.Windows = &specs.Windows{}
|
||||
}
|
||||
s.Windows.IgnoreFlushesDuringBoot = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithWindowNetworksAllowUnqualifiedDNSQuery sets `Windows.IgnoreFlushesDuringBoot`.
|
||||
func WithWindowNetworksAllowUnqualifiedDNSQuery() SpecOpts {
|
||||
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
|
||||
if s.Windows == nil {
|
||||
s.Windows = &specs.Windows{}
|
||||
}
|
||||
if s.Windows.Network == nil {
|
||||
s.Windows.Network = &specs.WindowsNetwork{}
|
||||
}
|
||||
|
||||
s.Windows.Network.AllowUnqualifiedDNSQuery = true
|
||||
return nil
|
||||
}
|
||||
}
|
9
vendor/github.com/containerd/containerd/plugin/plugin.go
generated
vendored
9
vendor/github.com/containerd/containerd/plugin/plugin.go
generated
vendored
@ -75,6 +75,15 @@ const (
|
||||
GCPlugin Type = "io.containerd.gc.v1"
|
||||
)
|
||||
|
||||
const (
|
||||
// RuntimeLinuxV1 is the legacy linux runtime
|
||||
RuntimeLinuxV1 = "io.containerd.runtime.v1.linux"
|
||||
// RuntimeRuncV1 is the runc runtime that supports a single container
|
||||
RuntimeRuncV1 = "io.containerd.runc.v1"
|
||||
// RuntimeRuncV2 is the runc runtime that supports multiple containers per shim
|
||||
RuntimeRuncV2 = "io.containerd.runc.v2"
|
||||
)
|
||||
|
||||
// Registration contains information for registering a plugin
|
||||
type Registration struct {
|
||||
// Type of the plugin
|
||||
|
204
vendor/github.com/containerd/containerd/pull.go
generated
vendored
Normal file
204
vendor/github.com/containerd/containerd/pull.go
generated
vendored
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
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 containerd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/platforms"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
"github.com/containerd/containerd/remotes/docker/schema1"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sync/semaphore"
|
||||
)
|
||||
|
||||
// Pull downloads the provided content into containerd's content store
|
||||
// and returns a platform specific image object
|
||||
func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpt) (Image, error) {
|
||||
pullCtx := defaultRemoteContext()
|
||||
for _, o := range opts {
|
||||
if err := o(c, pullCtx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if pullCtx.PlatformMatcher == nil {
|
||||
if len(pullCtx.Platforms) > 1 {
|
||||
return nil, errors.New("cannot pull multiplatform image locally, try Fetch")
|
||||
} else if len(pullCtx.Platforms) == 0 {
|
||||
pullCtx.PlatformMatcher = platforms.Default()
|
||||
} else {
|
||||
p, err := platforms.Parse(pullCtx.Platforms[0])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "invalid platform %s", pullCtx.Platforms[0])
|
||||
}
|
||||
|
||||
pullCtx.PlatformMatcher = platforms.Only(p)
|
||||
}
|
||||
}
|
||||
|
||||
ctx, done, err := c.WithLease(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer done(ctx)
|
||||
|
||||
img, err := c.fetch(ctx, pullCtx, ref, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i := NewImageWithPlatform(c, img, pullCtx.PlatformMatcher)
|
||||
|
||||
if pullCtx.Unpack {
|
||||
if err := i.Unpack(ctx, pullCtx.Snapshotter); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unpack image on snapshotter %s", pullCtx.Snapshotter)
|
||||
}
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, limit int) (images.Image, error) {
|
||||
store := c.ContentStore()
|
||||
name, desc, err := rCtx.Resolver.Resolve(ctx, ref)
|
||||
if err != nil {
|
||||
return images.Image{}, errors.Wrapf(err, "failed to resolve reference %q", ref)
|
||||
}
|
||||
|
||||
fetcher, err := rCtx.Resolver.Fetcher(ctx, name)
|
||||
if err != nil {
|
||||
return images.Image{}, errors.Wrapf(err, "failed to get fetcher for %q", name)
|
||||
}
|
||||
|
||||
var (
|
||||
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)
|
||||
|
||||
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)
|
||||
// Set any children labels for that content
|
||||
childrenHandler = images.SetChildrenLabels(store, childrenHandler)
|
||||
// Filter manifests by platforms but allow to handle manifest
|
||||
// and configuration for not-target platforms
|
||||
childrenHandler = remotes.FilterManifestByPlatformHandler(childrenHandler, rCtx.PlatformMatcher)
|
||||
// Sort and limit manifests if a finite number is needed
|
||||
if limit > 0 {
|
||||
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
|
||||
},
|
||||
)
|
||||
|
||||
handlers := append(rCtx.BaseHandlers,
|
||||
remotes.FetchHandler(store, fetcher),
|
||||
convertibleHandler,
|
||||
childrenHandler,
|
||||
)
|
||||
|
||||
// append distribution source label to blob data
|
||||
if rCtx.AppendDistributionSourceLabel {
|
||||
appendDistSrcLabelHandler, err := docker.AppendDistributionSourceLabel(store, ref)
|
||||
if err != nil {
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
handlers = append(handlers, appendDistSrcLabelHandler)
|
||||
}
|
||||
|
||||
handler = images.Handlers(handlers...)
|
||||
|
||||
converterFunc = func(ctx context.Context, desc ocispec.Descriptor) (ocispec.Descriptor, error) {
|
||||
return docker.ConvertManifest(ctx, store, desc)
|
||||
}
|
||||
}
|
||||
|
||||
if rCtx.HandlerWrapper != nil {
|
||||
handler = rCtx.HandlerWrapper(handler)
|
||||
}
|
||||
|
||||
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 isConvertible {
|
||||
if desc, err = converterFunc(ctx, desc); err != nil {
|
||||
return images.Image{}, err
|
||||
}
|
||||
}
|
||||
|
||||
img := images.Image{
|
||||
Name: name,
|
||||
Target: desc,
|
||||
Labels: rCtx.Labels,
|
||||
}
|
||||
|
||||
is := c.ImageService()
|
||||
for {
|
||||
if created, err := is.Create(ctx, img); err != nil {
|
||||
if !errdefs.IsAlreadyExists(err) {
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
updated, err := is.Update(ctx, img)
|
||||
if err != nil {
|
||||
// if image was removed, try create again
|
||||
if errdefs.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
img = updated
|
||||
} else {
|
||||
img = created
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
||||
}
|
8
vendor/github.com/containerd/containerd/remotes/docker/authorizer.go
generated
vendored
8
vendor/github.com/containerd/containerd/remotes/docker/authorizer.go
generated
vendored
@ -81,7 +81,7 @@ func (a *dockerAuthorizer) AddResponses(ctx context.Context, responses []*http.R
|
||||
// TODO(dmcg): Store challenge, not token
|
||||
// Move token fetching to authorize
|
||||
return a.setTokenAuth(ctx, host, c.parameters)
|
||||
} else if c.scheme == basicAuth {
|
||||
} else if c.scheme == basicAuth && a.credentials != nil {
|
||||
// TODO: Resolve credentials on authorize
|
||||
username, secret, err := a.credentials(host)
|
||||
if err != nil {
|
||||
@ -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
|
||||
}
|
||||
|
112
vendor/github.com/containerd/containerd/remotes/docker/handler.go
generated
vendored
Normal file
112
vendor/github.com/containerd/containerd/remotes/docker/handler.go
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
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 (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/labels"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/reference"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
var (
|
||||
// labelDistributionSource describes the source blob comes from.
|
||||
labelDistributionSource = "containerd.io/distribution.source"
|
||||
)
|
||||
|
||||
// AppendDistributionSourceLabel updates the label of blob with distribution source.
|
||||
func AppendDistributionSourceLabel(manager content.Manager, ref string) (images.HandlerFunc, error) {
|
||||
refspec, err := reference.Parse(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u, err := url.Parse("dummy://" + refspec.Locator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
source, repo := u.Hostname(), strings.TrimPrefix(u.Path, "/")
|
||||
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
info, err := manager.Info(ctx, desc.Digest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key := distributionSourceLabelKey(source)
|
||||
|
||||
originLabel := ""
|
||||
if info.Labels != nil {
|
||||
originLabel = info.Labels[key]
|
||||
}
|
||||
value := appendDistributionSourceLabel(originLabel, repo)
|
||||
|
||||
// The repo name has been limited under 256 and the distribution
|
||||
// label might hit the limitation of label size, when blob data
|
||||
// is used as the very, very common layer.
|
||||
if err := labels.Validate(key, value); err != nil {
|
||||
log.G(ctx).Warnf("skip to append distribution label: %s", err)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
info = content.Info{
|
||||
Digest: desc.Digest,
|
||||
Labels: map[string]string{
|
||||
key: value,
|
||||
},
|
||||
}
|
||||
_, err = manager.Update(ctx, info, fmt.Sprintf("labels.%s", key))
|
||||
return nil, err
|
||||
}, nil
|
||||
}
|
||||
|
||||
func appendDistributionSourceLabel(originLabel, repo string) string {
|
||||
repos := []string{}
|
||||
if originLabel != "" {
|
||||
repos = strings.Split(originLabel, ",")
|
||||
}
|
||||
repos = append(repos, repo)
|
||||
|
||||
// use emtpy string to present duplicate items
|
||||
for i := 1; i < len(repos); i++ {
|
||||
tmp, j := repos[i], i-1
|
||||
for ; j >= 0 && repos[j] >= tmp; j-- {
|
||||
if repos[j] == tmp {
|
||||
tmp = ""
|
||||
}
|
||||
repos[j+1] = repos[j]
|
||||
}
|
||||
repos[j+1] = tmp
|
||||
}
|
||||
|
||||
i := 0
|
||||
for ; i < len(repos) && repos[i] == ""; i++ {
|
||||
}
|
||||
|
||||
return strings.Join(repos[i:], ",")
|
||||
}
|
||||
|
||||
func distributionSourceLabelKey(source string) string {
|
||||
return fmt.Sprintf("%s.%s", labelDistributionSource, source)
|
||||
}
|
29
vendor/github.com/containerd/containerd/remotes/docker/resolver.go
generated
vendored
29
vendor/github.com/containerd/containerd/remotes/docker/resolver.go
generated
vendored
@ -29,6 +29,7 @@ import (
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/reference"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/version"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
@ -75,13 +76,16 @@ type ResolverOptions struct {
|
||||
|
||||
// Credentials provides username and secret given a host.
|
||||
// If username is empty but a secret is given, that secret
|
||||
// is interpretted as a long lived token.
|
||||
// is interpreted as a long lived token.
|
||||
// Deprecated: use Authorizer
|
||||
Credentials func(string) (string, string, error)
|
||||
|
||||
// Host provides the hostname given a namespace.
|
||||
Host func(string) (string, error)
|
||||
|
||||
// Headers are the HTTP request header fields sent by the resolver
|
||||
Headers http.Header
|
||||
|
||||
// PlainHTTP specifies to use plain http and not https
|
||||
PlainHTTP bool
|
||||
|
||||
@ -105,6 +109,7 @@ func DefaultHost(ns string) (string, error) {
|
||||
type dockerResolver struct {
|
||||
auth Authorizer
|
||||
host func(string) (string, error)
|
||||
headers http.Header
|
||||
plainHTTP bool
|
||||
client *http.Client
|
||||
tracker StatusTracker
|
||||
@ -118,12 +123,27 @@ func NewResolver(options ResolverOptions) remotes.Resolver {
|
||||
if options.Host == nil {
|
||||
options.Host = DefaultHost
|
||||
}
|
||||
if options.Headers == nil {
|
||||
options.Headers = make(http.Header)
|
||||
}
|
||||
if _, ok := options.Headers["Accept"]; !ok {
|
||||
// set headers for all the types we support for resolution.
|
||||
options.Headers.Set("Accept", strings.Join([]string{
|
||||
images.MediaTypeDockerSchema2Manifest,
|
||||
images.MediaTypeDockerSchema2ManifestList,
|
||||
ocispec.MediaTypeImageManifest,
|
||||
ocispec.MediaTypeImageIndex, "*"}, ", "))
|
||||
}
|
||||
if _, ok := options.Headers["User-Agent"]; !ok {
|
||||
options.Headers.Set("User-Agent", "containerd/"+version.Version)
|
||||
}
|
||||
if options.Authorizer == nil {
|
||||
options.Authorizer = NewAuthorizer(options.Client, options.Credentials)
|
||||
}
|
||||
return &dockerResolver{
|
||||
auth: options.Authorizer,
|
||||
host: options.Host,
|
||||
headers: options.Headers,
|
||||
plainHTTP: options.PlainHTTP,
|
||||
client: options.Client,
|
||||
tracker: options.Tracker,
|
||||
@ -182,12 +202,7 @@ func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocisp
|
||||
return "", ocispec.Descriptor{}, err
|
||||
}
|
||||
|
||||
// set headers for all the types we support for resolution.
|
||||
req.Header.Set("Accept", strings.Join([]string{
|
||||
images.MediaTypeDockerSchema2Manifest,
|
||||
images.MediaTypeDockerSchema2ManifestList,
|
||||
ocispec.MediaTypeImageManifest,
|
||||
ocispec.MediaTypeImageIndex, "*"}, ", "))
|
||||
req.Header = r.headers
|
||||
|
||||
log.G(ctx).Debug("resolving")
|
||||
resp, err := fetcher.doRequestWithRetries(ctx, req, nil)
|
||||
|
44
vendor/github.com/containerd/containerd/remotes/handlers.go
generated
vendored
44
vendor/github.com/containerd/containerd/remotes/handlers.go
generated
vendored
@ -156,7 +156,7 @@ func push(ctx context.Context, provider content.Provider, pusher Pusher, desc oc
|
||||
//
|
||||
// Base handlers can be provided which will be called before any push specific
|
||||
// handlers.
|
||||
func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, provider content.Provider, platform platforms.MatchComparer, baseHandlers ...images.Handler) error {
|
||||
func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, provider content.Provider, platform platforms.MatchComparer, wrapper func(h images.Handler) images.Handler) error {
|
||||
var m sync.Mutex
|
||||
manifestStack := []ocispec.Descriptor{}
|
||||
|
||||
@ -175,13 +175,16 @@ func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, pr
|
||||
|
||||
pushHandler := PushHandler(pusher, provider)
|
||||
|
||||
handlers := append(baseHandlers,
|
||||
var handler images.Handler = images.Handlers(
|
||||
images.FilterPlatforms(images.ChildrenHandler(provider), platform),
|
||||
filterHandler,
|
||||
pushHandler,
|
||||
)
|
||||
if wrapper != nil {
|
||||
handler = wrapper(handler)
|
||||
}
|
||||
|
||||
if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
|
||||
if err := images.Dispatch(ctx, handler, nil, desc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -203,3 +206,38 @@ func PushContent(ctx context.Context, pusher Pusher, desc ocispec.Descriptor, pr
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FilterManifestByPlatformHandler allows Handler to handle non-target
|
||||
// platform's manifest and configuration data.
|
||||
func FilterManifestByPlatformHandler(f images.HandlerFunc, m platforms.Matcher) images.HandlerFunc {
|
||||
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
|
||||
children, err := f(ctx, desc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// no platform information
|
||||
if desc.Platform == nil || m == nil {
|
||||
return children, nil
|
||||
}
|
||||
|
||||
var descs []ocispec.Descriptor
|
||||
switch desc.MediaType {
|
||||
case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
|
||||
if m.Match(*desc.Platform) {
|
||||
descs = children
|
||||
} else {
|
||||
for _, child := range children {
|
||||
if child.MediaType == images.MediaTypeDockerSchema2Config ||
|
||||
child.MediaType == ocispec.MediaTypeImageConfig {
|
||||
|
||||
descs = append(descs, child)
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
descs = children
|
||||
}
|
||||
return descs, nil
|
||||
}
|
||||
}
|
||||
|
28
vendor/github.com/containerd/containerd/runtime/linux/runctypes/next.pb.txt
generated
vendored
28
vendor/github.com/containerd/containerd/runtime/linux/runctypes/next.pb.txt
generated
vendored
@ -112,6 +112,20 @@ file {
|
||||
type: TYPE_UINT32
|
||||
json_name: "ioGid"
|
||||
}
|
||||
field {
|
||||
name: "criu_work_path"
|
||||
number: 12
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "criuWorkPath"
|
||||
}
|
||||
field {
|
||||
name: "criu_image_path"
|
||||
number: 13
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "criuImagePath"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "CheckpointOptions"
|
||||
@ -164,6 +178,20 @@ file {
|
||||
type: TYPE_STRING
|
||||
json_name: "cgroupsMode"
|
||||
}
|
||||
field {
|
||||
name: "work_path"
|
||||
number: 8
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "workPath"
|
||||
}
|
||||
field {
|
||||
name: "image_path"
|
||||
number: 9
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "imagePath"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "ProcessDetails"
|
||||
|
238
vendor/github.com/containerd/containerd/runtime/linux/runctypes/runc.pb.go
generated
vendored
238
vendor/github.com/containerd/containerd/runtime/linux/runctypes/runc.pb.go
generated
vendored
@ -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,
|
||||
}
|
||||
|
4
vendor/github.com/containerd/containerd/runtime/linux/runctypes/runc.proto
generated
vendored
4
vendor/github.com/containerd/containerd/runtime/linux/runctypes/runc.proto
generated
vendored
@ -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 {
|
||||
|
17
vendor/github.com/containerd/containerd/runtime/v2/runc/options/doc.go
generated
vendored
Normal file
17
vendor/github.com/containerd/containerd/runtime/v2/runc/options/doc.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
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 options
|
166
vendor/github.com/containerd/containerd/runtime/v2/runc/options/next.pb.txt
generated
vendored
Normal file
166
vendor/github.com/containerd/containerd/runtime/v2/runc/options/next.pb.txt
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
file {
|
||||
name: "github.com/containerd/containerd/runtime/v2/runc/options/oci.proto"
|
||||
package: "containerd.runc.v1"
|
||||
dependency: "gogoproto/gogo.proto"
|
||||
message_type {
|
||||
name: "Options"
|
||||
field {
|
||||
name: "no_pivot_root"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_BOOL
|
||||
json_name: "noPivotRoot"
|
||||
}
|
||||
field {
|
||||
name: "no_new_keyring"
|
||||
number: 2
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_BOOL
|
||||
json_name: "noNewKeyring"
|
||||
}
|
||||
field {
|
||||
name: "shim_cgroup"
|
||||
number: 3
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "shimCgroup"
|
||||
}
|
||||
field {
|
||||
name: "io_uid"
|
||||
number: 4
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_UINT32
|
||||
json_name: "ioUid"
|
||||
}
|
||||
field {
|
||||
name: "io_gid"
|
||||
number: 5
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_UINT32
|
||||
json_name: "ioGid"
|
||||
}
|
||||
field {
|
||||
name: "binary_name"
|
||||
number: 6
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "binaryName"
|
||||
}
|
||||
field {
|
||||
name: "root"
|
||||
number: 7
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "root"
|
||||
}
|
||||
field {
|
||||
name: "criu_path"
|
||||
number: 8
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "criuPath"
|
||||
}
|
||||
field {
|
||||
name: "systemd_cgroup"
|
||||
number: 9
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_BOOL
|
||||
json_name: "systemdCgroup"
|
||||
}
|
||||
field {
|
||||
name: "criu_image_path"
|
||||
number: 10
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "criuImagePath"
|
||||
}
|
||||
field {
|
||||
name: "criu_work_path"
|
||||
number: 11
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "criuWorkPath"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "CheckpointOptions"
|
||||
field {
|
||||
name: "exit"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_BOOL
|
||||
json_name: "exit"
|
||||
}
|
||||
field {
|
||||
name: "open_tcp"
|
||||
number: 2
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_BOOL
|
||||
json_name: "openTcp"
|
||||
}
|
||||
field {
|
||||
name: "external_unix_sockets"
|
||||
number: 3
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_BOOL
|
||||
json_name: "externalUnixSockets"
|
||||
}
|
||||
field {
|
||||
name: "terminal"
|
||||
number: 4
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_BOOL
|
||||
json_name: "terminal"
|
||||
}
|
||||
field {
|
||||
name: "file_locks"
|
||||
number: 5
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_BOOL
|
||||
json_name: "fileLocks"
|
||||
}
|
||||
field {
|
||||
name: "empty_namespaces"
|
||||
number: 6
|
||||
label: LABEL_REPEATED
|
||||
type: TYPE_STRING
|
||||
json_name: "emptyNamespaces"
|
||||
}
|
||||
field {
|
||||
name: "cgroups_mode"
|
||||
number: 7
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "cgroupsMode"
|
||||
}
|
||||
field {
|
||||
name: "image_path"
|
||||
number: 8
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "imagePath"
|
||||
}
|
||||
field {
|
||||
name: "work_path"
|
||||
number: 9
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "workPath"
|
||||
}
|
||||
}
|
||||
message_type {
|
||||
name: "ProcessDetails"
|
||||
field {
|
||||
name: "exec_id"
|
||||
number: 1
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
json_name: "execId"
|
||||
}
|
||||
}
|
||||
options {
|
||||
go_package: "github.com/containerd/containerd/runtime/v2/runc/options;options"
|
||||
}
|
||||
weak_dependency: 0
|
||||
syntax: "proto3"
|
||||
}
|
1313
vendor/github.com/containerd/containerd/runtime/v2/runc/options/oci.pb.go
generated
vendored
Normal file
1313
vendor/github.com/containerd/containerd/runtime/v2/runc/options/oci.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
58
vendor/github.com/containerd/containerd/runtime/v2/runc/options/oci.proto
generated
vendored
Normal file
58
vendor/github.com/containerd/containerd/runtime/v2/runc/options/oci.proto
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package containerd.runc.v1;
|
||||
|
||||
import weak "gogoproto/gogo.proto";
|
||||
|
||||
option go_package = "github.com/containerd/containerd/runtime/v2/runc/options;options";
|
||||
|
||||
message Options {
|
||||
// disable pivot root when creating a container
|
||||
bool no_pivot_root = 1;
|
||||
// create a new keyring for the container
|
||||
bool no_new_keyring = 2;
|
||||
// place the shim in a cgroup
|
||||
string shim_cgroup = 3;
|
||||
// set the I/O's pipes uid
|
||||
uint32 io_uid = 4;
|
||||
// set the I/O's pipes gid
|
||||
uint32 io_gid = 5;
|
||||
// binary name of the runc binary
|
||||
string binary_name = 6;
|
||||
// runc root directory
|
||||
string root = 7;
|
||||
// criu binary path
|
||||
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 {
|
||||
// exit the container after a checkpoint
|
||||
bool exit = 1;
|
||||
// checkpoint open tcp connections
|
||||
bool open_tcp = 2;
|
||||
// checkpoint external unix sockets
|
||||
bool external_unix_sockets = 3;
|
||||
// checkpoint terminals (ptys)
|
||||
bool terminal = 4;
|
||||
// allow checkpointing of file locks
|
||||
bool file_locks = 5;
|
||||
// restore provided namespaces as empty namespaces
|
||||
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 {
|
||||
// exec process id if the process is managed by a shim
|
||||
string exec_id = 1;
|
||||
}
|
463
vendor/github.com/containerd/containerd/services/content/contentserver/contentserver.go
generated
vendored
Normal file
463
vendor/github.com/containerd/containerd/services/content/contentserver/contentserver.go
generated
vendored
Normal file
@ -0,0 +1,463 @@
|
||||
/*
|
||||
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 contentserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
api "github.com/containerd/containerd/api/services/content/v1"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/log"
|
||||
ptypes "github.com/gogo/protobuf/types"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
store content.Store
|
||||
}
|
||||
|
||||
var bufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
buffer := make([]byte, 1<<20)
|
||||
return &buffer
|
||||
},
|
||||
}
|
||||
|
||||
// New returns the content GRPC server
|
||||
func New(cs content.Store) api.ContentServer {
|
||||
return &service{store: cs}
|
||||
}
|
||||
|
||||
func (s *service) Register(server *grpc.Server) error {
|
||||
api.RegisterContentServer(server, s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) Info(ctx context.Context, req *api.InfoRequest) (*api.InfoResponse, error) {
|
||||
if err := req.Digest.Validate(); err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "%q failed validation", req.Digest)
|
||||
}
|
||||
|
||||
bi, err := s.store.Info(ctx, req.Digest)
|
||||
if err != nil {
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
return &api.InfoResponse{
|
||||
Info: infoToGRPC(bi),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *service) Update(ctx context.Context, req *api.UpdateRequest) (*api.UpdateResponse, error) {
|
||||
if err := req.Info.Digest.Validate(); err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "%q failed validation", req.Info.Digest)
|
||||
}
|
||||
|
||||
info, err := s.store.Update(ctx, infoFromGRPC(req.Info), req.UpdateMask.GetPaths()...)
|
||||
if err != nil {
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
return &api.UpdateResponse{
|
||||
Info: infoToGRPC(info),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *service) List(req *api.ListContentRequest, session api.Content_ListServer) error {
|
||||
var (
|
||||
buffer []api.Info
|
||||
sendBlock = func(block []api.Info) error {
|
||||
// send last block
|
||||
return session.Send(&api.ListContentResponse{
|
||||
Info: block,
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
if err := s.store.Walk(session.Context(), func(info content.Info) error {
|
||||
buffer = append(buffer, api.Info{
|
||||
Digest: info.Digest,
|
||||
Size_: info.Size,
|
||||
CreatedAt: info.CreatedAt,
|
||||
Labels: info.Labels,
|
||||
})
|
||||
|
||||
if len(buffer) >= 100 {
|
||||
if err := sendBlock(buffer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buffer = buffer[:0]
|
||||
}
|
||||
|
||||
return nil
|
||||
}, req.Filters...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(buffer) > 0 {
|
||||
// send last block
|
||||
if err := sendBlock(buffer); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) Delete(ctx context.Context, req *api.DeleteContentRequest) (*ptypes.Empty, error) {
|
||||
log.G(ctx).WithField("digest", req.Digest).Debugf("delete content")
|
||||
if err := req.Digest.Validate(); err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
if err := s.store.Delete(ctx, req.Digest); err != nil {
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
return &ptypes.Empty{}, nil
|
||||
}
|
||||
|
||||
func (s *service) Read(req *api.ReadContentRequest, session api.Content_ReadServer) error {
|
||||
if err := req.Digest.Validate(); err != nil {
|
||||
return status.Errorf(codes.InvalidArgument, "%v: %v", req.Digest, err)
|
||||
}
|
||||
|
||||
oi, err := s.store.Info(session.Context(), req.Digest)
|
||||
if err != nil {
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
ra, err := s.store.ReaderAt(session.Context(), ocispec.Descriptor{Digest: req.Digest})
|
||||
if err != nil {
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
defer ra.Close()
|
||||
|
||||
var (
|
||||
offset = req.Offset
|
||||
// size is read size, not the expected size of the blob (oi.Size), which the caller might not be aware of.
|
||||
// offset+size can be larger than oi.Size.
|
||||
size = req.Size_
|
||||
|
||||
// TODO(stevvooe): Using the global buffer pool. At 32KB, it is probably
|
||||
// little inefficient for work over a fast network. We can tune this later.
|
||||
p = bufPool.Get().(*[]byte)
|
||||
)
|
||||
defer bufPool.Put(p)
|
||||
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
|
||||
if offset > oi.Size {
|
||||
return status.Errorf(codes.OutOfRange, "read past object length %v bytes", oi.Size)
|
||||
}
|
||||
|
||||
if size <= 0 || offset+size > oi.Size {
|
||||
size = oi.Size - offset
|
||||
}
|
||||
|
||||
_, err = io.CopyBuffer(
|
||||
&readResponseWriter{session: session},
|
||||
io.NewSectionReader(ra, offset, size), *p)
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
// readResponseWriter is a writer that places the output into ReadContentRequest messages.
|
||||
//
|
||||
// This allows io.CopyBuffer to do the heavy lifting of chunking the responses
|
||||
// into the buffer size.
|
||||
type readResponseWriter struct {
|
||||
offset int64
|
||||
session api.Content_ReadServer
|
||||
}
|
||||
|
||||
func (rw *readResponseWriter) Write(p []byte) (n int, err error) {
|
||||
if err := rw.session.Send(&api.ReadContentResponse{
|
||||
Offset: rw.offset,
|
||||
Data: p,
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
rw.offset += int64(len(p))
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (s *service) Status(ctx context.Context, req *api.StatusRequest) (*api.StatusResponse, error) {
|
||||
status, err := s.store.Status(ctx, req.Ref)
|
||||
if err != nil {
|
||||
return nil, errdefs.ToGRPCf(err, "could not get status for ref %q", req.Ref)
|
||||
}
|
||||
|
||||
var resp api.StatusResponse
|
||||
resp.Status = &api.Status{
|
||||
StartedAt: status.StartedAt,
|
||||
UpdatedAt: status.UpdatedAt,
|
||||
Ref: status.Ref,
|
||||
Offset: status.Offset,
|
||||
Total: status.Total,
|
||||
Expected: status.Expected,
|
||||
}
|
||||
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (s *service) ListStatuses(ctx context.Context, req *api.ListStatusesRequest) (*api.ListStatusesResponse, error) {
|
||||
statuses, err := s.store.ListStatuses(ctx, req.Filters...)
|
||||
if err != nil {
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
var resp api.ListStatusesResponse
|
||||
for _, status := range statuses {
|
||||
resp.Statuses = append(resp.Statuses, api.Status{
|
||||
StartedAt: status.StartedAt,
|
||||
UpdatedAt: status.UpdatedAt,
|
||||
Ref: status.Ref,
|
||||
Offset: status.Offset,
|
||||
Total: status.Total,
|
||||
Expected: status.Expected,
|
||||
})
|
||||
}
|
||||
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (s *service) Write(session api.Content_WriteServer) (err error) {
|
||||
var (
|
||||
ctx = session.Context()
|
||||
msg api.WriteContentResponse
|
||||
req *api.WriteContentRequest
|
||||
ref string
|
||||
total int64
|
||||
expected digest.Digest
|
||||
)
|
||||
|
||||
defer func(msg *api.WriteContentResponse) {
|
||||
// pump through the last message if no error was encountered
|
||||
if err != nil {
|
||||
if s, ok := status.FromError(err); ok && s.Code() != codes.AlreadyExists {
|
||||
// TODO(stevvooe): Really need a log line here to track which
|
||||
// errors are actually causing failure on the server side. May want
|
||||
// to configure the service with an interceptor to make this work
|
||||
// identically across all GRPC methods.
|
||||
//
|
||||
// This is pretty noisy, so we can remove it but leave it for now.
|
||||
log.G(ctx).WithError(err).Error("(*service).Write failed")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err = session.Send(msg)
|
||||
}(&msg)
|
||||
|
||||
// handle the very first request!
|
||||
req, err = session.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ref = req.Ref
|
||||
|
||||
if ref == "" {
|
||||
return status.Errorf(codes.InvalidArgument, "first message must have a reference")
|
||||
}
|
||||
|
||||
fields := logrus.Fields{
|
||||
"ref": ref,
|
||||
}
|
||||
total = req.Total
|
||||
expected = req.Expected
|
||||
if total > 0 {
|
||||
fields["total"] = total
|
||||
}
|
||||
|
||||
if expected != "" {
|
||||
fields["expected"] = expected
|
||||
}
|
||||
|
||||
ctx = log.WithLogger(ctx, log.G(ctx).WithFields(fields))
|
||||
|
||||
log.G(ctx).Debug("(*service).Write started")
|
||||
// this action locks the writer for the session.
|
||||
wr, err := s.store.Writer(ctx,
|
||||
content.WithRef(ref),
|
||||
content.WithDescriptor(ocispec.Descriptor{Size: total, Digest: expected}))
|
||||
if err != nil {
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
defer wr.Close()
|
||||
|
||||
for {
|
||||
msg.Action = req.Action
|
||||
ws, err := wr.Status()
|
||||
if err != nil {
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
msg.Offset = ws.Offset // always set the offset.
|
||||
|
||||
// NOTE(stevvooe): In general, there are two cases underwhich a remote
|
||||
// writer is used.
|
||||
//
|
||||
// For pull, we almost always have this before fetching large content,
|
||||
// through descriptors. We allow predeclaration of the expected size
|
||||
// and digest.
|
||||
//
|
||||
// For push, it is more complex. If we want to cut through content into
|
||||
// storage, we may have no expectation until we are done processing the
|
||||
// content. The case here is the following:
|
||||
//
|
||||
// 1. Start writing content.
|
||||
// 2. Compress inline.
|
||||
// 3. Validate digest and size (maybe).
|
||||
//
|
||||
// Supporting these two paths is quite awkward but it lets both API
|
||||
// users use the same writer style for each with a minimum of overhead.
|
||||
if req.Expected != "" {
|
||||
if expected != "" && expected != req.Expected {
|
||||
log.G(ctx).Debugf("commit digest differs from writer digest: %v != %v", req.Expected, expected)
|
||||
}
|
||||
expected = req.Expected
|
||||
|
||||
if _, err := s.store.Info(session.Context(), req.Expected); err == nil {
|
||||
if err := wr.Close(); err != nil {
|
||||
log.G(ctx).WithError(err).Error("failed to close writer")
|
||||
}
|
||||
if err := s.store.Abort(session.Context(), ref); err != nil {
|
||||
log.G(ctx).WithError(err).Error("failed to abort write")
|
||||
}
|
||||
|
||||
return status.Errorf(codes.AlreadyExists, "blob with expected digest %v exists", req.Expected)
|
||||
}
|
||||
}
|
||||
|
||||
if req.Total > 0 {
|
||||
// Update the expected total. Typically, this could be seen at
|
||||
// negotiation time or on a commit message.
|
||||
if total > 0 && req.Total != total {
|
||||
log.G(ctx).Debugf("commit size differs from writer size: %v != %v", req.Total, total)
|
||||
}
|
||||
total = req.Total
|
||||
}
|
||||
|
||||
switch req.Action {
|
||||
case api.WriteActionStat:
|
||||
msg.Digest = wr.Digest()
|
||||
msg.StartedAt = ws.StartedAt
|
||||
msg.UpdatedAt = ws.UpdatedAt
|
||||
msg.Total = total
|
||||
case api.WriteActionWrite, api.WriteActionCommit:
|
||||
if req.Offset > 0 {
|
||||
// validate the offset if provided
|
||||
if req.Offset != ws.Offset {
|
||||
return status.Errorf(codes.OutOfRange, "write @%v must occur at current offset %v", req.Offset, ws.Offset)
|
||||
}
|
||||
}
|
||||
|
||||
if req.Offset == 0 && ws.Offset > 0 {
|
||||
if err := wr.Truncate(req.Offset); err != nil {
|
||||
return errors.Wrapf(err, "truncate failed")
|
||||
}
|
||||
msg.Offset = req.Offset
|
||||
}
|
||||
|
||||
// issue the write if we actually have data.
|
||||
if len(req.Data) > 0 {
|
||||
// While this looks like we could use io.WriterAt here, because we
|
||||
// maintain the offset as append only, we just issue the write.
|
||||
n, err := wr.Write(req.Data)
|
||||
if err != nil {
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
if n != len(req.Data) {
|
||||
// TODO(stevvooe): Perhaps, we can recover this by including it
|
||||
// in the offset on the write return.
|
||||
return status.Errorf(codes.DataLoss, "wrote %v of %v bytes", n, len(req.Data))
|
||||
}
|
||||
|
||||
msg.Offset += int64(n)
|
||||
}
|
||||
|
||||
if req.Action == api.WriteActionCommit {
|
||||
var opts []content.Opt
|
||||
if req.Labels != nil {
|
||||
opts = append(opts, content.WithLabels(req.Labels))
|
||||
}
|
||||
if err := wr.Commit(ctx, total, expected, opts...); err != nil {
|
||||
return errdefs.ToGRPC(err)
|
||||
}
|
||||
}
|
||||
|
||||
msg.Digest = wr.Digest()
|
||||
}
|
||||
|
||||
if err := session.Send(&msg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err = session.Recv()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) Abort(ctx context.Context, req *api.AbortRequest) (*ptypes.Empty, error) {
|
||||
if err := s.store.Abort(ctx, req.Ref); err != nil {
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
|
||||
return &ptypes.Empty{}, nil
|
||||
}
|
||||
|
||||
func infoToGRPC(info content.Info) api.Info {
|
||||
return api.Info{
|
||||
Digest: info.Digest,
|
||||
Size_: info.Size,
|
||||
CreatedAt: info.CreatedAt,
|
||||
UpdatedAt: info.UpdatedAt,
|
||||
Labels: info.Labels,
|
||||
}
|
||||
}
|
||||
|
||||
func infoFromGRPC(info api.Info) content.Info {
|
||||
return content.Info{
|
||||
Digest: info.Digest,
|
||||
Size: info.Size_,
|
||||
CreatedAt: info.CreatedAt,
|
||||
UpdatedAt: info.UpdatedAt,
|
||||
Labels: info.Labels,
|
||||
}
|
||||
}
|
60
vendor/github.com/containerd/containerd/signal_map_linux.go
generated
vendored
60
vendor/github.com/containerd/containerd/signal_map_linux.go
generated
vendored
@ -1,60 +0,0 @@
|
||||
/*
|
||||
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 containerd
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var signalMap = map[string]syscall.Signal{
|
||||
"ABRT": unix.SIGABRT,
|
||||
"ALRM": unix.SIGALRM,
|
||||
"BUS": unix.SIGBUS,
|
||||
"CHLD": unix.SIGCHLD,
|
||||
"CLD": unix.SIGCLD,
|
||||
"CONT": unix.SIGCONT,
|
||||
"FPE": unix.SIGFPE,
|
||||
"HUP": unix.SIGHUP,
|
||||
"ILL": unix.SIGILL,
|
||||
"INT": unix.SIGINT,
|
||||
"IO": unix.SIGIO,
|
||||
"IOT": unix.SIGIOT,
|
||||
"KILL": unix.SIGKILL,
|
||||
"PIPE": unix.SIGPIPE,
|
||||
"POLL": unix.SIGPOLL,
|
||||
"PROF": unix.SIGPROF,
|
||||
"PWR": unix.SIGPWR,
|
||||
"QUIT": unix.SIGQUIT,
|
||||
"SEGV": unix.SIGSEGV,
|
||||
"STKFLT": unix.SIGSTKFLT,
|
||||
"STOP": unix.SIGSTOP,
|
||||
"SYS": unix.SIGSYS,
|
||||
"TERM": unix.SIGTERM,
|
||||
"TRAP": unix.SIGTRAP,
|
||||
"TSTP": unix.SIGTSTP,
|
||||
"TTIN": unix.SIGTTIN,
|
||||
"TTOU": unix.SIGTTOU,
|
||||
"URG": unix.SIGURG,
|
||||
"USR1": unix.SIGUSR1,
|
||||
"USR2": unix.SIGUSR2,
|
||||
"VTALRM": unix.SIGVTALRM,
|
||||
"WINCH": unix.SIGWINCH,
|
||||
"XCPU": unix.SIGXCPU,
|
||||
"XFSZ": unix.SIGXFSZ,
|
||||
}
|
58
vendor/github.com/containerd/containerd/signal_map_unix.go
generated
vendored
58
vendor/github.com/containerd/containerd/signal_map_unix.go
generated
vendored
@ -1,58 +0,0 @@
|
||||
// +build darwin freebsd solaris
|
||||
|
||||
/*
|
||||
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 containerd
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var signalMap = map[string]syscall.Signal{
|
||||
"ABRT": unix.SIGABRT,
|
||||
"ALRM": unix.SIGALRM,
|
||||
"BUS": unix.SIGBUS,
|
||||
"CHLD": unix.SIGCHLD,
|
||||
"CONT": unix.SIGCONT,
|
||||
"FPE": unix.SIGFPE,
|
||||
"HUP": unix.SIGHUP,
|
||||
"ILL": unix.SIGILL,
|
||||
"INT": unix.SIGINT,
|
||||
"IO": unix.SIGIO,
|
||||
"IOT": unix.SIGIOT,
|
||||
"KILL": unix.SIGKILL,
|
||||
"PIPE": unix.SIGPIPE,
|
||||
"PROF": unix.SIGPROF,
|
||||
"QUIT": unix.SIGQUIT,
|
||||
"SEGV": unix.SIGSEGV,
|
||||
"STOP": unix.SIGSTOP,
|
||||
"SYS": unix.SIGSYS,
|
||||
"TERM": unix.SIGTERM,
|
||||
"TRAP": unix.SIGTRAP,
|
||||
"TSTP": unix.SIGTSTP,
|
||||
"TTIN": unix.SIGTTIN,
|
||||
"TTOU": unix.SIGTTOU,
|
||||
"URG": unix.SIGURG,
|
||||
"USR1": unix.SIGUSR1,
|
||||
"USR2": unix.SIGUSR2,
|
||||
"VTALRM": unix.SIGVTALRM,
|
||||
"WINCH": unix.SIGWINCH,
|
||||
"XCPU": unix.SIGXCPU,
|
||||
"XFSZ": unix.SIGXFSZ,
|
||||
}
|
24
vendor/github.com/containerd/containerd/signals.go
generated
vendored
24
vendor/github.com/containerd/containerd/signals.go
generated
vendored
@ -20,13 +20,11 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
)
|
||||
|
||||
// StopSignalLabel is a well-known containerd label for storing the stop
|
||||
@ -83,23 +81,3 @@ func GetOCIStopSignal(ctx context.Context, image Image, defaultSignal string) (s
|
||||
|
||||
return config.StopSignal, nil
|
||||
}
|
||||
|
||||
// ParseSignal parses a given string into a syscall.Signal
|
||||
// it checks that the signal exists in the platform-appropriate signalMap
|
||||
func ParseSignal(rawSignal string) (syscall.Signal, error) {
|
||||
s, err := strconv.Atoi(rawSignal)
|
||||
if err == nil {
|
||||
sig := syscall.Signal(s)
|
||||
for _, msig := range signalMap {
|
||||
if sig == msig {
|
||||
return sig, nil
|
||||
}
|
||||
}
|
||||
return -1, fmt.Errorf("unknown signal %q", rawSignal)
|
||||
}
|
||||
signal, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")]
|
||||
if !ok {
|
||||
return -1, fmt.Errorf("unknown signal %q", rawSignal)
|
||||
}
|
||||
return signal, nil
|
||||
}
|
||||
|
47
vendor/github.com/containerd/containerd/signals_unix.go
generated
vendored
Normal file
47
vendor/github.com/containerd/containerd/signals_unix.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
||||
/*
|
||||
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 containerd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// ParseSignal parses a given string into a syscall.Signal
|
||||
// the rawSignal can be a string with "SIG" prefix,
|
||||
// or a signal number in string format.
|
||||
func ParseSignal(rawSignal string) (syscall.Signal, error) {
|
||||
s, err := strconv.Atoi(rawSignal)
|
||||
if err == nil {
|
||||
signal := syscall.Signal(s)
|
||||
if unix.SignalName(signal) != "" {
|
||||
return signal, nil
|
||||
}
|
||||
return -1, fmt.Errorf("unknown signal %q", rawSignal)
|
||||
}
|
||||
signal := unix.SignalNum(strings.ToUpper(rawSignal))
|
||||
if signal == 0 {
|
||||
return -1, fmt.Errorf("unknown signal %q", rawSignal)
|
||||
}
|
||||
return signal, nil
|
||||
}
|
@ -17,6 +17,9 @@
|
||||
package containerd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
@ -37,3 +40,24 @@ var signalMap = map[string]syscall.Signal{
|
||||
"ALRM": syscall.Signal(windows.SIGALRM),
|
||||
"TERM": syscall.Signal(windows.SIGTERM),
|
||||
}
|
||||
|
||||
// ParseSignal parses a given string into a syscall.Signal
|
||||
// the rawSignal can be a string with "SIG" prefix,
|
||||
// or a signal number in string format.
|
||||
func ParseSignal(rawSignal string) (syscall.Signal, error) {
|
||||
s, err := strconv.Atoi(rawSignal)
|
||||
if err == nil {
|
||||
sig := syscall.Signal(s)
|
||||
for _, msig := range signalMap {
|
||||
if sig == msig {
|
||||
return sig, nil
|
||||
}
|
||||
}
|
||||
return -1, fmt.Errorf("unknown signal %q", rawSignal)
|
||||
}
|
||||
signal, ok := signalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")]
|
||||
if !ok {
|
||||
return -1, fmt.Errorf("unknown signal %q", rawSignal)
|
||||
}
|
||||
return signal, nil
|
||||
}
|
20
vendor/github.com/containerd/containerd/snapshots/snapshotter.go
generated
vendored
20
vendor/github.com/containerd/containerd/snapshots/snapshotter.go
generated
vendored
@ -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 := snapshots.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.
|
||||
|
61
vendor/github.com/containerd/containerd/task.go
generated
vendored
61
vendor/github.com/containerd/containerd/task.go
generated
vendored
@ -37,11 +37,13 @@ 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"
|
||||
is "github.com/opencontainers/image-spec/specs-go"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -115,6 +117,13 @@ type CheckpointTaskInfo struct {
|
||||
ParentCheckpoint digest.Digest
|
||||
// Options hold runtime specific settings for checkpointing a task
|
||||
Options interface{}
|
||||
|
||||
runtime string
|
||||
}
|
||||
|
||||
// Runtime name for the container
|
||||
func (i *CheckpointTaskInfo) Runtime() string {
|
||||
return i.runtime
|
||||
}
|
||||
|
||||
// CheckpointTaskOpts allows the caller to set checkpoint options
|
||||
@ -129,6 +138,12 @@ type TaskInfo struct {
|
||||
RootFS []mount.Mount
|
||||
// Options hold runtime specific settings for task creation
|
||||
Options interface{}
|
||||
runtime string
|
||||
}
|
||||
|
||||
// Runtime name for the container
|
||||
func (i *TaskInfo) Runtime() string {
|
||||
return i.runtime
|
||||
}
|
||||
|
||||
// Task is the executable object within containerd
|
||||
@ -147,6 +162,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
|
||||
@ -389,17 +406,25 @@ 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 {
|
||||
return nil, err
|
||||
}
|
||||
defer done(ctx)
|
||||
cr, err := t.client.ContainerService().Get(ctx, t.id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request := &tasks.CheckpointTaskRequest{
|
||||
ContainerID: t.id,
|
||||
}
|
||||
var i CheckpointTaskInfo
|
||||
i := CheckpointTaskInfo{
|
||||
runtime: cr.Runtime.Name,
|
||||
}
|
||||
for _, o := range opts {
|
||||
if err := o(&i); err != nil {
|
||||
return nil, err
|
||||
@ -422,10 +447,6 @@ func (t *task) Checkpoint(ctx context.Context, opts ...CheckpointTaskOpts) (Imag
|
||||
return nil, err
|
||||
}
|
||||
defer t.Resume(ctx)
|
||||
cr, err := t.client.ContainerService().Get(ctx, t.id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
index := v1.Index{
|
||||
Versioned: is.Versioned{
|
||||
SchemaVersion: 2,
|
||||
@ -435,6 +456,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
|
||||
@ -544,6 +571,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{
|
||||
@ -621,3 +649,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 plugin.RuntimeRuncV1, plugin.RuntimeRuncV2:
|
||||
if opts, ok := v.(*options.CheckpointOptions); ok && opts.ImagePath != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
case plugin.RuntimeLinuxV1:
|
||||
if opts, ok := v.(*runctypes.CheckpointOptions); ok && opts.ImagePath != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
54
vendor/github.com/containerd/containerd/task_opts.go
generated
vendored
54
vendor/github.com/containerd/containerd/task_opts.go
generated
vendored
@ -27,6 +27,8 @@ 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"
|
||||
@ -89,6 +91,58 @@ func WithCheckpointName(name string) CheckpointTaskOpts {
|
||||
}
|
||||
}
|
||||
|
||||
// WithCheckpointImagePath sets image path for checkpoint option
|
||||
func WithCheckpointImagePath(path string) CheckpointTaskOpts {
|
||||
return func(r *CheckpointTaskInfo) error {
|
||||
if CheckRuntime(r.Runtime(), "io.containerd.runc") {
|
||||
if r.Options == nil {
|
||||
r.Options = &options.CheckpointOptions{}
|
||||
}
|
||||
opts, ok := r.Options.(*options.CheckpointOptions)
|
||||
if !ok {
|
||||
return errors.New("invalid v2 shim checkpoint options format")
|
||||
}
|
||||
opts.ImagePath = path
|
||||
} else {
|
||||
if r.Options == nil {
|
||||
r.Options = &runctypes.CheckpointOptions{}
|
||||
}
|
||||
opts, ok := r.Options.(*runctypes.CheckpointOptions)
|
||||
if !ok {
|
||||
return errors.New("invalid v1 shim checkpoint options format")
|
||||
}
|
||||
opts.ImagePath = path
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithRestoreImagePath sets image path for create option
|
||||
func WithRestoreImagePath(path string) NewTaskOpts {
|
||||
return func(ctx context.Context, c *Client, ti *TaskInfo) error {
|
||||
if CheckRuntime(ti.Runtime(), "io.containerd.runc") {
|
||||
if ti.Options == nil {
|
||||
ti.Options = &options.Options{}
|
||||
}
|
||||
opts, ok := ti.Options.(*options.Options)
|
||||
if !ok {
|
||||
return errors.New("invalid v2 shim create options format")
|
||||
}
|
||||
opts.CriuImagePath = path
|
||||
} else {
|
||||
if ti.Options == nil {
|
||||
ti.Options = &runctypes.CreateOptions{}
|
||||
}
|
||||
opts, ok := ti.Options.(*runctypes.CreateOptions)
|
||||
if !ok {
|
||||
return errors.New("invalid v1 shim 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
|
||||
|
||||
|
58
vendor/github.com/containerd/containerd/task_opts_unix.go
generated
vendored
58
vendor/github.com/containerd/containerd/task_opts_unix.go
generated
vendored
@ -22,36 +22,58 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/runtime/linux/runctypes"
|
||||
"github.com/containerd/containerd/runtime/v2/runc/options"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// WithNoNewKeyring causes tasks not to be created with a new keyring for secret storage.
|
||||
// There is an upper limit on the number of keyrings in a linux system
|
||||
func WithNoNewKeyring(ctx context.Context, c *Client, ti *TaskInfo) error {
|
||||
if ti.Options == nil {
|
||||
ti.Options = &runctypes.CreateOptions{}
|
||||
if CheckRuntime(ti.Runtime(), "io.containerd.runc") {
|
||||
if ti.Options == nil {
|
||||
ti.Options = &options.Options{}
|
||||
}
|
||||
opts, ok := ti.Options.(*options.Options)
|
||||
if !ok {
|
||||
return errors.New("invalid v2 shim create options format")
|
||||
}
|
||||
opts.NoNewKeyring = true
|
||||
} else {
|
||||
if ti.Options == nil {
|
||||
ti.Options = &runctypes.CreateOptions{}
|
||||
}
|
||||
opts, ok := ti.Options.(*runctypes.CreateOptions)
|
||||
if !ok {
|
||||
return errors.New("could not cast TaskInfo Options to CreateOptions")
|
||||
}
|
||||
opts.NoNewKeyring = true
|
||||
}
|
||||
opts, ok := ti.Options.(*runctypes.CreateOptions)
|
||||
if !ok {
|
||||
return errors.New("could not cast TaskInfo Options to CreateOptions")
|
||||
}
|
||||
|
||||
opts.NoNewKeyring = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithNoPivotRoot instructs the runtime not to you pivot_root
|
||||
func WithNoPivotRoot(_ context.Context, _ *Client, info *TaskInfo) error {
|
||||
if info.Options == nil {
|
||||
info.Options = &runctypes.CreateOptions{
|
||||
NoPivotRoot: true,
|
||||
func WithNoPivotRoot(_ context.Context, _ *Client, ti *TaskInfo) error {
|
||||
if CheckRuntime(ti.Runtime(), "io.containerd.runc") {
|
||||
if ti.Options == nil {
|
||||
ti.Options = &options.Options{}
|
||||
}
|
||||
return nil
|
||||
opts, ok := ti.Options.(*options.Options)
|
||||
if !ok {
|
||||
return errors.New("invalid v2 shim create options format")
|
||||
}
|
||||
opts.NoPivotRoot = true
|
||||
} else {
|
||||
if ti.Options == nil {
|
||||
ti.Options = &runctypes.CreateOptions{
|
||||
NoPivotRoot: true,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
opts, ok := ti.Options.(*runctypes.CreateOptions)
|
||||
if !ok {
|
||||
return errors.New("invalid options type, expected runctypes.CreateOptions")
|
||||
}
|
||||
opts.NoPivotRoot = true
|
||||
}
|
||||
opts, ok := info.Options.(*runctypes.CreateOptions)
|
||||
if !ok {
|
||||
return errors.New("invalid options type, expected runctypes.CreateOptions")
|
||||
}
|
||||
opts.NoPivotRoot = true
|
||||
return nil
|
||||
}
|
||||
|
39
vendor/github.com/containerd/containerd/vendor.conf
generated
vendored
39
vendor/github.com/containerd/containerd/vendor.conf
generated
vendored
@ -19,31 +19,32 @@ github.com/matttproud/golang_protobuf_extensions v1.0.0
|
||||
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/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4 # v1.0.1-59-g29686db
|
||||
github.com/opencontainers/runc 2b18fe1d885ee5083ef9f0838fee39b62d653e30
|
||||
github.com/sirupsen/logrus v1.0.0
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1
|
||||
github.com/sirupsen/logrus v1.3.0
|
||||
github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
|
||||
golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
|
||||
google.golang.org/grpc v1.12.0
|
||||
github.com/pkg/errors v0.8.0
|
||||
github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7
|
||||
golang.org/x/sys 41f3e6584952bb034a481797859f6ab34b6803bd https://github.com/golang/sys
|
||||
golang.org/x/sys d455e41777fca6e8a5a79e34a14b8368bc11d9ba 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.1
|
||||
github.com/Microsoft/go-winio v0.4.12
|
||||
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
|
||||
go.etcd.io/bbolt v1.3.2
|
||||
|
||||
# cri dependencies
|
||||
github.com/containerd/cri a92c40017473cbe0239ce180125f12669757e44f # 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 +54,6 @@ github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
|
||||
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,17 +72,19 @@ 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 9a0b8b8b5982014b729cd34eb7cd7a11062aa6ec
|
||||
github.com/containerd/zfs 9f6ef3b1fe5144bd91fe5855b4eba81bc0d17d03
|
||||
github.com/mistifyio/go-zfs 166add352731e515512690329794ee593f1aaff2
|
||||
github.com/pborman/uuid c65b2f87fee37d1c7854c9164a450713c28d50cd
|
||||
|
||||
# aufs dependencies
|
||||
github.com/containerd/aufs ffa39970e26ad01d81f540b21e65f9c1841a5f92
|
||||
github.com/containerd/aufs da3cf16bfbe68ba8f114f1536a05c01528a25434
|
||||
|
29
vendor/github.com/containerd/containerd/version/version.go
generated
vendored
Normal file
29
vendor/github.com/containerd/containerd/version/version.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
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 version
|
||||
|
||||
var (
|
||||
// Package is filled at linking time
|
||||
Package = "github.com/containerd/containerd"
|
||||
|
||||
// Version holds the complete version number. Filled in at linking time.
|
||||
Version = "1.2.0+unknown"
|
||||
|
||||
// Revision is filled with the VCS (e.g. git) revision being used to build
|
||||
// the program at linking time.
|
||||
Revision = ""
|
||||
)
|
Reference in New Issue
Block a user