Merge pull request #8262 from mxpv/v1
🪦 Remove `io.containerd.runtime.v1.linux` and `io.containerd.runc.v1`
			
			
This commit is contained in:
		
							
								
								
									
										7
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -390,16 +390,9 @@ jobs: | |||||||
|       fail-fast: false |       fail-fast: false | ||||||
|       matrix: |       matrix: | ||||||
|         runtime: |         runtime: | ||||||
|           - io.containerd.runtime.v1.linux |  | ||||||
|           - io.containerd.runc.v1 |  | ||||||
|           - io.containerd.runc.v2 |           - io.containerd.runc.v2 | ||||||
|         runc: [runc, crun] |         runc: [runc, crun] | ||||||
|         enable_cri_sandboxes: ["", "sandboxed"] |         enable_cri_sandboxes: ["", "sandboxed"] | ||||||
|         exclude: |  | ||||||
|           - runtime: io.containerd.runc.v1 |  | ||||||
|             runc: crun |  | ||||||
|           - runtime: io.containerd.runtime.v1.linux |  | ||||||
|             runc: crun |  | ||||||
|  |  | ||||||
|     env: |     env: | ||||||
|       GOTEST: gotestsum -- |       GOTEST: gotestsum -- | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Makefile
									
									
									
									
									
								
							| @@ -254,14 +254,6 @@ bin/gen-manpages: cmd/gen-manpages FORCE | |||||||
| 	@echo "$(WHALE) $@" | 	@echo "$(WHALE) $@" | ||||||
| 	$(GO) build ${DEBUG_GO_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} -o $@ ${GO_LDFLAGS} $(subst urfave_cli_no_docs,,${GO_TAGS})  ./cmd/gen-manpages | 	$(GO) build ${DEBUG_GO_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} -o $@ ${GO_LDFLAGS} $(subst urfave_cli_no_docs,,${GO_TAGS})  ./cmd/gen-manpages | ||||||
|  |  | ||||||
| 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) $@" |  | ||||||
| 	@CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o $@ ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim |  | ||||||
|  |  | ||||||
| bin/containerd-shim-runc-v1: cmd/containerd-shim-runc-v1 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220 |  | ||||||
| 	@echo "$(WHALE) $@" |  | ||||||
| 	@CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o $@ ${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 | 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) $@" | 	@echo "$(WHALE) $@" | ||||||
| 	@CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o $@ ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v2 | 	@CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o $@ ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v2 | ||||||
| @@ -400,7 +392,7 @@ clean: ## clean up binaries | |||||||
| clean-test: ## clean up debris from previously failed tests | clean-test: ## clean up debris from previously failed tests | ||||||
| 	@echo "$(WHALE) $@" | 	@echo "$(WHALE) $@" | ||||||
| 	$(eval containers=$(shell find /run/containerd/runc -mindepth 2 -maxdepth 3  -type d -exec basename {} \;)) | 	$(eval containers=$(shell find /run/containerd/runc -mindepth 2 -maxdepth 3  -type d -exec basename {} \;)) | ||||||
| 	$(shell pidof containerd containerd-shim runc | xargs -r -n 1 kill -9) | 	$(shell pidof containerd runc | xargs -r -n 1 kill -9) | ||||||
| 	@( for container in $(containers); do \ | 	@( for container in $(containers); do \ | ||||||
| 	    grep $$container /proc/self/mountinfo | while read -r mountpoint; do \ | 	    grep $$container /proc/self/mountinfo | while read -r mountpoint; do \ | ||||||
| 		umount $$(echo $$mountpoint | awk '{print $$5}'); \ | 		umount $$(echo $$mountpoint | awk '{print $$5}'); \ | ||||||
|   | |||||||
| @@ -13,9 +13,6 @@ | |||||||
| #   limitations under the License. | #   limitations under the License. | ||||||
|  |  | ||||||
|  |  | ||||||
| #darwin specific settings |  | ||||||
| COMMANDS += containerd-shim |  | ||||||
|  |  | ||||||
| # amd64 supports go test -race | # amd64 supports go test -race | ||||||
| ifeq ($(GOARCH),amd64) | ifeq ($(GOARCH),amd64) | ||||||
| 	TESTFLAGS_RACE= -race | 	TESTFLAGS_RACE= -race | ||||||
|   | |||||||
| @@ -14,7 +14,6 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
| #freebsd specific settings | #freebsd specific settings | ||||||
| COMMANDS += containerd-shim |  | ||||||
|  |  | ||||||
| # amd64 supports go test -race | # amd64 supports go test -race | ||||||
| ifeq ($(GOARCH),amd64) | ifeq ($(GOARCH),amd64) | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ | |||||||
| #linux specific settings | #linux specific settings | ||||||
| WHALE="+" | WHALE="+" | ||||||
| ONI="-" | ONI="-" | ||||||
| COMMANDS += containerd-shim containerd-shim-runc-v1 containerd-shim-runc-v2 | COMMANDS += containerd-shim-runc-v2 | ||||||
|  |  | ||||||
| # check GOOS for cross compile builds | # check GOOS for cross compile builds | ||||||
| ifeq ($(GOOS),linux) | ifeq ($(GOOS),linux) | ||||||
|   | |||||||
| @@ -28,14 +28,6 @@ prefixes = [ | |||||||
| ] | ] | ||||||
| generators = ["go", "go-grpc"] | generators = ["go", "go-grpc"] | ||||||
|  |  | ||||||
| # Lock down runc config |  | ||||||
| [[descriptors]] |  | ||||||
| prefix = "github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| target = "runtime/linux/runctypes/next.pb.txt" |  | ||||||
| ignore_files = [ |  | ||||||
| 	"google/protobuf/descriptor.proto", |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| [[descriptors]] | [[descriptors]] | ||||||
| prefix = "github.com/containerd/containerd/runtime/v2/runc/options" | prefix = "github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
| target = "runtime/v2/runc/options/next.pb.txt" | target = "runtime/v2/runc/options/next.pb.txt" | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								RELEASES.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								RELEASES.md
									
									
									
									
									
								
							| @@ -371,8 +371,8 @@ The deprecated features are shown in the following table: | |||||||
|  |  | ||||||
| | Component                                                                        | Deprecation release | Target release for removal | Recommendation                           | | | Component                                                                        | Deprecation release | Target release for removal | Recommendation                           | | ||||||
| |----------------------------------------------------------------------------------|---------------------|----------------------------|------------------------------------------| | |----------------------------------------------------------------------------------|---------------------|----------------------------|------------------------------------------| | ||||||
| | Runtime V1 API and implementation (`io.containerd.runtime.v1.linux`)             | containerd v1.4     | containerd v2.0            | Use `io.containerd.runc.v2`              | | | Runtime V1 API and implementation (`io.containerd.runtime.v1.linux`)             | containerd v1.4     | containerd v2.0 ✅         | Use `io.containerd.runc.v2`              | | ||||||
| | Runc V1 implementation of Runtime V2 (`io.containerd.runc.v1`)                   | containerd v1.4     | containerd v2.0            | Use `io.containerd.runc.v2`              | | | Runc V1 implementation of Runtime V2 (`io.containerd.runc.v1`)                   | containerd v1.4     | containerd v2.0 ✅         | Use `io.containerd.runc.v2`              | | ||||||
| | config.toml `version = 1`                                                        | containerd v1.5     | containerd v2.0            | Use config.toml `version = 2`            | | | config.toml `version = 1`                                                        | containerd v1.5     | containerd v2.0            | Use config.toml `version = 2`            | | ||||||
| | Built-in `aufs` snapshotter                                                      | containerd v1.5     | containerd v2.0 ✅         | Use `overlayfs` snapshotter              | | | Built-in `aufs` snapshotter                                                      | containerd v1.5     | containerd v2.0 ✅         | Use `overlayfs` snapshotter              | | ||||||
| | Container label `containerd.io/restart.logpath`                                  | containerd v1.5     | containerd v2.0 ✅         | Use `containerd.io/restart.loguri` label | | | Container label `containerd.io/restart.logpath`                                  | containerd v1.5     | containerd v2.0 ✅         | Use `containerd.io/restart.loguri` label | | ||||||
| @@ -385,12 +385,12 @@ The deprecated properties in [`config.toml`](./docs/cri/config.md) are shown in | |||||||
|  |  | ||||||
| | Property Group                                                       | Property                     | Deprecation release | Target release for removal | Recommendation                                  | | | Property Group                                                       | Property                     | Deprecation release | Target release for removal | Recommendation                                  | | ||||||
| |----------------------------------------------------------------------|------------------------------|---------------------|----------------------------|-------------------------------------------------| | |----------------------------------------------------------------------|------------------------------|---------------------|----------------------------|-------------------------------------------------| | ||||||
| |`[plugins."io.containerd.grpc.v1.cri"]`                               | `systemd_cgroup`             | containerd v1.3     | containerd v2.0            | Use `SystemdCgroup` in runc options (see below) | | |`[plugins."io.containerd.grpc.v1.cri"]`                               | `systemd_cgroup`             | containerd v1.3     | containerd v2.0 ✅         | Use `SystemdCgroup` in runc options (see below) | | ||||||
| |`[plugins."io.containerd.grpc.v1.cri".cni]`                           | `conf_template`              | containerd v1.?     | containerd v2.0            | Create a CNI config in `/etc/cni/net.d`         | | |`[plugins."io.containerd.grpc.v1.cri".cni]`                           | `conf_template`              | containerd v1.?     | containerd v2.0            | Create a CNI config in `/etc/cni/net.d`         | | ||||||
| |`[plugins."io.containerd.grpc.v1.cri".containerd]`                    | `untrusted_workload_runtime` | containerd v1.2     | containerd v2.0            | Create `untrusted` runtime in `runtimes`        | | |`[plugins."io.containerd.grpc.v1.cri".containerd]`                    | `untrusted_workload_runtime` | containerd v1.2     | containerd v2.0 ✅         | Create `untrusted` runtime in `runtimes`        | | ||||||
| |`[plugins."io.containerd.grpc.v1.cri".containerd]`                    | `default_runtime`            | containerd v1.3     | containerd v2.0            | Use `default_runtime_name`                      | | |`[plugins."io.containerd.grpc.v1.cri".containerd]`                    | `default_runtime`            | containerd v1.3     | containerd v2.0 ✅         | Use `default_runtime_name`                      | | ||||||
| |`[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.*]`         | `runtime_engine`             | containerd v1.3     | containerd v2.0            | Use runtime v2                                  | | |`[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.*]`         | `runtime_engine`             | containerd v1.3     | containerd v2.0 ✅         | Use runtime v2                                  | | ||||||
| |`[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.*]`         | `runtime_root`               | containerd v1.3     | containerd v2.0            | Use `options.Root`                              | | |`[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.*]`         | `runtime_root`               | containerd v1.3     | containerd v2.0 ✅         | Use `options.Root`                              | | ||||||
| |`[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.*.options]` | `CriuPath`                   | containerd v1.7     | containerd v2.0            | Set `$PATH` to the `criu` binary                | | |`[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.*.options]` | `CriuPath`                   | containerd v1.7     | containerd v2.0            | Set `$PATH` to the `criu` binary                | | ||||||
| |`[plugins."io.containerd.grpc.v1.cri".registry]`                      | `auths`                      | containerd v1.3     | containerd v2.0            | Use [`ImagePullSecrets`](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/). See also [#8228](https://github.com/containerd/containerd/issues/8228). | | |`[plugins."io.containerd.grpc.v1.cri".registry]`                      | `auths`                      | containerd v1.3     | containerd v2.0            | Use [`ImagePullSecrets`](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/). See also [#8228](https://github.com/containerd/containerd/issues/8228). | | ||||||
| |`[plugins."io.containerd.grpc.v1.cri".registry]`                      | `configs`                    | containerd v1.5     | containerd v2.0            | Use [`config_path`](./docs/hosts.md)            | | |`[plugins."io.containerd.grpc.v1.cri".registry]`                      | `configs`                    | containerd v1.5     | containerd v2.0            | Use [`config_path`](./docs/hosts.md)            | | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								client.go
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								client.go
									
									
									
									
									
								
							| @@ -818,23 +818,6 @@ func (c *Client) getSnapshotter(ctx context.Context, name string) (snapshots.Sna | |||||||
| 	return s, nil | 	return s, 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 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // GetSnapshotterSupportedPlatforms returns a platform matchers which represents the | // GetSnapshotterSupportedPlatforms returns a platform matchers which represents the | ||||||
| // supported platforms for the given snapshotters | // supported platforms for the given snapshotters | ||||||
| func (c *Client) GetSnapshotterSupportedPlatforms(ctx context.Context, snapshotterName string) (platforms.MatchComparer, error) { | func (c *Client) GetSnapshotterSupportedPlatforms(ctx context.Context, snapshotterName string) (platforms.MatchComparer, error) { | ||||||
|   | |||||||
| @@ -1,28 +0,0 @@ | |||||||
| //go:build linux |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|    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 main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	v1 "github.com/containerd/containerd/runtime/v2/runc/v1" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v2/shim" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
| 	shim.Run("io.containerd.runc.v1", v1.New) |  | ||||||
| } |  | ||||||
| @@ -1,333 +0,0 @@ | |||||||
| //go: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 main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"bytes" |  | ||||||
| 	"context" |  | ||||||
| 	"errors" |  | ||||||
| 	"flag" |  | ||||||
| 	"fmt" |  | ||||||
| 	"io" |  | ||||||
| 	"net" |  | ||||||
| 	"os" |  | ||||||
| 	"os/signal" |  | ||||||
| 	"runtime" |  | ||||||
| 	"runtime/debug" |  | ||||||
| 	"strings" |  | ||||||
| 	"sync" |  | ||||||
| 	"syscall" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/events" |  | ||||||
| 	"github.com/containerd/containerd/namespaces" |  | ||||||
| 	"github.com/containerd/containerd/pkg/process" |  | ||||||
| 	"github.com/containerd/containerd/protobuf" |  | ||||||
| 	"github.com/containerd/containerd/protobuf/proto" |  | ||||||
| 	ptypes "github.com/containerd/containerd/protobuf/types" |  | ||||||
| 	shimlog "github.com/containerd/containerd/runtime/v1" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v1/shim" |  | ||||||
| 	shimapi "github.com/containerd/containerd/runtime/v1/shim/v1" |  | ||||||
| 	"github.com/containerd/containerd/sys/reaper" |  | ||||||
| 	"github.com/containerd/containerd/version" |  | ||||||
| 	"github.com/containerd/ttrpc" |  | ||||||
| 	"github.com/sirupsen/logrus" |  | ||||||
| 	exec "golang.org/x/sys/execabs" |  | ||||||
| 	"golang.org/x/sys/unix" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	debugFlag            bool |  | ||||||
| 	versionFlag          bool |  | ||||||
| 	namespaceFlag        string |  | ||||||
| 	socketFlag           string |  | ||||||
| 	addressFlag          string |  | ||||||
| 	workdirFlag          string |  | ||||||
| 	runtimeRootFlag      string |  | ||||||
| 	criuFlag             string |  | ||||||
| 	systemdCgroupFlag    bool |  | ||||||
| 	containerdBinaryFlag string |  | ||||||
|  |  | ||||||
| 	bufPool = sync.Pool{ |  | ||||||
| 		New: func() interface{} { |  | ||||||
| 			return bytes.NewBuffer(nil) |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func parseFlags() { |  | ||||||
| 	flag.BoolVar(&debugFlag, "debug", false, "enable debug output in logs") |  | ||||||
| 	flag.BoolVar(&versionFlag, "v", false, "show the shim version and exit") |  | ||||||
| 	flag.StringVar(&namespaceFlag, "namespace", "", "namespace that owns the shim") |  | ||||||
| 	flag.StringVar(&socketFlag, "socket", "", "socket path to serve") |  | ||||||
| 	flag.StringVar(&addressFlag, "address", "", "grpc address back to main containerd") |  | ||||||
| 	flag.StringVar(&workdirFlag, "workdir", "", "path used to storage large temporary data") |  | ||||||
| 	flag.StringVar(&runtimeRootFlag, "runtime-root", process.RuncRoot, "root directory for the runtime") |  | ||||||
| 	flag.StringVar(&criuFlag, "criu", "", "path to criu binary (deprecated: do not use)") |  | ||||||
| 	flag.BoolVar(&systemdCgroupFlag, "systemd-cgroup", false, "set runtime to use systemd-cgroup") |  | ||||||
| 	// currently, the `containerd publish` utility is embedded in the daemon binary. |  | ||||||
| 	// The daemon invokes `containerd-shim -containerd-binary ...` with its own os.Executable() path. |  | ||||||
| 	flag.StringVar(&containerdBinaryFlag, "containerd-binary", "containerd", "path to containerd binary (used for `containerd publish`)") |  | ||||||
| 	flag.Parse() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func setRuntime() { |  | ||||||
| 	debug.SetGCPercent(40) |  | ||||||
| 	go func() { |  | ||||||
| 		for range time.Tick(30 * time.Second) { |  | ||||||
| 			debug.FreeOSMemory() |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
| 	if os.Getenv("GOMAXPROCS") == "" { |  | ||||||
| 		// If GOMAXPROCS hasn't been set, we default to a value of 2 to reduce |  | ||||||
| 		// the number of Go stacks present in the shim. |  | ||||||
| 		runtime.GOMAXPROCS(2) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
| 	parseFlags() |  | ||||||
| 	if versionFlag { |  | ||||||
| 		fmt.Println("containerd-shim") |  | ||||||
| 		fmt.Println("  Version: ", version.Version) |  | ||||||
| 		fmt.Println("  Revision:", version.Revision) |  | ||||||
| 		fmt.Println("  Go version:", version.GoVersion) |  | ||||||
| 		fmt.Println("") |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	setRuntime() |  | ||||||
|  |  | ||||||
| 	if debugFlag { |  | ||||||
| 		logrus.SetLevel(logrus.DebugLevel) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	stdout, stderr, err := openStdioKeepAlivePipes(workdirFlag) |  | ||||||
| 	if err != nil { |  | ||||||
| 		fmt.Fprintf(os.Stderr, "containerd-shim: %s\n", err) |  | ||||||
| 		os.Exit(1) |  | ||||||
| 	} |  | ||||||
| 	defer func() { |  | ||||||
| 		stdout.Close() |  | ||||||
| 		stderr.Close() |  | ||||||
| 	}() |  | ||||||
|  |  | ||||||
| 	// redirect the following output into fifo to make sure that containerd |  | ||||||
| 	// still can read the log after restart |  | ||||||
| 	logrus.SetOutput(stdout) |  | ||||||
|  |  | ||||||
| 	if err := executeShim(); err != nil { |  | ||||||
| 		fmt.Fprintf(os.Stderr, "containerd-shim: %s\n", err) |  | ||||||
| 		os.Exit(1) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // If containerd server process dies, we need the shim to keep stdout/err reader |  | ||||||
| // FDs so that Linux does not SIGPIPE the shim process if it tries to use its end of |  | ||||||
| // these pipes. |  | ||||||
| func openStdioKeepAlivePipes(dir string) (io.ReadWriteCloser, io.ReadWriteCloser, error) { |  | ||||||
| 	background := context.Background() |  | ||||||
| 	keepStdoutAlive, err := shimlog.OpenShimStdoutLog(background, dir) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, nil, err |  | ||||||
| 	} |  | ||||||
| 	keepStderrAlive, err := shimlog.OpenShimStderrLog(background, dir) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, nil, err |  | ||||||
| 	} |  | ||||||
| 	return keepStdoutAlive, keepStderrAlive, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func executeShim() error { |  | ||||||
| 	// start handling signals as soon as possible so that things are properly reaped |  | ||||||
| 	// or if runtime exits before we hit the handler |  | ||||||
| 	signals, err := setupSignals() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	dump := make(chan os.Signal, 32) |  | ||||||
| 	signal.Notify(dump, syscall.SIGUSR1) |  | ||||||
|  |  | ||||||
| 	path, err := os.Getwd() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	server, err := newServer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("failed creating server: %w", err) |  | ||||||
| 	} |  | ||||||
| 	sv, err := shim.NewService( |  | ||||||
| 		shim.Config{ |  | ||||||
| 			Path:          path, |  | ||||||
| 			Namespace:     namespaceFlag, |  | ||||||
| 			WorkDir:       workdirFlag, |  | ||||||
| 			SystemdCgroup: systemdCgroupFlag, |  | ||||||
| 			RuntimeRoot:   runtimeRootFlag, |  | ||||||
| 		}, |  | ||||||
| 		&remoteEventsPublisher{address: addressFlag}, |  | ||||||
| 	) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	logrus.Debug("registering ttrpc server") |  | ||||||
| 	shimapi.RegisterShimService(server, sv) |  | ||||||
|  |  | ||||||
| 	socket := socketFlag |  | ||||||
| 	if err := serve(context.Background(), server, socket); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	logger := logrus.WithFields(logrus.Fields{ |  | ||||||
| 		"pid":       os.Getpid(), |  | ||||||
| 		"path":      path, |  | ||||||
| 		"namespace": namespaceFlag, |  | ||||||
| 	}) |  | ||||||
| 	go func() { |  | ||||||
| 		for range dump { |  | ||||||
| 			dumpStacks(logger) |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
| 	return handleSignals(logger, signals, server, sv) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // serve serves the ttrpc API over a unix socket at the provided path |  | ||||||
| // this function does not block |  | ||||||
| func serve(ctx context.Context, server *ttrpc.Server, path string) error { |  | ||||||
| 	var ( |  | ||||||
| 		l   net.Listener |  | ||||||
| 		err error |  | ||||||
| 	) |  | ||||||
| 	if path == "" { |  | ||||||
| 		f := os.NewFile(3, "socket") |  | ||||||
| 		l, err = net.FileListener(f) |  | ||||||
| 		f.Close() |  | ||||||
| 		path = "[inherited from parent]" |  | ||||||
| 	} else { |  | ||||||
| 		const ( |  | ||||||
| 			abstractSocketPrefix = "\x00" |  | ||||||
| 			socketPathLimit      = 106 |  | ||||||
| 		) |  | ||||||
| 		p := strings.TrimPrefix(path, "unix://") |  | ||||||
| 		if len(p) == len(path) { |  | ||||||
| 			p = abstractSocketPrefix + p |  | ||||||
| 		} |  | ||||||
| 		if len(p) > socketPathLimit { |  | ||||||
| 			return fmt.Errorf("%q: unix socket path too long (> %d)", p, socketPathLimit) |  | ||||||
| 		} |  | ||||||
| 		l, err = net.Listen("unix", p) |  | ||||||
| 	} |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	logrus.WithField("socket", path).Debug("serving api on unix socket") |  | ||||||
| 	go func() { |  | ||||||
| 		defer l.Close() |  | ||||||
| 		if err := server.Serve(ctx, l); err != nil && !errors.Is(err, net.ErrClosed) { |  | ||||||
| 			logrus.WithError(err).Fatal("containerd-shim: ttrpc server failure") |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func handleSignals(logger *logrus.Entry, signals chan os.Signal, server *ttrpc.Server, sv *shim.Service) error { |  | ||||||
| 	var ( |  | ||||||
| 		termOnce sync.Once |  | ||||||
| 		done     = make(chan struct{}) |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	for { |  | ||||||
| 		select { |  | ||||||
| 		case <-done: |  | ||||||
| 			return nil |  | ||||||
| 		case s := <-signals: |  | ||||||
| 			switch s { |  | ||||||
| 			case unix.SIGCHLD: |  | ||||||
| 				if err := reaper.Reap(); err != nil { |  | ||||||
| 					logger.WithError(err).Error("reap exit status") |  | ||||||
| 				} |  | ||||||
| 			case unix.SIGTERM, unix.SIGINT: |  | ||||||
| 				go termOnce.Do(func() { |  | ||||||
| 					ctx := context.TODO() |  | ||||||
| 					if err := server.Shutdown(ctx); err != nil { |  | ||||||
| 						logger.WithError(err).Error("failed to shutdown server") |  | ||||||
| 					} |  | ||||||
| 					// Ensure our child is dead if any |  | ||||||
| 					sv.Kill(ctx, &shimapi.KillRequest{ |  | ||||||
| 						Signal: uint32(syscall.SIGKILL), |  | ||||||
| 						All:    true, |  | ||||||
| 					}) |  | ||||||
| 					sv.Delete(context.Background(), &ptypes.Empty{}) |  | ||||||
| 					close(done) |  | ||||||
| 				}) |  | ||||||
| 			case unix.SIGPIPE: |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func dumpStacks(logger *logrus.Entry) { |  | ||||||
| 	var ( |  | ||||||
| 		buf       []byte |  | ||||||
| 		stackSize int |  | ||||||
| 	) |  | ||||||
| 	bufferLen := 16384 |  | ||||||
| 	for stackSize == len(buf) { |  | ||||||
| 		buf = make([]byte, bufferLen) |  | ||||||
| 		stackSize = runtime.Stack(buf, true) |  | ||||||
| 		bufferLen *= 2 |  | ||||||
| 	} |  | ||||||
| 	buf = buf[:stackSize] |  | ||||||
| 	logger.Infof("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type remoteEventsPublisher struct { |  | ||||||
| 	address string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (l *remoteEventsPublisher) Publish(ctx context.Context, topic string, event events.Event) error { |  | ||||||
| 	ns, _ := namespaces.Namespace(ctx) |  | ||||||
| 	encoded, err := protobuf.MarshalAnyToProto(event) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	data, err := proto.Marshal(encoded) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	cmd := exec.CommandContext(ctx, containerdBinaryFlag, "--address", l.address, "publish", "--topic", topic, "--namespace", ns) |  | ||||||
| 	cmd.Stdin = bytes.NewReader(data) |  | ||||||
| 	b := bufPool.Get().(*bytes.Buffer) |  | ||||||
| 	defer func() { |  | ||||||
| 		b.Reset() |  | ||||||
| 		bufPool.Put(b) |  | ||||||
| 	}() |  | ||||||
| 	cmd.Stdout = b |  | ||||||
| 	cmd.Stderr = b |  | ||||||
| 	c, err := reaper.Default.Start(cmd) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	status, err := reaper.Default.WaitTimeout(cmd, c, 30*time.Second) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("failed to publish event: %s: %w", b.String(), err) |  | ||||||
| 	} |  | ||||||
| 	if status != 0 { |  | ||||||
| 		return fmt.Errorf("failed to publish event: %s", b.String()) |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,44 +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 main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"os" |  | ||||||
| 	"os/signal" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/sys/reaper" |  | ||||||
| 	runc "github.com/containerd/go-runc" |  | ||||||
| 	"github.com/containerd/ttrpc" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // setupSignals creates a new signal handler for all signals and sets the shim as a |  | ||||||
| // sub-reaper so that the container processes are reparented |  | ||||||
| func setupSignals() (chan os.Signal, error) { |  | ||||||
| 	signals := make(chan os.Signal, 2048) |  | ||||||
| 	signal.Notify(signals) |  | ||||||
| 	// make sure runc is setup to use the monitor |  | ||||||
| 	// for waiting on processes |  | ||||||
| 	runc.Monitor = reaper.Default |  | ||||||
| 	return signals, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newServer() (*ttrpc.Server, error) { |  | ||||||
| 	// for darwin, we omit the socket credentials because these syscalls are |  | ||||||
| 	// slightly different. since we don't have darwin support yet, this can be |  | ||||||
| 	// implemented later and the build can continue without issue. |  | ||||||
| 	return ttrpc.NewServer() |  | ||||||
| } |  | ||||||
| @@ -1,45 +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 main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"os" |  | ||||||
| 	"os/signal" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/sys/reaper" |  | ||||||
|  |  | ||||||
| 	runc "github.com/containerd/go-runc" |  | ||||||
| 	"github.com/containerd/ttrpc" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // setupSignals creates a new signal handler for all signals and sets the shim as a |  | ||||||
| // sub-reaper so that the container processes are reparented |  | ||||||
| func setupSignals() (chan os.Signal, error) { |  | ||||||
| 	signals := make(chan os.Signal, 2048) |  | ||||||
| 	signal.Notify(signals) |  | ||||||
| 	// make sure runc is setup to use the monitor |  | ||||||
| 	// for waiting on processes |  | ||||||
| 	runc.Monitor = reaper.Default |  | ||||||
| 	return signals, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newServer() (*ttrpc.Server, error) { |  | ||||||
| 	// for freebsd, we omit the socket credentials because these syscalls are |  | ||||||
| 	// slightly different. since we don't have freebsd support yet, this can be |  | ||||||
| 	// implemented later and the build can continue without issue. |  | ||||||
| 	return ttrpc.NewServer() |  | ||||||
| } |  | ||||||
| @@ -1,46 +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 main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"os" |  | ||||||
| 	"os/signal" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/sys/reaper" |  | ||||||
| 	runc "github.com/containerd/go-runc" |  | ||||||
| 	"github.com/containerd/ttrpc" |  | ||||||
| 	"golang.org/x/sys/unix" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // setupSignals creates a new signal handler for all signals and sets the shim as a |  | ||||||
| // sub-reaper so that the container processes are reparented |  | ||||||
| func setupSignals() (chan os.Signal, error) { |  | ||||||
| 	signals := make(chan os.Signal, 32) |  | ||||||
| 	signal.Notify(signals, unix.SIGTERM, unix.SIGINT, unix.SIGCHLD, unix.SIGPIPE) |  | ||||||
| 	// make sure runc is setup to use the monitor |  | ||||||
| 	// for waiting on processes |  | ||||||
| 	runc.Monitor = reaper.Default |  | ||||||
| 	// set the shim as the subreaper for all orphaned processes created by the container |  | ||||||
| 	if err := reaper.SetSubreaper(1); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return signals, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newServer() (*ttrpc.Server, error) { |  | ||||||
| 	return ttrpc.NewServer(ttrpc.WithServerHandshaker(ttrpc.UnixSocketRequireSameUser())) |  | ||||||
| } |  | ||||||
| @@ -19,7 +19,6 @@ package builtins | |||||||
| import ( | import ( | ||||||
| 	_ "github.com/containerd/containerd/metrics/cgroups" | 	_ "github.com/containerd/containerd/metrics/cgroups" | ||||||
| 	_ "github.com/containerd/containerd/metrics/cgroups/v2" | 	_ "github.com/containerd/containerd/metrics/cgroups/v2" | ||||||
| 	_ "github.com/containerd/containerd/runtime/v1/linux" |  | ||||||
| 	_ "github.com/containerd/containerd/runtime/v2/runc/options" | 	_ "github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
| 	_ "github.com/containerd/containerd/snapshots/native/plugin" | 	_ "github.com/containerd/containerd/snapshots/native/plugin" | ||||||
| 	_ "github.com/containerd/containerd/snapshots/overlay/plugin" | 	_ "github.com/containerd/containerd/snapshots/overlay/plugin" | ||||||
|   | |||||||
| @@ -22,8 +22,6 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/containerd/containerd" | 	"github.com/containerd/containerd" | ||||||
| 	"github.com/containerd/containerd/cmd/ctr/commands" | 	"github.com/containerd/containerd/cmd/ctr/commands" | ||||||
| 	"github.com/containerd/containerd/plugin" |  | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v2/runc/options" | 	"github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
| 	"github.com/urfave/cli" | 	"github.com/urfave/cli" | ||||||
| ) | ) | ||||||
| @@ -86,38 +84,21 @@ func withCheckpointOpts(rt string, context *cli.Context) containerd.CheckpointTa | |||||||
| 		imagePath := context.String("image-path") | 		imagePath := context.String("image-path") | ||||||
| 		workPath := context.String("work-path") | 		workPath := context.String("work-path") | ||||||
|  |  | ||||||
| 		switch rt { | 		if r.Options == nil { | ||||||
| 		case plugin.RuntimeRuncV1, plugin.RuntimeRuncV2: | 			r.Options = &options.CheckpointOptions{} | ||||||
| 			if r.Options == nil { |  | ||||||
| 				r.Options = &options.CheckpointOptions{} |  | ||||||
| 			} |  | ||||||
| 			opts, _ := r.Options.(*options.CheckpointOptions) |  | ||||||
|  |  | ||||||
| 			if context.Bool("exit") { |  | ||||||
| 				opts.Exit = true |  | ||||||
| 			} |  | ||||||
| 			if imagePath != "" { |  | ||||||
| 				opts.ImagePath = imagePath |  | ||||||
| 			} |  | ||||||
| 			if workPath != "" { |  | ||||||
| 				opts.WorkPath = workPath |  | ||||||
| 			} |  | ||||||
| 		case plugin.RuntimeLinuxV1: |  | ||||||
| 			if r.Options == nil { |  | ||||||
| 				r.Options = &runctypes.CheckpointOptions{} |  | ||||||
| 			} |  | ||||||
| 			opts, _ := r.Options.(*runctypes.CheckpointOptions) |  | ||||||
|  |  | ||||||
| 			if context.Bool("exit") { |  | ||||||
| 				opts.Exit = true |  | ||||||
| 			} |  | ||||||
| 			if imagePath != "" { |  | ||||||
| 				opts.ImagePath = imagePath |  | ||||||
| 			} |  | ||||||
| 			if workPath != "" { |  | ||||||
| 				opts.WorkPath = workPath |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
|  | 		opts, _ := r.Options.(*options.CheckpointOptions) | ||||||
|  |  | ||||||
|  | 		if context.Bool("exit") { | ||||||
|  | 			opts.Exit = true | ||||||
|  | 		} | ||||||
|  | 		if imagePath != "" { | ||||||
|  | 			opts.ImagePath = imagePath | ||||||
|  | 		} | ||||||
|  | 		if workPath != "" { | ||||||
|  | 			opts.WorkPath = workPath | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -240,7 +240,7 @@ containerd_extra_runtime_handler=${CONTAINERD_EXTRA_RUNTIME_HANDLER:-""} | |||||||
| if [[ -n "${containerd_extra_runtime_handler}" ]]; then | if [[ -n "${containerd_extra_runtime_handler}" ]]; then | ||||||
|   cat >> ${config_path} <<EOF |   cat >> ${config_path} <<EOF | ||||||
| [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.${containerd_extra_runtime_handler}] | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.${containerd_extra_runtime_handler}] | ||||||
|   runtime_type = "${CONTAINERD_EXTRA_RUNTIME_TYPE:-io.containerd.runc.v1}" |   runtime_type = "${CONTAINERD_EXTRA_RUNTIME_TYPE:-io.containerd.runc.v2}" | ||||||
|  |  | ||||||
| [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.${containerd_extra_runtime_handler}.options] | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.${containerd_extra_runtime_handler}.options] | ||||||
| ${CONTAINERD_EXTRA_RUNTIME_OPTIONS:-} | ${CONTAINERD_EXTRA_RUNTIME_OPTIONS:-} | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ For each `containerd` release, we'll publish a release tarball specifically for | |||||||
| ### Content | ### Content | ||||||
| As shown below, the release tarball contains: | As shown below, the release tarball contains: | ||||||
|  |  | ||||||
| - `containerd`, `containerd-shim`, `containerd-shim-runc-v1`, `containerd-shim-runc-v2`, `ctr`: binaries for containerd. | - `containerd`, `containerd-shim-runc-v2`, `ctr`: binaries for containerd. | ||||||
| - `runc`: runc binary. | - `runc`: runc binary. | ||||||
| - `/opt/cni/bin`: binaries for [Container Network Interface](https://github.com/containernetworking/cni) | - `/opt/cni/bin`: binaries for [Container Network Interface](https://github.com/containernetworking/cni) | ||||||
| - `crictl`, `crictl.yaml`: command line tools for CRI container runtime and its config file. | - `crictl`, `crictl.yaml`: command line tools for CRI container runtime and its config file. | ||||||
|   | |||||||
| @@ -18,8 +18,7 @@ package integration | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	// Register for linux platforms | 	// Register for linux platforms | ||||||
| 	_ "github.com/containerd/containerd/plugins/sandbox" // WithInMemoryServices will fail otherwise | 	_ "github.com/containerd/containerd/plugins/sandbox"  // WithInMemoryServices will fail otherwise | ||||||
| 	_ "github.com/containerd/containerd/runtime/v1/linux" |  | ||||||
| 	_ "github.com/containerd/containerd/services/sandbox" // WithInMemoryServices will fail otherwise | 	_ "github.com/containerd/containerd/services/sandbox" // WithInMemoryServices will fail otherwise | ||||||
| 	_ "github.com/containerd/containerd/snapshots/overlay/plugin" | 	_ "github.com/containerd/containerd/snapshots/overlay/plugin" | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -32,7 +32,6 @@ import ( | |||||||
| 	. "github.com/containerd/containerd" | 	. "github.com/containerd/containerd" | ||||||
| 	"github.com/containerd/containerd/cio" | 	"github.com/containerd/containerd/cio" | ||||||
| 	"github.com/containerd/containerd/oci" | 	"github.com/containerd/containerd/oci" | ||||||
| 	"github.com/containerd/containerd/plugin" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -48,9 +47,6 @@ func TestCheckpointRestorePTY(t *testing.T) { | |||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 	defer client.Close() | 	defer client.Close() | ||||||
| 	if client.Runtime() == plugin.RuntimeLinuxV1 { |  | ||||||
| 		t.Skip() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var ( | 	var ( | ||||||
| 		ctx, cancel = testContext(t) | 		ctx, cancel = testContext(t) | ||||||
| @@ -174,9 +170,6 @@ func TestCheckpointRestore(t *testing.T) { | |||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 	defer client.Close() | 	defer client.Close() | ||||||
| 	if client.Runtime() == plugin.RuntimeLinuxV1 { |  | ||||||
| 		t.Skip() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var ( | 	var ( | ||||||
| 		ctx, cancel = testContext(t) | 		ctx, cancel = testContext(t) | ||||||
| @@ -264,9 +257,6 @@ func TestCheckpointRestoreNewContainer(t *testing.T) { | |||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 	defer client.Close() | 	defer client.Close() | ||||||
| 	if client.Runtime() == plugin.RuntimeLinuxV1 { |  | ||||||
| 		t.Skip() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	id := t.Name() | 	id := t.Name() | ||||||
| 	ctx, cancel := testContext(t) | 	ctx, cancel := testContext(t) | ||||||
| @@ -354,9 +344,6 @@ func TestCheckpointLeaveRunning(t *testing.T) { | |||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 	defer client.Close() | 	defer client.Close() | ||||||
| 	if client.Runtime() == plugin.RuntimeLinuxV1 { |  | ||||||
| 		t.Skip() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var ( | 	var ( | ||||||
| 		ctx, cancel = testContext(t) | 		ctx, cancel = testContext(t) | ||||||
| @@ -538,9 +525,6 @@ func TestCheckpointOnPauseStatus(t *testing.T) { | |||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 	defer client.Close() | 	defer client.Close() | ||||||
| 	if client.Runtime() == plugin.RuntimeLinuxV1 { |  | ||||||
| 		t.Skip() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var ( | 	var ( | ||||||
| 		ctx, cancel = testContext(t) | 		ctx, cancel = testContext(t) | ||||||
|   | |||||||
| @@ -39,7 +39,6 @@ import ( | |||||||
| 	"github.com/containerd/containerd/errdefs" | 	"github.com/containerd/containerd/errdefs" | ||||||
| 	"github.com/containerd/containerd/oci" | 	"github.com/containerd/containerd/oci" | ||||||
| 	"github.com/containerd/containerd/plugin" | 	"github.com/containerd/containerd/plugin" | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v2/runc/options" | 	"github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
| 	"github.com/containerd/containerd/sys" | 	"github.com/containerd/containerd/sys" | ||||||
| 	"github.com/opencontainers/runtime-spec/specs-go" | 	"github.com/opencontainers/runtime-spec/specs-go" | ||||||
| @@ -375,16 +374,9 @@ func TestDaemonReconnectsToShimIOPipesOnRestart(t *testing.T) { | |||||||
|  |  | ||||||
| 	// After we restarted containerd we write some messages to the log pipes, simulating shim writing stuff there. | 	// After we restarted containerd we write some messages to the log pipes, simulating shim writing stuff there. | ||||||
| 	// Then we make sure that these messages are available on the containerd log thus proving that the server reconnected to the log pipes | 	// Then we make sure that these messages are available on the containerd log thus proving that the server reconnected to the log pipes | ||||||
| 	runtimeVersion := getRuntimeVersion() | 	logDirPath := getLogDirPath("v2", id) | ||||||
| 	logDirPath := getLogDirPath(runtimeVersion, id) |  | ||||||
|  |  | ||||||
| 	switch runtimeVersion { | 	writeToFile(t, filepath.Join(logDirPath, "log"), fmt.Sprintf("%s writing to log\n", id)) | ||||||
| 	case "v1": |  | ||||||
| 		writeToFile(t, filepath.Join(logDirPath, "shim.stdout.log"), fmt.Sprintf("%s writing to stdout\n", id)) |  | ||||||
| 		writeToFile(t, filepath.Join(logDirPath, "shim.stderr.log"), fmt.Sprintf("%s writing to stderr\n", id)) |  | ||||||
| 	case "v2": |  | ||||||
| 		writeToFile(t, filepath.Join(logDirPath, "log"), fmt.Sprintf("%s writing to log\n", id)) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	statusC, err := task.Wait(ctx) | 	statusC, err := task.Wait(ctx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -402,18 +394,8 @@ func TestDaemonReconnectsToShimIOPipesOnRestart(t *testing.T) { | |||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	switch runtimeVersion { | 	if !strings.Contains(string(stdioContents), fmt.Sprintf("%s writing to log", id)) { | ||||||
| 	case "v1": | 		t.Fatal("containerd did not connect to the shim log pipe") | ||||||
| 		if !strings.Contains(string(stdioContents), fmt.Sprintf("%s writing to stdout", id)) { |  | ||||||
| 			t.Fatal("containerd did not connect to the shim stdout pipe") |  | ||||||
| 		} |  | ||||||
| 		if !strings.Contains(string(stdioContents), fmt.Sprintf("%s writing to stderr", id)) { |  | ||||||
| 			t.Fatal("containerd did not connect to the shim stderr pipe") |  | ||||||
| 		} |  | ||||||
| 	case "v2": |  | ||||||
| 		if !strings.Contains(string(stdioContents), fmt.Sprintf("%s writing to log", id)) { |  | ||||||
| 			t.Fatal("containerd did not connect to the shim log pipe") |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -432,8 +414,6 @@ func writeToFile(t *testing.T, filePath, message string) { | |||||||
|  |  | ||||||
| func getLogDirPath(runtimeVersion, id string) string { | func getLogDirPath(runtimeVersion, id string) string { | ||||||
| 	switch runtimeVersion { | 	switch runtimeVersion { | ||||||
| 	case "v1": |  | ||||||
| 		return filepath.Join(defaultRoot, plugin.RuntimeLinuxV1, testNamespace, id) |  | ||||||
| 	case "v2": | 	case "v2": | ||||||
| 		return filepath.Join(defaultState, "io.containerd.runtime.v2.task", testNamespace, id) | 		return filepath.Join(defaultState, "io.containerd.runtime.v2.task", testNamespace, id) | ||||||
| 	default: | 	default: | ||||||
| @@ -441,15 +421,6 @@ func getLogDirPath(runtimeVersion, id string) string { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func getRuntimeVersion() string { |  | ||||||
| 	switch rt := os.Getenv("TEST_RUNTIME"); rt { |  | ||||||
| 	case plugin.RuntimeLinuxV1: |  | ||||||
| 		return "v1" |  | ||||||
| 	default: |  | ||||||
| 		return "v2" |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestContainerAttach(t *testing.T) { | func TestContainerAttach(t *testing.T) { | ||||||
| 	t.Parallel() | 	t.Parallel() | ||||||
|  |  | ||||||
| @@ -1031,49 +1002,6 @@ func TestDaemonRestartWithRunningShim(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestContainerRuntimeOptionsv1(t *testing.T) { |  | ||||||
| 	t.Parallel() |  | ||||||
|  |  | ||||||
| 	client, err := newClient(t, address) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
| 	defer client.Close() |  | ||||||
|  |  | ||||||
| 	var ( |  | ||||||
| 		image       Image |  | ||||||
| 		ctx, cancel = testContext(t) |  | ||||||
| 		id          = t.Name() |  | ||||||
| 	) |  | ||||||
| 	defer cancel() |  | ||||||
|  |  | ||||||
| 	image, err = client.GetImage(ctx, testImage) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	container, err := client.NewContainer( |  | ||||||
| 		ctx, id, |  | ||||||
| 		WithNewSnapshot(id, image), |  | ||||||
| 		WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)), |  | ||||||
| 		WithRuntime(plugin.RuntimeLinuxV1, &runctypes.RuncOptions{Runtime: "no-runc"}), |  | ||||||
| 	) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
| 	defer container.Delete(ctx, WithSnapshotCleanup) |  | ||||||
|  |  | ||||||
| 	task, err := container.NewTask(ctx, empty()) |  | ||||||
| 	if err == nil { |  | ||||||
| 		t.Errorf("task creation should have failed") |  | ||||||
| 		task.Delete(ctx) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if !strings.Contains(err.Error(), `"no-runc"`) { |  | ||||||
| 		t.Errorf("task creation should have failed because of lack of executable. Instead failed with: %v", err.Error()) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestContainerRuntimeOptionsv2(t *testing.T) { | func TestContainerRuntimeOptionsv2(t *testing.T) { | ||||||
| 	t.Parallel() | 	t.Parallel() | ||||||
|  |  | ||||||
| @@ -1099,7 +1027,7 @@ func TestContainerRuntimeOptionsv2(t *testing.T) { | |||||||
| 		ctx, id, | 		ctx, id, | ||||||
| 		WithNewSnapshot(id, image), | 		WithNewSnapshot(id, image), | ||||||
| 		WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)), | 		WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)), | ||||||
| 		WithRuntime(plugin.RuntimeRuncV1, &options.Options{BinaryName: "no-runc"}), | 		WithRuntime(plugin.RuntimeRuncV2, &options.Options{BinaryName: "no-runc"}), | ||||||
| 	) | 	) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| @@ -1187,17 +1115,9 @@ func testUserNamespaces(t *testing.T, readonlyRootFS bool) { | |||||||
| 	} | 	} | ||||||
| 	defer container.Delete(ctx, WithSnapshotCleanup) | 	defer container.Delete(ctx, WithSnapshotCleanup) | ||||||
|  |  | ||||||
| 	var copts interface{} | 	copts := &options.Options{ | ||||||
| 	if CheckRuntime(client.Runtime(), "io.containerd.runc") { | 		IoUid: 1000, | ||||||
| 		copts = &options.Options{ | 		IoGid: 2000, | ||||||
| 			IoUid: 1000, |  | ||||||
| 			IoGid: 2000, |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		copts = &runctypes.CreateOptions{ |  | ||||||
| 			IoUid: 1000, |  | ||||||
| 			IoGid: 2000, |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio), func(_ context.Context, client *Client, r *TaskInfo) error { | 	task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStdio), func(_ context.Context, client *Client, r *TaskInfo) error { | ||||||
|   | |||||||
| @@ -39,7 +39,6 @@ import ( | |||||||
| 	"github.com/containerd/containerd/namespaces" | 	"github.com/containerd/containerd/namespaces" | ||||||
| 	"github.com/containerd/containerd/oci" | 	"github.com/containerd/containerd/oci" | ||||||
| 	"github.com/containerd/containerd/platforms" | 	"github.com/containerd/containerd/platforms" | ||||||
| 	"github.com/containerd/containerd/plugin" |  | ||||||
| 	gogotypes "github.com/containerd/containerd/protobuf/types" | 	gogotypes "github.com/containerd/containerd/protobuf/types" | ||||||
| 	_ "github.com/containerd/containerd/runtime" | 	_ "github.com/containerd/containerd/runtime" | ||||||
| 	"github.com/containerd/containerd/runtime/v2/runc/options" | 	"github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
| @@ -670,10 +669,6 @@ func TestKillContainerDeletedByRunc(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| 	defer client.Close() | 	defer client.Close() | ||||||
|  |  | ||||||
| 	if client.Runtime() == plugin.RuntimeLinuxV1 { |  | ||||||
| 		t.Skip("test relies on runtime v2") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var ( | 	var ( | ||||||
| 		image       Image | 		image       Image | ||||||
| 		ctx, cancel = testContext(t) | 		ctx, cancel = testContext(t) | ||||||
|   | |||||||
| @@ -55,7 +55,7 @@ version = 2 | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	id := t.Name() | 	id := t.Name() | ||||||
| 	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("top")), WithRuntime(plugin.RuntimeRuncV1, &options.Options{ | 	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("top")), WithRuntime(plugin.RuntimeRuncV2, &options.Options{ | ||||||
| 		Root: runtimeRoot, | 		Root: runtimeRoot, | ||||||
| 	})) | 	})) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|   | |||||||
| @@ -1,64 +0,0 @@ | |||||||
| //go: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 client |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"testing" |  | ||||||
|  |  | ||||||
| 	. "github.com/containerd/containerd" |  | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func TestWithNoNewKeyringAddsNoNewKeyringToOptions(t *testing.T) { |  | ||||||
| 	var taskInfo TaskInfo |  | ||||||
| 	var ctx context.Context |  | ||||||
| 	var client Client |  | ||||||
|  |  | ||||||
| 	err := WithNoNewKeyring(ctx, &client, &taskInfo) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	opts := taskInfo.Options.(*runctypes.CreateOptions) |  | ||||||
|  |  | ||||||
| 	if !opts.NoNewKeyring { |  | ||||||
| 		t.Fatal("NoNewKeyring set on WithNoNewKeyring") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestWithNoNewKeyringDoesNotOverwriteOtherOptions(t *testing.T) { |  | ||||||
| 	var taskInfo TaskInfo |  | ||||||
| 	var ctx context.Context |  | ||||||
| 	var client Client |  | ||||||
|  |  | ||||||
| 	taskInfo.Options = &runctypes.CreateOptions{NoPivotRoot: true} |  | ||||||
|  |  | ||||||
| 	err := WithNoNewKeyring(ctx, &client, &taskInfo) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	opts := taskInfo.Options.(*runctypes.CreateOptions) |  | ||||||
|  |  | ||||||
| 	if !opts.NoPivotRoot { |  | ||||||
| 		t.Fatal("WithNoNewKeyring overwrote other options") |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -30,7 +30,6 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	v1shimcli "github.com/containerd/containerd/runtime/v1/shim/client" |  | ||||||
| 	v2shimcli "github.com/containerd/containerd/runtime/v2/shim" | 	v2shimcli "github.com/containerd/containerd/runtime/v2/shim" | ||||||
| 	"github.com/containerd/ttrpc" | 	"github.com/containerd/ttrpc" | ||||||
| ) | ) | ||||||
| @@ -47,10 +46,8 @@ func TestFailFastWhenConnectShim(t *testing.T) { | |||||||
|  |  | ||||||
| 	// abstract Unix domain sockets are only for Linux. | 	// abstract Unix domain sockets are only for Linux. | ||||||
| 	if runtime.GOOS == "linux" { | 	if runtime.GOOS == "linux" { | ||||||
| 		t.Run("abstract-unix-socket-v1", testFailFastWhenConnectShim(true, v1shimcli.AnonDialer)) |  | ||||||
| 		t.Run("abstract-unix-socket-v2", testFailFastWhenConnectShim(true, v2shimcli.AnonDialer)) | 		t.Run("abstract-unix-socket-v2", testFailFastWhenConnectShim(true, v2shimcli.AnonDialer)) | ||||||
| 	} | 	} | ||||||
| 	t.Run("normal-unix-socket-v1", testFailFastWhenConnectShim(false, v1shimcli.AnonDialer)) |  | ||||||
| 	t.Run("normal-unix-socket-v2", testFailFastWhenConnectShim(false, v2shimcli.AnonDialer)) | 	t.Run("normal-unix-socket-v2", testFailFastWhenConnectShim(false, v2shimcli.AnonDialer)) | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -28,7 +28,6 @@ import ( | |||||||
| 	"github.com/containerd/containerd/log" | 	"github.com/containerd/containerd/log" | ||||||
| 	"github.com/containerd/containerd/namespaces" | 	"github.com/containerd/containerd/namespaces" | ||||||
| 	"github.com/containerd/containerd/runtime" | 	"github.com/containerd/containerd/runtime" | ||||||
| 	"github.com/containerd/containerd/runtime/v1/linux" |  | ||||||
| 	"github.com/docker/go-metrics" | 	"github.com/docker/go-metrics" | ||||||
| 	"github.com/sirupsen/logrus" | 	"github.com/sirupsen/logrus" | ||||||
| ) | ) | ||||||
| @@ -55,11 +54,15 @@ type cgroupsMonitor struct { | |||||||
| 	publisher events.Publisher | 	publisher events.Publisher | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type cgroupTask interface { | ||||||
|  | 	Cgroup() (cgroups.Cgroup, error) | ||||||
|  | } | ||||||
|  |  | ||||||
| func (m *cgroupsMonitor) Monitor(c runtime.Task, labels map[string]string) error { | func (m *cgroupsMonitor) Monitor(c runtime.Task, labels map[string]string) error { | ||||||
| 	if err := m.collector.Add(c, labels); err != nil { | 	if err := m.collector.Add(c, labels); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	t, ok := c.(*linux.Task) | 	t, ok := c.(cgroupTask) | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -24,7 +24,6 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/log" | 	"github.com/containerd/containerd/log" | ||||||
| 	"github.com/containerd/containerd/plugin" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type SandboxControllerMode string | type SandboxControllerMode string | ||||||
| @@ -46,10 +45,6 @@ type Runtime struct { | |||||||
| 	// When specified, containerd will ignore runtime name field when resolving shim location. | 	// When specified, containerd will ignore runtime name field when resolving shim location. | ||||||
| 	// Path must be abs. | 	// Path must be abs. | ||||||
| 	Path string `toml:"runtime_path" json:"runtimePath"` | 	Path string `toml:"runtime_path" json:"runtimePath"` | ||||||
| 	// Engine is the name of the runtime engine used by containerd. |  | ||||||
| 	// This only works for runtime type "io.containerd.runtime.v1.linux". |  | ||||||
| 	// DEPRECATED: use Options instead. Remove when shim v1 is deprecated. |  | ||||||
| 	Engine string `toml:"runtime_engine" json:"runtimeEngine"` |  | ||||||
| 	// PodAnnotations is a list of pod annotations passed to both pod sandbox as well as | 	// PodAnnotations is a list of pod annotations passed to both pod sandbox as well as | ||||||
| 	// container OCI annotations. | 	// container OCI annotations. | ||||||
| 	PodAnnotations []string `toml:"pod_annotations" json:"PodAnnotations"` | 	PodAnnotations []string `toml:"pod_annotations" json:"PodAnnotations"` | ||||||
| @@ -57,10 +52,6 @@ type Runtime struct { | |||||||
| 	// Container annotations in CRI are usually generated by other Kubernetes node components (i.e., not users). | 	// Container annotations in CRI are usually generated by other Kubernetes node components (i.e., not users). | ||||||
| 	// Currently, only device plugins populate the annotations. | 	// Currently, only device plugins populate the annotations. | ||||||
| 	ContainerAnnotations []string `toml:"container_annotations" json:"ContainerAnnotations"` | 	ContainerAnnotations []string `toml:"container_annotations" json:"ContainerAnnotations"` | ||||||
| 	// Root is the directory used by containerd for runtime state. |  | ||||||
| 	// DEPRECATED: use Options instead. Remove when shim v1 is deprecated. |  | ||||||
| 	// This only works for runtime type "io.containerd.runtime.v1.linux". |  | ||||||
| 	Root string `toml:"runtime_root" json:"runtimeRoot"` |  | ||||||
| 	// Options are config options for the runtime. | 	// Options are config options for the runtime. | ||||||
| 	// If options is loaded from toml config, it will be map[string]interface{}. | 	// If options is loaded from toml config, it will be map[string]interface{}. | ||||||
| 	// Options can be converted into toml.Tree using toml.TreeFromMap(). | 	// Options can be converted into toml.Tree using toml.TreeFromMap(). | ||||||
| @@ -99,19 +90,10 @@ type ContainerdConfig struct { | |||||||
| 	Snapshotter string `toml:"snapshotter" json:"snapshotter"` | 	Snapshotter string `toml:"snapshotter" json:"snapshotter"` | ||||||
| 	// DefaultRuntimeName is the default runtime name to use from the runtimes table. | 	// DefaultRuntimeName is the default runtime name to use from the runtimes table. | ||||||
| 	DefaultRuntimeName string `toml:"default_runtime_name" json:"defaultRuntimeName"` | 	DefaultRuntimeName string `toml:"default_runtime_name" json:"defaultRuntimeName"` | ||||||
| 	// DefaultRuntime is the default runtime to use in containerd. |  | ||||||
| 	// This runtime is used when no runtime handler (or the empty string) is provided. |  | ||||||
| 	// DEPRECATED: use DefaultRuntimeName instead. Remove in containerd 1.4. |  | ||||||
| 	DefaultRuntime Runtime `toml:"default_runtime" json:"defaultRuntime"` |  | ||||||
| 	// UntrustedWorkloadRuntime is a runtime to run untrusted workloads on it. |  | ||||||
| 	// DEPRECATED: use `untrusted` runtime in Runtimes instead. Remove in containerd 1.4. |  | ||||||
| 	UntrustedWorkloadRuntime Runtime `toml:"untrusted_workload_runtime" json:"untrustedWorkloadRuntime"` |  | ||||||
| 	// Runtimes is a map from CRI RuntimeHandler strings, which specify types of runtime | 	// Runtimes is a map from CRI RuntimeHandler strings, which specify types of runtime | ||||||
| 	// configurations, to the matching configurations. | 	// configurations, to the matching configurations. | ||||||
| 	Runtimes map[string]Runtime `toml:"runtimes" json:"runtimes"` | 	Runtimes map[string]Runtime `toml:"runtimes" json:"runtimes"` | ||||||
| 	// NoPivot disables pivot-root (linux only), required when running a container in a RamDisk with runc |  | ||||||
| 	// This only works for runtime type "io.containerd.runtime.v1.linux". |  | ||||||
| 	NoPivot bool `toml:"no_pivot" json:"noPivot"` |  | ||||||
|  |  | ||||||
| 	// DisableSnapshotAnnotations disables to pass additional annotations (image | 	// DisableSnapshotAnnotations disables to pass additional annotations (image | ||||||
| 	// related information) to snapshotters. These annotations are required by | 	// related information) to snapshotters. These annotations are required by | ||||||
| @@ -274,10 +256,6 @@ type PluginConfig struct { | |||||||
| 	SandboxImage string `toml:"sandbox_image" json:"sandboxImage"` | 	SandboxImage string `toml:"sandbox_image" json:"sandboxImage"` | ||||||
| 	// StatsCollectPeriod is the period (in seconds) of snapshots stats collection. | 	// StatsCollectPeriod is the period (in seconds) of snapshots stats collection. | ||||||
| 	StatsCollectPeriod int `toml:"stats_collect_period" json:"statsCollectPeriod"` | 	StatsCollectPeriod int `toml:"stats_collect_period" json:"statsCollectPeriod"` | ||||||
| 	// SystemdCgroup enables systemd cgroup support. |  | ||||||
| 	// This only works for runtime type "io.containerd.runtime.v1.linux". |  | ||||||
| 	// DEPRECATED: config runc runtime handler instead. Remove when shim v1 is deprecated. |  | ||||||
| 	SystemdCgroup bool `toml:"systemd_cgroup" json:"systemdCgroup"` |  | ||||||
| 	// EnableTLSStreaming indicates to enable the TLS streaming support. | 	// EnableTLSStreaming indicates to enable the TLS streaming support. | ||||||
| 	EnableTLSStreaming bool `toml:"enable_tls_streaming" json:"enableTLSStreaming"` | 	EnableTLSStreaming bool `toml:"enable_tls_streaming" json:"enableTLSStreaming"` | ||||||
| 	// X509KeyPairStreaming is a x509 key pair used for TLS streaming | 	// X509KeyPairStreaming is a x509 key pair used for TLS streaming | ||||||
| @@ -401,22 +379,6 @@ func ValidatePluginConfig(ctx context.Context, c *PluginConfig) error { | |||||||
| 		c.ContainerdConfig.Runtimes = make(map[string]Runtime) | 		c.ContainerdConfig.Runtimes = make(map[string]Runtime) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Validation for deprecated untrusted_workload_runtime. |  | ||||||
| 	if c.ContainerdConfig.UntrustedWorkloadRuntime.Type != "" { |  | ||||||
| 		log.G(ctx).Warning("`untrusted_workload_runtime` is deprecated, please use `untrusted` runtime in `runtimes` instead") |  | ||||||
| 		if _, ok := c.ContainerdConfig.Runtimes[RuntimeUntrusted]; ok { |  | ||||||
| 			return fmt.Errorf("conflicting definitions: configuration includes both `untrusted_workload_runtime` and `runtimes[%q]`", RuntimeUntrusted) |  | ||||||
| 		} |  | ||||||
| 		c.ContainerdConfig.Runtimes[RuntimeUntrusted] = c.ContainerdConfig.UntrustedWorkloadRuntime |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Validation for deprecated default_runtime field. |  | ||||||
| 	if c.ContainerdConfig.DefaultRuntime.Type != "" { |  | ||||||
| 		log.G(ctx).Warning("`default_runtime` is deprecated, please use `default_runtime_name` to reference the default configuration you have defined in `runtimes`") |  | ||||||
| 		c.ContainerdConfig.DefaultRuntimeName = RuntimeDefault |  | ||||||
| 		c.ContainerdConfig.Runtimes[RuntimeDefault] = c.ContainerdConfig.DefaultRuntime |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Validation for default_runtime_name | 	// Validation for default_runtime_name | ||||||
| 	if c.ContainerdConfig.DefaultRuntimeName == "" { | 	if c.ContainerdConfig.DefaultRuntimeName == "" { | ||||||
| 		return errors.New("`default_runtime_name` is empty") | 		return errors.New("`default_runtime_name` is empty") | ||||||
| @@ -425,33 +387,7 @@ func ValidatePluginConfig(ctx context.Context, c *PluginConfig) error { | |||||||
| 		return fmt.Errorf("no corresponding runtime configured in `containerd.runtimes` for `containerd` `default_runtime_name = \"%s\"", c.ContainerdConfig.DefaultRuntimeName) | 		return fmt.Errorf("no corresponding runtime configured in `containerd.runtimes` for `containerd` `default_runtime_name = \"%s\"", c.ContainerdConfig.DefaultRuntimeName) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Validation for deprecated runtime options. |  | ||||||
| 	if c.SystemdCgroup { |  | ||||||
| 		if c.ContainerdConfig.Runtimes[c.ContainerdConfig.DefaultRuntimeName].Type != plugin.RuntimeLinuxV1 { |  | ||||||
| 			return fmt.Errorf("`systemd_cgroup` only works for runtime %s", plugin.RuntimeLinuxV1) |  | ||||||
| 		} |  | ||||||
| 		log.G(ctx).Warning("`systemd_cgroup` is deprecated, please use runtime `options` instead") |  | ||||||
| 	} |  | ||||||
| 	if c.NoPivot { |  | ||||||
| 		if c.ContainerdConfig.Runtimes[c.ContainerdConfig.DefaultRuntimeName].Type != plugin.RuntimeLinuxV1 { |  | ||||||
| 			return fmt.Errorf("`no_pivot` only works for runtime %s", plugin.RuntimeLinuxV1) |  | ||||||
| 		} |  | ||||||
| 		// NoPivot can't be deprecated yet, because there is no alternative config option |  | ||||||
| 		// for `io.containerd.runtime.v1.linux`. |  | ||||||
| 	} |  | ||||||
| 	for k, r := range c.ContainerdConfig.Runtimes { | 	for k, r := range c.ContainerdConfig.Runtimes { | ||||||
| 		if r.Engine != "" { |  | ||||||
| 			if r.Type != plugin.RuntimeLinuxV1 { |  | ||||||
| 				return fmt.Errorf("`runtime_engine` only works for runtime %s", plugin.RuntimeLinuxV1) |  | ||||||
| 			} |  | ||||||
| 			log.G(ctx).Warning("`runtime_engine` is deprecated, please use runtime `options` instead") |  | ||||||
| 		} |  | ||||||
| 		if r.Root != "" { |  | ||||||
| 			if r.Type != plugin.RuntimeLinuxV1 { |  | ||||||
| 				return fmt.Errorf("`runtime_root` only works for runtime %s", plugin.RuntimeLinuxV1) |  | ||||||
| 			} |  | ||||||
| 			log.G(ctx).Warning("`runtime_root` is deprecated, please use runtime `options` instead") |  | ||||||
| 		} |  | ||||||
| 		if !r.PrivilegedWithoutHostDevices && r.PrivilegedWithoutHostDevicesAllDevicesAllowed { | 		if !r.PrivilegedWithoutHostDevices && r.PrivilegedWithoutHostDevicesAllDevicesAllowed { | ||||||
| 			return errors.New("`privileged_without_host_devices_all_devices_allowed` requires `privileged_without_host_devices` to be enabled") | 			return errors.New("`privileged_without_host_devices_all_devices_allowed` requires `privileged_without_host_devices` to be enabled") | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -18,10 +18,8 @@ package config | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" |  | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/plugin" |  | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -31,81 +29,6 @@ func TestValidateConfig(t *testing.T) { | |||||||
| 		expectedErr string | 		expectedErr string | ||||||
| 		expected    *PluginConfig | 		expected    *PluginConfig | ||||||
| 	}{ | 	}{ | ||||||
| 		"deprecated untrusted_workload_runtime": { |  | ||||||
| 			config: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					UntrustedWorkloadRuntime: Runtime{ |  | ||||||
| 						Type: "untrusted", |  | ||||||
| 					}, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Type: "default", |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			expected: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					UntrustedWorkloadRuntime: Runtime{ |  | ||||||
| 						Type: "untrusted", |  | ||||||
| 					}, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeUntrusted: { |  | ||||||
| 							Type:        "untrusted", |  | ||||||
| 							SandboxMode: string(ModePodSandbox), |  | ||||||
| 						}, |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Type:        "default", |  | ||||||
| 							SandboxMode: string(ModePodSandbox), |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		"both untrusted_workload_runtime and runtime[untrusted]": { |  | ||||||
| 			config: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					UntrustedWorkloadRuntime: Runtime{ |  | ||||||
| 						Type: "untrusted-1", |  | ||||||
| 					}, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeUntrusted: { |  | ||||||
| 							Type: "untrusted-2", |  | ||||||
| 						}, |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Type: "default", |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			expectedErr: fmt.Sprintf("conflicting definitions: configuration includes both `untrusted_workload_runtime` and `runtimes[%q]`", RuntimeUntrusted), |  | ||||||
| 		}, |  | ||||||
| 		"deprecated default_runtime": { |  | ||||||
| 			config: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntime: Runtime{ |  | ||||||
| 						Type: "default", |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			expected: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntime: Runtime{ |  | ||||||
| 						Type: "default", |  | ||||||
| 					}, |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Type:        "default", |  | ||||||
| 							SandboxMode: string(ModePodSandbox), |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		"no default_runtime_name": { | 		"no default_runtime_name": { | ||||||
| 			config:      &PluginConfig{}, | 			config:      &PluginConfig{}, | ||||||
| 			expectedErr: "`default_runtime_name` is empty", | 			expectedErr: "`default_runtime_name` is empty", | ||||||
| @@ -118,170 +41,13 @@ func TestValidateConfig(t *testing.T) { | |||||||
| 			}, | 			}, | ||||||
| 			expectedErr: "no corresponding runtime configured in `containerd.runtimes` for `containerd` `default_runtime_name = \"default\"", | 			expectedErr: "no corresponding runtime configured in `containerd.runtimes` for `containerd` `default_runtime_name = \"default\"", | ||||||
| 		}, | 		}, | ||||||
| 		"deprecated systemd_cgroup for v1 runtime": { |  | ||||||
| 			config: &PluginConfig{ |  | ||||||
| 				SystemdCgroup: true, |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Type: plugin.RuntimeLinuxV1, |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			expected: &PluginConfig{ |  | ||||||
| 				SystemdCgroup: true, |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Type:        plugin.RuntimeLinuxV1, |  | ||||||
| 							SandboxMode: string(ModePodSandbox), |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		"deprecated systemd_cgroup for v2 runtime": { |  | ||||||
| 			config: &PluginConfig{ |  | ||||||
| 				SystemdCgroup: true, |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Type: plugin.RuntimeRuncV1, |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			expectedErr: fmt.Sprintf("`systemd_cgroup` only works for runtime %s", plugin.RuntimeLinuxV1), |  | ||||||
| 		}, |  | ||||||
| 		"no_pivot for v1 runtime": { |  | ||||||
| 			config: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					NoPivot:            true, |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Type: plugin.RuntimeLinuxV1, |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			expected: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					NoPivot:            true, |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Type:        plugin.RuntimeLinuxV1, |  | ||||||
| 							SandboxMode: string(ModePodSandbox), |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		"no_pivot for v2 runtime": { |  | ||||||
| 			config: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					NoPivot:            true, |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Type: plugin.RuntimeRuncV1, |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			expectedErr: fmt.Sprintf("`no_pivot` only works for runtime %s", plugin.RuntimeLinuxV1), |  | ||||||
| 		}, |  | ||||||
| 		"deprecated runtime_engine for v1 runtime": { |  | ||||||
| 			config: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Engine: "runc", |  | ||||||
| 							Type:   plugin.RuntimeLinuxV1, |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			expected: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Engine:      "runc", |  | ||||||
| 							Type:        plugin.RuntimeLinuxV1, |  | ||||||
| 							SandboxMode: string(ModePodSandbox), |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		"deprecated runtime_engine for v2 runtime": { |  | ||||||
| 			config: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Engine: "runc", |  | ||||||
| 							Type:   plugin.RuntimeRuncV1, |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			expectedErr: fmt.Sprintf("`runtime_engine` only works for runtime %s", plugin.RuntimeLinuxV1), |  | ||||||
| 		}, |  | ||||||
| 		"deprecated runtime_root for v1 runtime": { |  | ||||||
| 			config: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Root: "/run/containerd/runc", |  | ||||||
| 							Type: plugin.RuntimeLinuxV1, |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			expected: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Root:        "/run/containerd/runc", |  | ||||||
| 							Type:        plugin.RuntimeLinuxV1, |  | ||||||
| 							SandboxMode: string(ModePodSandbox), |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		"deprecated runtime_root for v2 runtime": { |  | ||||||
| 			config: &PluginConfig{ |  | ||||||
| 				ContainerdConfig: ContainerdConfig{ |  | ||||||
| 					DefaultRuntimeName: RuntimeDefault, |  | ||||||
| 					Runtimes: map[string]Runtime{ |  | ||||||
| 						RuntimeDefault: { |  | ||||||
| 							Root: "/run/containerd/runc", |  | ||||||
| 							Type: plugin.RuntimeRuncV1, |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			expectedErr: fmt.Sprintf("`runtime_root` only works for runtime %s", plugin.RuntimeLinuxV1), |  | ||||||
| 		}, |  | ||||||
| 		"deprecated auths": { | 		"deprecated auths": { | ||||||
| 			config: &PluginConfig{ | 			config: &PluginConfig{ | ||||||
| 				ContainerdConfig: ContainerdConfig{ | 				ContainerdConfig: ContainerdConfig{ | ||||||
| 					DefaultRuntimeName: RuntimeDefault, | 					DefaultRuntimeName: RuntimeDefault, | ||||||
| 					Runtimes: map[string]Runtime{ | 					Runtimes: map[string]Runtime{ | ||||||
| 						RuntimeDefault: { | 						RuntimeDefault: {}, | ||||||
| 							Type: plugin.RuntimeRuncV1, |  | ||||||
| 						}, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 				Registry: Registry{ | 				Registry: Registry{ | ||||||
| @@ -295,7 +61,6 @@ func TestValidateConfig(t *testing.T) { | |||||||
| 					DefaultRuntimeName: RuntimeDefault, | 					DefaultRuntimeName: RuntimeDefault, | ||||||
| 					Runtimes: map[string]Runtime{ | 					Runtimes: map[string]Runtime{ | ||||||
| 						RuntimeDefault: { | 						RuntimeDefault: { | ||||||
| 							Type:        plugin.RuntimeRuncV1, |  | ||||||
| 							SandboxMode: string(ModePodSandbox), | 							SandboxMode: string(ModePodSandbox), | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
|   | |||||||
| @@ -29,9 +29,6 @@ import ( | |||||||
| // DefaultConfig returns default configurations of cri plugin. | // DefaultConfig returns default configurations of cri plugin. | ||||||
| func DefaultConfig() PluginConfig { | func DefaultConfig() PluginConfig { | ||||||
| 	defaultRuncV2Opts := ` | 	defaultRuncV2Opts := ` | ||||||
| 	# NoPivotRoot disables pivot root when creating a container. |  | ||||||
| 	NoPivotRoot = false |  | ||||||
|  |  | ||||||
| 	# NoNewKeyring disables new keyring for the container. | 	# NoNewKeyring disables new keyring for the container. | ||||||
| 	NoNewKeyring = false | 	NoNewKeyring = false | ||||||
|  |  | ||||||
| @@ -53,9 +50,6 @@ func DefaultConfig() PluginConfig { | |||||||
| 	# CriuPath is the criu binary path. | 	# CriuPath is the criu binary path. | ||||||
| 	CriuPath = "" | 	CriuPath = "" | ||||||
|  |  | ||||||
| 	# SystemdCgroup enables systemd cgroups. |  | ||||||
| 	SystemdCgroup = false |  | ||||||
|  |  | ||||||
| 	# CriuImagePath is the criu image path | 	# CriuImagePath is the criu image path | ||||||
| 	CriuImagePath = "" | 	CriuImagePath = "" | ||||||
|  |  | ||||||
| @@ -74,7 +68,6 @@ func DefaultConfig() PluginConfig { | |||||||
| 		ContainerdConfig: ContainerdConfig{ | 		ContainerdConfig: ContainerdConfig{ | ||||||
| 			Snapshotter:        containerd.DefaultSnapshotter, | 			Snapshotter:        containerd.DefaultSnapshotter, | ||||||
| 			DefaultRuntimeName: "runc", | 			DefaultRuntimeName: "runc", | ||||||
| 			NoPivot:            false, |  | ||||||
| 			Runtimes: map[string]Runtime{ | 			Runtimes: map[string]Runtime{ | ||||||
| 				"runc": { | 				"runc": { | ||||||
| 					Type:        "io.containerd.runc.v2", | 					Type:        "io.containerd.runc.v2", | ||||||
| @@ -97,7 +90,6 @@ func DefaultConfig() PluginConfig { | |||||||
| 		}, | 		}, | ||||||
| 		SandboxImage:                     "registry.k8s.io/pause:3.8", | 		SandboxImage:                     "registry.k8s.io/pause:3.8", | ||||||
| 		StatsCollectPeriod:               10, | 		StatsCollectPeriod:               10, | ||||||
| 		SystemdCgroup:                    false, |  | ||||||
| 		MaxContainerLogLineSize:          16 * 1024, | 		MaxContainerLogLineSize:          16 * 1024, | ||||||
| 		MaxConcurrentDownloads:           3, | 		MaxConcurrentDownloads:           3, | ||||||
| 		DisableProcMount:                 false, | 		DisableProcMount:                 false, | ||||||
|   | |||||||
| @@ -38,7 +38,6 @@ func DefaultConfig() PluginConfig { | |||||||
| 		ContainerdConfig: ContainerdConfig{ | 		ContainerdConfig: ContainerdConfig{ | ||||||
| 			Snapshotter:        containerd.DefaultSnapshotter, | 			Snapshotter:        containerd.DefaultSnapshotter, | ||||||
| 			DefaultRuntimeName: "runhcs-wcow-process", | 			DefaultRuntimeName: "runhcs-wcow-process", | ||||||
| 			NoPivot:            false, |  | ||||||
| 			Runtimes: map[string]Runtime{ | 			Runtimes: map[string]Runtime{ | ||||||
| 				"runhcs-wcow-process": { | 				"runhcs-wcow-process": { | ||||||
| 					Type:                 "io.containerd.runhcs.v1", | 					Type:                 "io.containerd.runhcs.v1", | ||||||
|   | |||||||
| @@ -1,38 +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 opts |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd" |  | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // WithContainerdShimCgroup returns function that sets the containerd |  | ||||||
| // shim cgroup path |  | ||||||
| func WithContainerdShimCgroup(path string) containerd.NewTaskOpts { |  | ||||||
| 	return func(_ context.Context, _ *containerd.Client, r *containerd.TaskInfo) error { |  | ||||||
| 		r.Options = &runctypes.CreateOptions{ |  | ||||||
| 			ShimCgroup: path, |  | ||||||
| 		} |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| //TODO: Since Options is an interface different WithXXX will be needed to set different |  | ||||||
| // combinations of CreateOptions. |  | ||||||
| @@ -110,17 +110,12 @@ func (c *criService) StartContainer(ctx context.Context, r *runtime.StartContain | |||||||
| 		return cntr.IO, nil | 		return cntr.IO, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ctrInfo, err := container.Info(ctx) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("failed to get container info: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ociRuntime, err := c.getSandboxRuntime(sandbox.Config, sandbox.Metadata.RuntimeHandler) | 	ociRuntime, err := c.getSandboxRuntime(sandbox.Config, sandbox.Metadata.RuntimeHandler) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to get sandbox runtime: %w", err) | 		return nil, fmt.Errorf("failed to get sandbox runtime: %w", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	taskOpts := c.taskOpts(ctrInfo.Runtime.Name) | 	var taskOpts []containerd.NewTaskOpts | ||||||
| 	if ociRuntime.Path != "" { | 	if ociRuntime.Path != "" { | ||||||
| 		taskOpts = append(taskOpts, containerd.WithRuntimePath(ociRuntime.Path)) | 		taskOpts = append(taskOpts, containerd.WithRuntimePath(ociRuntime.Path)) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -42,7 +42,6 @@ import ( | |||||||
| 	runtimeoptions "github.com/containerd/containerd/pkg/runtimeoptions/v1" | 	runtimeoptions "github.com/containerd/containerd/pkg/runtimeoptions/v1" | ||||||
| 	"github.com/containerd/containerd/plugin" | 	"github.com/containerd/containerd/plugin" | ||||||
| 	"github.com/containerd/containerd/reference/docker" | 	"github.com/containerd/containerd/reference/docker" | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" | 	runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
|  |  | ||||||
| 	runhcsoptions "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options" | 	runhcsoptions "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options" | ||||||
| @@ -330,15 +329,7 @@ func parseImageReferences(refs []string) ([]string, []string) { | |||||||
| // generateRuntimeOptions generates runtime options from cri plugin config. | // generateRuntimeOptions generates runtime options from cri plugin config. | ||||||
| func generateRuntimeOptions(r criconfig.Runtime, c criconfig.Config) (interface{}, error) { | func generateRuntimeOptions(r criconfig.Runtime, c criconfig.Config) (interface{}, error) { | ||||||
| 	if r.Options == nil { | 	if r.Options == nil { | ||||||
| 		if r.Type != plugin.RuntimeLinuxV1 { | 		return nil, nil | ||||||
| 			return nil, nil |  | ||||||
| 		} |  | ||||||
| 		// This is a legacy config, generate runctypes.RuncOptions. |  | ||||||
| 		return &runctypes.RuncOptions{ |  | ||||||
| 			Runtime:       r.Engine, |  | ||||||
| 			RuntimeRoot:   r.Root, |  | ||||||
| 			SystemdCgroup: c.SystemdCgroup, |  | ||||||
| 		}, nil |  | ||||||
| 	} | 	} | ||||||
| 	optionsTree, err := toml.TreeFromMap(r.Options) | 	optionsTree, err := toml.TreeFromMap(r.Options) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -364,12 +355,8 @@ func generateRuntimeOptions(r criconfig.Runtime, c criconfig.Config) (interface{ | |||||||
| // getRuntimeOptionsType gets empty runtime options by the runtime type name. | // getRuntimeOptionsType gets empty runtime options by the runtime type name. | ||||||
| func getRuntimeOptionsType(t string) interface{} { | func getRuntimeOptionsType(t string) interface{} { | ||||||
| 	switch t { | 	switch t { | ||||||
| 	case plugin.RuntimeRuncV1: |  | ||||||
| 		fallthrough |  | ||||||
| 	case plugin.RuntimeRuncV2: | 	case plugin.RuntimeRuncV2: | ||||||
| 		return &runcoptions.Options{} | 		return &runcoptions.Options{} | ||||||
| 	case plugin.RuntimeLinuxV1: |  | ||||||
| 		return &runctypes.RuncOptions{} |  | ||||||
| 	case runtimeRunhcsV1: | 	case runtimeRunhcsV1: | ||||||
| 		return &runhcsoptions.Options{} | 		return &runhcsoptions.Options{} | ||||||
| 	default: | 	default: | ||||||
|   | |||||||
| @@ -35,7 +35,6 @@ import ( | |||||||
| 	"github.com/containerd/containerd/plugin" | 	"github.com/containerd/containerd/plugin" | ||||||
| 	"github.com/containerd/containerd/protobuf/types" | 	"github.com/containerd/containerd/protobuf/types" | ||||||
| 	"github.com/containerd/containerd/reference/docker" | 	"github.com/containerd/containerd/reference/docker" | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" | 	runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
| 	"github.com/containerd/typeurl/v2" | 	"github.com/containerd/typeurl/v2" | ||||||
|  |  | ||||||
| @@ -210,10 +209,6 @@ systemd_cgroup = true | |||||||
| [containerd] | [containerd] | ||||||
|   no_pivot = true |   no_pivot = true | ||||||
|   default_runtime_name = "default" |   default_runtime_name = "default" | ||||||
| [containerd.runtimes.legacy] |  | ||||||
|   runtime_type = "` + plugin.RuntimeLinuxV1 + `" |  | ||||||
| [containerd.runtimes.runc] |  | ||||||
|   runtime_type = "` + plugin.RuntimeRuncV1 + `" |  | ||||||
| [containerd.runtimes.runcv2] | [containerd.runtimes.runcv2] | ||||||
|   runtime_type = "` + plugin.RuntimeRuncV2 + `" |   runtime_type = "` + plugin.RuntimeRuncV2 + `" | ||||||
| ` | ` | ||||||
| @@ -222,13 +217,9 @@ systemd_cgroup = true | |||||||
| [containerd] | [containerd] | ||||||
|   no_pivot = true |   no_pivot = true | ||||||
|   default_runtime_name = "default" |   default_runtime_name = "default" | ||||||
| [containerd.runtimes.legacy] |  | ||||||
|   runtime_type = "` + plugin.RuntimeLinuxV1 + `" |  | ||||||
| [containerd.runtimes.legacy.options] | [containerd.runtimes.legacy.options] | ||||||
|   Runtime = "legacy" |   Runtime = "legacy" | ||||||
|   RuntimeRoot = "/legacy" |   RuntimeRoot = "/legacy" | ||||||
| [containerd.runtimes.runc] |  | ||||||
|   runtime_type = "` + plugin.RuntimeRuncV1 + `" |  | ||||||
| [containerd.runtimes.runc.options] | [containerd.runtimes.runc.options] | ||||||
|   BinaryName = "runc" |   BinaryName = "runc" | ||||||
|   Root = "/runc" |   Root = "/runc" | ||||||
| @@ -245,7 +236,7 @@ systemd_cgroup = true | |||||||
| 	require.NoError(t, err) | 	require.NoError(t, err) | ||||||
| 	err = tree.Unmarshal(&nilOptsConfig) | 	err = tree.Unmarshal(&nilOptsConfig) | ||||||
| 	require.NoError(t, err) | 	require.NoError(t, err) | ||||||
| 	require.Len(t, nilOptsConfig.Runtimes, 3) | 	require.Len(t, nilOptsConfig.Runtimes, 1) | ||||||
|  |  | ||||||
| 	tree, err = toml.Load(nonNilOpts) | 	tree, err = toml.Load(nonNilOpts) | ||||||
| 	require.NoError(t, err) | 	require.NoError(t, err) | ||||||
| @@ -258,32 +249,11 @@ systemd_cgroup = true | |||||||
| 		c               criconfig.Config | 		c               criconfig.Config | ||||||
| 		expectedOptions interface{} | 		expectedOptions interface{} | ||||||
| 	}{ | 	}{ | ||||||
| 		"when options is nil, should return nil option for io.containerd.runc.v1": { |  | ||||||
| 			r:               nilOptsConfig.Runtimes["runc"], |  | ||||||
| 			c:               nilOptsConfig, |  | ||||||
| 			expectedOptions: nil, |  | ||||||
| 		}, |  | ||||||
| 		"when options is nil, should return nil option for io.containerd.runc.v2": { | 		"when options is nil, should return nil option for io.containerd.runc.v2": { | ||||||
| 			r:               nilOptsConfig.Runtimes["runcv2"], | 			r:               nilOptsConfig.Runtimes["runcv2"], | ||||||
| 			c:               nilOptsConfig, | 			c:               nilOptsConfig, | ||||||
| 			expectedOptions: nil, | 			expectedOptions: nil, | ||||||
| 		}, | 		}, | ||||||
| 		"when options is nil, should use legacy fields for legacy runtime": { |  | ||||||
| 			r: nilOptsConfig.Runtimes["legacy"], |  | ||||||
| 			c: nilOptsConfig, |  | ||||||
| 			expectedOptions: &runctypes.RuncOptions{ |  | ||||||
| 				SystemdCgroup: true, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		"when options is not nil, should be able to decode for io.containerd.runc.v1": { |  | ||||||
| 			r: nonNilOptsConfig.Runtimes["runc"], |  | ||||||
| 			c: nonNilOptsConfig, |  | ||||||
| 			expectedOptions: &runcoptions.Options{ |  | ||||||
| 				BinaryName:   "runc", |  | ||||||
| 				Root:         "/runc", |  | ||||||
| 				NoNewKeyring: true, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		"when options is not nil, should be able to decode for io.containerd.runc.v2": { | 		"when options is not nil, should be able to decode for io.containerd.runc.v2": { | ||||||
| 			r: nonNilOptsConfig.Runtimes["runcv2"], | 			r: nonNilOptsConfig.Runtimes["runcv2"], | ||||||
| 			c: nonNilOptsConfig, | 			c: nonNilOptsConfig, | ||||||
| @@ -293,14 +263,6 @@ systemd_cgroup = true | |||||||
| 				NoNewKeyring: true, | 				NoNewKeyring: true, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		"when options is not nil, should be able to decode for legacy runtime": { |  | ||||||
| 			r: nonNilOptsConfig.Runtimes["legacy"], |  | ||||||
| 			c: nonNilOptsConfig, |  | ||||||
| 			expectedOptions: &runctypes.RuncOptions{ |  | ||||||
| 				Runtime:     "legacy", |  | ||||||
| 				RuntimeRoot: "/legacy", |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 	} { | 	} { | ||||||
| 		t.Run(desc, func(t *testing.T) { | 		t.Run(desc, func(t *testing.T) { | ||||||
| 			opts, err := generateRuntimeOptions(test.r, test.c) | 			opts, err := generateRuntimeOptions(test.r, test.c) | ||||||
|   | |||||||
| @@ -212,7 +212,7 @@ func (c *Controller) Start(ctx context.Context, id string) (cin sandbox.Controll | |||||||
| 	// Create sandbox task in containerd. | 	// Create sandbox task in containerd. | ||||||
| 	log.G(ctx).Tracef("Create sandbox container (id=%q, name=%q).", id, metadata.Name) | 	log.G(ctx).Tracef("Create sandbox container (id=%q, name=%q).", id, metadata.Name) | ||||||
|  |  | ||||||
| 	taskOpts := c.taskOpts(ociRuntime.Type) | 	var taskOpts []containerd.NewTaskOpts | ||||||
| 	if ociRuntime.Path != "" { | 	if ociRuntime.Path != "" { | ||||||
| 		taskOpts = append(taskOpts, containerd.WithRuntimePath(ociRuntime.Path)) | 		taskOpts = append(taskOpts, containerd.WithRuntimePath(ociRuntime.Path)) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -22,9 +22,7 @@ import ( | |||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd" |  | ||||||
| 	"github.com/containerd/containerd/oci" | 	"github.com/containerd/containerd/oci" | ||||||
| 	"github.com/containerd/containerd/plugin" |  | ||||||
| 	imagespec "github.com/opencontainers/image-spec/specs-go/v1" | 	imagespec "github.com/opencontainers/image-spec/specs-go/v1" | ||||||
| 	runtimespec "github.com/opencontainers/runtime-spec/specs-go" | 	runtimespec "github.com/opencontainers/runtime-spec/specs-go" | ||||||
| 	"github.com/opencontainers/selinux/go-selinux" | 	"github.com/opencontainers/selinux/go-selinux" | ||||||
| @@ -325,19 +323,3 @@ func (c *Controller) cleanupSandboxFiles(id string, config *runtime.PodSandboxCo | |||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // taskOpts generates task options for a (sandbox) container. |  | ||||||
| func (c *Controller) taskOpts(runtimeType string) []containerd.NewTaskOpts { |  | ||||||
| 	// TODO(random-liu): Remove this after shim v1 is deprecated. |  | ||||||
| 	var taskOpts []containerd.NewTaskOpts |  | ||||||
|  |  | ||||||
| 	// c.config.NoPivot is only supported for RuntimeLinuxV1 = "io.containerd.runtime.v1.linux" legacy linux runtime |  | ||||||
| 	// and is not supported for RuntimeRuncV1 = "io.containerd.runc.v1" or  RuntimeRuncV2 = "io.containerd.runc.v2" |  | ||||||
| 	// for RuncV1/2 no pivot is set under the containerd.runtimes.runc.options config see |  | ||||||
| 	// https://github.com/containerd/containerd/blob/v1.3.2/runtime/v2/runc/options/oci.pb.go#L26 |  | ||||||
| 	if c.config.NoPivot && runtimeType == plugin.RuntimeLinuxV1 { |  | ||||||
| 		taskOpts = append(taskOpts, containerd.WithNoPivotRoot) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return taskOpts |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -19,7 +19,6 @@ | |||||||
| package podsandbox | package podsandbox | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/containerd/containerd" |  | ||||||
| 	"github.com/containerd/containerd/oci" | 	"github.com/containerd/containerd/oci" | ||||||
| 	"github.com/containerd/containerd/pkg/cri/annotations" | 	"github.com/containerd/containerd/pkg/cri/annotations" | ||||||
| 	imagespec "github.com/opencontainers/image-spec/specs-go/v1" | 	imagespec "github.com/opencontainers/image-spec/specs-go/v1" | ||||||
| @@ -49,8 +48,3 @@ func (c *Controller) setupSandboxFiles(id string, config *runtime.PodSandboxConf | |||||||
| func (c *Controller) cleanupSandboxFiles(id string, config *runtime.PodSandboxConfig) error { | func (c *Controller) cleanupSandboxFiles(id string, config *runtime.PodSandboxConfig) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // taskOpts generates task options for a (sandbox) container. |  | ||||||
| func (c *Controller) taskOpts(runtimeType string) []containerd.NewTaskOpts { |  | ||||||
| 	return []containerd.NewTaskOpts{} |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -26,8 +26,6 @@ import ( | |||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| 	runtime "k8s.io/cri-api/pkg/apis/runtime/v1" | 	runtime "k8s.io/cri-api/pkg/apis/runtime/v1" | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/pkg/cri/annotations" |  | ||||||
| 	criconfig "github.com/containerd/containerd/pkg/cri/config" |  | ||||||
| 	sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" | 	sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -207,166 +205,3 @@ func TestHostAccessingSandbox(t *testing.T) { | |||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestGetSandboxRuntime(t *testing.T) { |  | ||||||
| 	untrustedWorkloadRuntime := criconfig.Runtime{ |  | ||||||
| 		Type:   "io.containerd.runtime.v1.linux", |  | ||||||
| 		Engine: "untrusted-workload-runtime", |  | ||||||
| 		Root:   "", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	defaultRuntime := criconfig.Runtime{ |  | ||||||
| 		Type:   "io.containerd.runtime.v1.linux", |  | ||||||
| 		Engine: "default-runtime", |  | ||||||
| 		Root:   "", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	fooRuntime := criconfig.Runtime{ |  | ||||||
| 		Type:   "io.containerd.runtime.v1.linux", |  | ||||||
| 		Engine: "foo-bar", |  | ||||||
| 		Root:   "", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for desc, test := range map[string]struct { |  | ||||||
| 		sandboxConfig   *runtime.PodSandboxConfig |  | ||||||
| 		runtimeHandler  string |  | ||||||
| 		runtimes        map[string]criconfig.Runtime |  | ||||||
| 		expectErr       bool |  | ||||||
| 		expectedRuntime criconfig.Runtime |  | ||||||
| 	}{ |  | ||||||
| 		"should return error if untrusted workload requires host access": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Linux: &runtime.LinuxPodSandboxConfig{ |  | ||||||
| 					SecurityContext: &runtime.LinuxSandboxSecurityContext{ |  | ||||||
| 						Privileged: false, |  | ||||||
| 						NamespaceOptions: &runtime.NamespaceOption{ |  | ||||||
| 							Network: runtime.NamespaceMode_NODE, |  | ||||||
| 							Pid:     runtime.NamespaceMode_NODE, |  | ||||||
| 							Ipc:     runtime.NamespaceMode_NODE, |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "true", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectErr: true, |  | ||||||
| 		}, |  | ||||||
| 		"should use untrusted workload runtime for untrusted workload": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "true", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectedRuntime: untrustedWorkloadRuntime, |  | ||||||
| 		}, |  | ||||||
| 		"should use default runtime for regular workload": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{}, |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault: defaultRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectedRuntime: defaultRuntime, |  | ||||||
| 		}, |  | ||||||
| 		"should use default runtime for trusted workload": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "false", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectedRuntime: defaultRuntime, |  | ||||||
| 		}, |  | ||||||
| 		"should return error if untrusted workload runtime is required but not configured": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "true", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault: defaultRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectErr: true, |  | ||||||
| 		}, |  | ||||||
| 		"should use 'untrusted' runtime for untrusted workload": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "true", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectedRuntime: untrustedWorkloadRuntime, |  | ||||||
| 		}, |  | ||||||
| 		"should use 'untrusted' runtime for untrusted workload & handler": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "true", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimeHandler: "untrusted", |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectedRuntime: untrustedWorkloadRuntime, |  | ||||||
| 		}, |  | ||||||
| 		"should return an error if untrusted annotation with conflicting handler": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "true", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimeHandler: "foo", |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 				"foo":                      fooRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectErr: true, |  | ||||||
| 		}, |  | ||||||
| 		"should use correct runtime for a runtime handler": { |  | ||||||
| 			sandboxConfig:  &runtime.PodSandboxConfig{}, |  | ||||||
| 			runtimeHandler: "foo", |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 				"foo":                      fooRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectedRuntime: fooRuntime, |  | ||||||
| 		}, |  | ||||||
| 		"should return error if runtime handler is required but not configured": { |  | ||||||
| 			sandboxConfig:  &runtime.PodSandboxConfig{}, |  | ||||||
| 			runtimeHandler: "bar", |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault: defaultRuntime, |  | ||||||
| 				"foo":                    fooRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectErr: true, |  | ||||||
| 		}, |  | ||||||
| 	} { |  | ||||||
| 		t.Run(desc, func(t *testing.T) { |  | ||||||
| 			cri := newControllerService() |  | ||||||
| 			cri.config = criconfig.Config{ |  | ||||||
| 				PluginConfig: criconfig.DefaultConfig(), |  | ||||||
| 			} |  | ||||||
| 			cri.config.ContainerdConfig.DefaultRuntimeName = criconfig.RuntimeDefault |  | ||||||
| 			cri.config.ContainerdConfig.Runtimes = test.runtimes |  | ||||||
| 			r, err := cri.getSandboxRuntime(test.sandboxConfig, test.runtimeHandler) |  | ||||||
| 			assert.Equal(t, test.expectErr, err != nil) |  | ||||||
| 			assert.Equal(t, test.expectedRuntime, r) |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -20,7 +20,6 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"strconv" | 	"strconv" | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd" |  | ||||||
| 	"github.com/containerd/containerd/oci" | 	"github.com/containerd/containerd/oci" | ||||||
| 	imagespec "github.com/opencontainers/image-spec/specs-go/v1" | 	imagespec "github.com/opencontainers/image-spec/specs-go/v1" | ||||||
| 	runtimespec "github.com/opencontainers/runtime-spec/specs-go" | 	runtimespec "github.com/opencontainers/runtime-spec/specs-go" | ||||||
| @@ -102,8 +101,3 @@ func (c *Controller) setupSandboxFiles(id string, config *runtime.PodSandboxConf | |||||||
| func (c *Controller) cleanupSandboxFiles(id string, config *runtime.PodSandboxConfig) error { | func (c *Controller) cleanupSandboxFiles(id string, config *runtime.PodSandboxConfig) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // No task options needed for windows. |  | ||||||
| func (c *Controller) taskOpts(runtimeType string) []containerd.NewTaskOpts { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -1,38 +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 sbserver |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/containerd/containerd" |  | ||||||
| 	"github.com/containerd/containerd/plugin" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // taskOpts generates task options for a (sandbox) container. |  | ||||||
| func (c *criService) taskOpts(runtimeType string) []containerd.NewTaskOpts { |  | ||||||
| 	// TODO(random-liu): Remove this after shim v1 is deprecated. |  | ||||||
| 	var taskOpts []containerd.NewTaskOpts |  | ||||||
|  |  | ||||||
| 	// c.config.NoPivot is only supported for RuntimeLinuxV1 = "io.containerd.runtime.v1.linux" legacy linux runtime |  | ||||||
| 	// and is not supported for RuntimeRuncV1 = "io.containerd.runc.v1" or  RuntimeRuncV2 = "io.containerd.runc.v2" |  | ||||||
| 	// for RuncV1/2 no pivot is set under the containerd.runtimes.runc.options config see |  | ||||||
| 	// https://github.com/containerd/containerd/blob/v1.3.2/runtime/v2/runc/options/oci.pb.go#L26 |  | ||||||
| 	if c.config.NoPivot && runtimeType == plugin.RuntimeLinuxV1 { |  | ||||||
| 		taskOpts = append(taskOpts, containerd.WithNoPivotRoot) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return taskOpts |  | ||||||
| } |  | ||||||
| @@ -1,28 +0,0 @@ | |||||||
| //go:build !windows && !linux |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|    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 sbserver |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/containerd/containerd" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // taskOpts generates task options for a (sandbox) container. |  | ||||||
| func (c *criService) taskOpts(runtimeType string) []containerd.NewTaskOpts { |  | ||||||
| 	return []containerd.NewTaskOpts{} |  | ||||||
| } |  | ||||||
| @@ -1,26 +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 sbserver |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/containerd/containerd" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // No task options needed for windows. |  | ||||||
| func (c *criService) taskOpts(runtimeType string) []containerd.NewTaskOpts { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -110,17 +110,12 @@ func (c *criService) StartContainer(ctx context.Context, r *runtime.StartContain | |||||||
| 		return cntr.IO, nil | 		return cntr.IO, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ctrInfo, err := container.Info(ctx) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("failed to get container info: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ociRuntime, err := c.getSandboxRuntime(sandbox.Config, sandbox.Metadata.RuntimeHandler) | 	ociRuntime, err := c.getSandboxRuntime(sandbox.Config, sandbox.Metadata.RuntimeHandler) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("failed to get sandbox runtime: %w", err) | 		return nil, fmt.Errorf("failed to get sandbox runtime: %w", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	taskOpts := c.taskOpts(ctrInfo.Runtime.Name) | 	var taskOpts []containerd.NewTaskOpts | ||||||
| 	if ociRuntime.Path != "" { | 	if ociRuntime.Path != "" { | ||||||
| 		taskOpts = append(taskOpts, containerd.WithRuntimePath(ociRuntime.Path)) | 		taskOpts = append(taskOpts, containerd.WithRuntimePath(ociRuntime.Path)) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -37,7 +37,6 @@ import ( | |||||||
| 	runtimeoptions "github.com/containerd/containerd/pkg/runtimeoptions/v1" | 	runtimeoptions "github.com/containerd/containerd/pkg/runtimeoptions/v1" | ||||||
| 	"github.com/containerd/containerd/plugin" | 	"github.com/containerd/containerd/plugin" | ||||||
| 	"github.com/containerd/containerd/reference/docker" | 	"github.com/containerd/containerd/reference/docker" | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" | 	runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
| 	"github.com/containerd/typeurl/v2" | 	"github.com/containerd/typeurl/v2" | ||||||
| 	runtimespec "github.com/opencontainers/runtime-spec/specs-go" | 	runtimespec "github.com/opencontainers/runtime-spec/specs-go" | ||||||
| @@ -338,15 +337,7 @@ func parseImageReferences(refs []string) ([]string, []string) { | |||||||
| // generateRuntimeOptions generates runtime options from cri plugin config. | // generateRuntimeOptions generates runtime options from cri plugin config. | ||||||
| func generateRuntimeOptions(r criconfig.Runtime, c criconfig.Config) (interface{}, error) { | func generateRuntimeOptions(r criconfig.Runtime, c criconfig.Config) (interface{}, error) { | ||||||
| 	if r.Options == nil { | 	if r.Options == nil { | ||||||
| 		if r.Type != plugin.RuntimeLinuxV1 { | 		return nil, nil | ||||||
| 			return nil, nil |  | ||||||
| 		} |  | ||||||
| 		// This is a legacy config, generate runctypes.RuncOptions. |  | ||||||
| 		return &runctypes.RuncOptions{ |  | ||||||
| 			Runtime:       r.Engine, |  | ||||||
| 			RuntimeRoot:   r.Root, |  | ||||||
| 			SystemdCgroup: c.SystemdCgroup, |  | ||||||
| 		}, nil |  | ||||||
| 	} | 	} | ||||||
| 	optionsTree, err := toml.TreeFromMap(r.Options) | 	optionsTree, err := toml.TreeFromMap(r.Options) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -372,12 +363,8 @@ func generateRuntimeOptions(r criconfig.Runtime, c criconfig.Config) (interface{ | |||||||
| // getRuntimeOptionsType gets empty runtime options by the runtime type name. | // getRuntimeOptionsType gets empty runtime options by the runtime type name. | ||||||
| func getRuntimeOptionsType(t string) interface{} { | func getRuntimeOptionsType(t string) interface{} { | ||||||
| 	switch t { | 	switch t { | ||||||
| 	case plugin.RuntimeRuncV1: |  | ||||||
| 		fallthrough |  | ||||||
| 	case plugin.RuntimeRuncV2: | 	case plugin.RuntimeRuncV2: | ||||||
| 		return &runcoptions.Options{} | 		return &runcoptions.Options{} | ||||||
| 	case plugin.RuntimeLinuxV1: |  | ||||||
| 		return &runctypes.RuncOptions{} |  | ||||||
| 	case runtimeRunhcsV1: | 	case runtimeRunhcsV1: | ||||||
| 		return &runhcsoptions.Options{} | 		return &runhcsoptions.Options{} | ||||||
| 	default: | 	default: | ||||||
|   | |||||||
| @@ -33,7 +33,6 @@ import ( | |||||||
| 	"github.com/containerd/containerd/plugin" | 	"github.com/containerd/containerd/plugin" | ||||||
| 	"github.com/containerd/containerd/protobuf/types" | 	"github.com/containerd/containerd/protobuf/types" | ||||||
| 	"github.com/containerd/containerd/reference/docker" | 	"github.com/containerd/containerd/reference/docker" | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" | 	runcoptions "github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
| 	"github.com/containerd/typeurl/v2" | 	"github.com/containerd/typeurl/v2" | ||||||
|  |  | ||||||
| @@ -206,29 +205,19 @@ func TestLocalResolve(t *testing.T) { | |||||||
|  |  | ||||||
| func TestGenerateRuntimeOptions(t *testing.T) { | func TestGenerateRuntimeOptions(t *testing.T) { | ||||||
| 	nilOpts := ` | 	nilOpts := ` | ||||||
| systemd_cgroup = true |  | ||||||
| [containerd] | [containerd] | ||||||
|   no_pivot = true |   no_pivot = true | ||||||
|   default_runtime_name = "default" |   default_runtime_name = "default" | ||||||
| [containerd.runtimes.legacy] |  | ||||||
|   runtime_type = "` + plugin.RuntimeLinuxV1 + `" |  | ||||||
| [containerd.runtimes.runc] |  | ||||||
|   runtime_type = "` + plugin.RuntimeRuncV1 + `" |  | ||||||
| [containerd.runtimes.runcv2] | [containerd.runtimes.runcv2] | ||||||
|   runtime_type = "` + plugin.RuntimeRuncV2 + `" |   runtime_type = "` + plugin.RuntimeRuncV2 + `" | ||||||
| ` | ` | ||||||
| 	nonNilOpts := ` | 	nonNilOpts := ` | ||||||
| systemd_cgroup = true |  | ||||||
| [containerd] | [containerd] | ||||||
|   no_pivot = true |   no_pivot = true | ||||||
|   default_runtime_name = "default" |   default_runtime_name = "default" | ||||||
| [containerd.runtimes.legacy] |  | ||||||
|   runtime_type = "` + plugin.RuntimeLinuxV1 + `" |  | ||||||
| [containerd.runtimes.legacy.options] | [containerd.runtimes.legacy.options] | ||||||
|   Runtime = "legacy" |   Runtime = "legacy" | ||||||
|   RuntimeRoot = "/legacy" |   RuntimeRoot = "/legacy" | ||||||
| [containerd.runtimes.runc] |  | ||||||
|   runtime_type = "` + plugin.RuntimeRuncV1 + `" |  | ||||||
| [containerd.runtimes.runc.options] | [containerd.runtimes.runc.options] | ||||||
|   BinaryName = "runc" |   BinaryName = "runc" | ||||||
|   Root = "/runc" |   Root = "/runc" | ||||||
| @@ -245,7 +234,7 @@ systemd_cgroup = true | |||||||
| 	require.NoError(t, err) | 	require.NoError(t, err) | ||||||
| 	err = tree.Unmarshal(&nilOptsConfig) | 	err = tree.Unmarshal(&nilOptsConfig) | ||||||
| 	require.NoError(t, err) | 	require.NoError(t, err) | ||||||
| 	require.Len(t, nilOptsConfig.Runtimes, 3) | 	require.Len(t, nilOptsConfig.Runtimes, 1) | ||||||
|  |  | ||||||
| 	tree, err = toml.Load(nonNilOpts) | 	tree, err = toml.Load(nonNilOpts) | ||||||
| 	require.NoError(t, err) | 	require.NoError(t, err) | ||||||
| @@ -258,32 +247,11 @@ systemd_cgroup = true | |||||||
| 		c               criconfig.Config | 		c               criconfig.Config | ||||||
| 		expectedOptions interface{} | 		expectedOptions interface{} | ||||||
| 	}{ | 	}{ | ||||||
| 		"when options is nil, should return nil option for io.containerd.runc.v1": { |  | ||||||
| 			r:               nilOptsConfig.Runtimes["runc"], |  | ||||||
| 			c:               nilOptsConfig, |  | ||||||
| 			expectedOptions: nil, |  | ||||||
| 		}, |  | ||||||
| 		"when options is nil, should return nil option for io.containerd.runc.v2": { | 		"when options is nil, should return nil option for io.containerd.runc.v2": { | ||||||
| 			r:               nilOptsConfig.Runtimes["runcv2"], | 			r:               nilOptsConfig.Runtimes["runcv2"], | ||||||
| 			c:               nilOptsConfig, | 			c:               nilOptsConfig, | ||||||
| 			expectedOptions: nil, | 			expectedOptions: nil, | ||||||
| 		}, | 		}, | ||||||
| 		"when options is nil, should use legacy fields for legacy runtime": { |  | ||||||
| 			r: nilOptsConfig.Runtimes["legacy"], |  | ||||||
| 			c: nilOptsConfig, |  | ||||||
| 			expectedOptions: &runctypes.RuncOptions{ |  | ||||||
| 				SystemdCgroup: true, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		"when options is not nil, should be able to decode for io.containerd.runc.v1": { |  | ||||||
| 			r: nonNilOptsConfig.Runtimes["runc"], |  | ||||||
| 			c: nonNilOptsConfig, |  | ||||||
| 			expectedOptions: &runcoptions.Options{ |  | ||||||
| 				BinaryName:   "runc", |  | ||||||
| 				Root:         "/runc", |  | ||||||
| 				NoNewKeyring: true, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		"when options is not nil, should be able to decode for io.containerd.runc.v2": { | 		"when options is not nil, should be able to decode for io.containerd.runc.v2": { | ||||||
| 			r: nonNilOptsConfig.Runtimes["runcv2"], | 			r: nonNilOptsConfig.Runtimes["runcv2"], | ||||||
| 			c: nonNilOptsConfig, | 			c: nonNilOptsConfig, | ||||||
| @@ -293,14 +261,6 @@ systemd_cgroup = true | |||||||
| 				NoNewKeyring: true, | 				NoNewKeyring: true, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		"when options is not nil, should be able to decode for legacy runtime": { |  | ||||||
| 			r: nonNilOptsConfig.Runtimes["legacy"], |  | ||||||
| 			c: nonNilOptsConfig, |  | ||||||
| 			expectedOptions: &runctypes.RuncOptions{ |  | ||||||
| 				Runtime:     "legacy", |  | ||||||
| 				RuntimeRoot: "/legacy", |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 	} { | 	} { | ||||||
| 		t.Run(desc, func(t *testing.T) { | 		t.Run(desc, func(t *testing.T) { | ||||||
| 			opts, err := generateRuntimeOptions(test.r, test.c) | 			opts, err := generateRuntimeOptions(test.r, test.c) | ||||||
|   | |||||||
| @@ -352,7 +352,7 @@ func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox | |||||||
| 	log.G(ctx).Tracef("Create sandbox container (id=%q, name=%q).", | 	log.G(ctx).Tracef("Create sandbox container (id=%q, name=%q).", | ||||||
| 		id, name) | 		id, name) | ||||||
|  |  | ||||||
| 	taskOpts := c.taskOpts(ociRuntime.Type) | 	var taskOpts []containerd.NewTaskOpts | ||||||
| 	if ociRuntime.Path != "" { | 	if ociRuntime.Path != "" { | ||||||
| 		taskOpts = append(taskOpts, containerd.WithRuntimePath(ociRuntime.Path)) | 		taskOpts = append(taskOpts, containerd.WithRuntimePath(ociRuntime.Path)) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -22,9 +22,7 @@ import ( | |||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd" |  | ||||||
| 	"github.com/containerd/containerd/oci" | 	"github.com/containerd/containerd/oci" | ||||||
| 	"github.com/containerd/containerd/plugin" |  | ||||||
| 	"github.com/containerd/containerd/snapshots" | 	"github.com/containerd/containerd/snapshots" | ||||||
| 	imagespec "github.com/opencontainers/image-spec/specs-go/v1" | 	imagespec "github.com/opencontainers/image-spec/specs-go/v1" | ||||||
| 	runtimespec "github.com/opencontainers/runtime-spec/specs-go" | 	runtimespec "github.com/opencontainers/runtime-spec/specs-go" | ||||||
| @@ -344,22 +342,6 @@ func (c *criService) cleanupSandboxFiles(id string, config *runtime.PodSandboxCo | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // taskOpts generates task options for a (sandbox) container. |  | ||||||
| func (c *criService) taskOpts(runtimeType string) []containerd.NewTaskOpts { |  | ||||||
| 	// TODO(random-liu): Remove this after shim v1 is deprecated. |  | ||||||
| 	var taskOpts []containerd.NewTaskOpts |  | ||||||
|  |  | ||||||
| 	// c.config.NoPivot is only supported for RuntimeLinuxV1 = "io.containerd.runtime.v1.linux" legacy linux runtime |  | ||||||
| 	// and is not supported for RuntimeRuncV1 = "io.containerd.runc.v1" or  RuntimeRuncV2 = "io.containerd.runc.v2" |  | ||||||
| 	// for RuncV1/2 no pivot is set under the containerd.runtimes.runc.options config see |  | ||||||
| 	// https://github.com/containerd/containerd/blob/v1.3.2/runtime/v2/runc/options/oci.pb.go#L26 |  | ||||||
| 	if c.config.NoPivot && runtimeType == plugin.RuntimeLinuxV1 { |  | ||||||
| 		taskOpts = append(taskOpts, containerd.WithNoPivotRoot) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return taskOpts |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *criService) updateNetNamespacePath(spec *runtimespec.Spec, nsPath string) { | func (c *criService) updateNetNamespacePath(spec *runtimespec.Spec, nsPath string) { | ||||||
| 	for i := range spec.Linux.Namespaces { | 	for i := range spec.Linux.Namespaces { | ||||||
| 		if spec.Linux.Namespaces[i].Type == runtimespec.NetworkNamespace { | 		if spec.Linux.Namespaces[i].Type == runtimespec.NetworkNamespace { | ||||||
|   | |||||||
| @@ -19,7 +19,6 @@ | |||||||
| package server | package server | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/containerd/containerd" |  | ||||||
| 	"github.com/containerd/containerd/oci" | 	"github.com/containerd/containerd/oci" | ||||||
| 	"github.com/containerd/containerd/pkg/cri/annotations" | 	"github.com/containerd/containerd/pkg/cri/annotations" | ||||||
| 	"github.com/containerd/containerd/snapshots" | 	"github.com/containerd/containerd/snapshots" | ||||||
| @@ -51,11 +50,6 @@ func (c *criService) cleanupSandboxFiles(id string, config *runtime.PodSandboxCo | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // taskOpts generates task options for a (sandbox) container. |  | ||||||
| func (c *criService) taskOpts(runtimeType string) []containerd.NewTaskOpts { |  | ||||||
| 	return []containerd.NewTaskOpts{} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *criService) updateNetNamespacePath(spec *runtimespec.Spec, nsPath string) { | func (c *criService) updateNetNamespacePath(spec *runtimespec.Spec, nsPath string) { | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -29,8 +29,6 @@ import ( | |||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| 	runtime "k8s.io/cri-api/pkg/apis/runtime/v1" | 	runtime "k8s.io/cri-api/pkg/apis/runtime/v1" | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/pkg/cri/annotations" |  | ||||||
| 	criconfig "github.com/containerd/containerd/pkg/cri/config" |  | ||||||
| 	sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" | 	sandboxstore "github.com/containerd/containerd/pkg/cri/store/sandbox" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -361,166 +359,3 @@ func TestHostAccessingSandbox(t *testing.T) { | |||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestGetSandboxRuntime(t *testing.T) { |  | ||||||
| 	untrustedWorkloadRuntime := criconfig.Runtime{ |  | ||||||
| 		Type:   "io.containerd.runtime.v1.linux", |  | ||||||
| 		Engine: "untrusted-workload-runtime", |  | ||||||
| 		Root:   "", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	defaultRuntime := criconfig.Runtime{ |  | ||||||
| 		Type:   "io.containerd.runtime.v1.linux", |  | ||||||
| 		Engine: "default-runtime", |  | ||||||
| 		Root:   "", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	fooRuntime := criconfig.Runtime{ |  | ||||||
| 		Type:   "io.containerd.runtime.v1.linux", |  | ||||||
| 		Engine: "foo-bar", |  | ||||||
| 		Root:   "", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for desc, test := range map[string]struct { |  | ||||||
| 		sandboxConfig   *runtime.PodSandboxConfig |  | ||||||
| 		runtimeHandler  string |  | ||||||
| 		runtimes        map[string]criconfig.Runtime |  | ||||||
| 		expectErr       bool |  | ||||||
| 		expectedRuntime criconfig.Runtime |  | ||||||
| 	}{ |  | ||||||
| 		"should return error if untrusted workload requires host access": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Linux: &runtime.LinuxPodSandboxConfig{ |  | ||||||
| 					SecurityContext: &runtime.LinuxSandboxSecurityContext{ |  | ||||||
| 						Privileged: false, |  | ||||||
| 						NamespaceOptions: &runtime.NamespaceOption{ |  | ||||||
| 							Network: runtime.NamespaceMode_NODE, |  | ||||||
| 							Pid:     runtime.NamespaceMode_NODE, |  | ||||||
| 							Ipc:     runtime.NamespaceMode_NODE, |  | ||||||
| 						}, |  | ||||||
| 					}, |  | ||||||
| 				}, |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "true", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectErr: true, |  | ||||||
| 		}, |  | ||||||
| 		"should use untrusted workload runtime for untrusted workload": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "true", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectedRuntime: untrustedWorkloadRuntime, |  | ||||||
| 		}, |  | ||||||
| 		"should use default runtime for regular workload": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{}, |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault: defaultRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectedRuntime: defaultRuntime, |  | ||||||
| 		}, |  | ||||||
| 		"should use default runtime for trusted workload": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "false", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectedRuntime: defaultRuntime, |  | ||||||
| 		}, |  | ||||||
| 		"should return error if untrusted workload runtime is required but not configured": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "true", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault: defaultRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectErr: true, |  | ||||||
| 		}, |  | ||||||
| 		"should use 'untrusted' runtime for untrusted workload": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "true", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectedRuntime: untrustedWorkloadRuntime, |  | ||||||
| 		}, |  | ||||||
| 		"should use 'untrusted' runtime for untrusted workload & handler": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "true", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimeHandler: "untrusted", |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectedRuntime: untrustedWorkloadRuntime, |  | ||||||
| 		}, |  | ||||||
| 		"should return an error if untrusted annotation with conflicting handler": { |  | ||||||
| 			sandboxConfig: &runtime.PodSandboxConfig{ |  | ||||||
| 				Annotations: map[string]string{ |  | ||||||
| 					annotations.UntrustedWorkload: "true", |  | ||||||
| 				}, |  | ||||||
| 			}, |  | ||||||
| 			runtimeHandler: "foo", |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 				"foo":                      fooRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectErr: true, |  | ||||||
| 		}, |  | ||||||
| 		"should use correct runtime for a runtime handler": { |  | ||||||
| 			sandboxConfig:  &runtime.PodSandboxConfig{}, |  | ||||||
| 			runtimeHandler: "foo", |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault:   defaultRuntime, |  | ||||||
| 				criconfig.RuntimeUntrusted: untrustedWorkloadRuntime, |  | ||||||
| 				"foo":                      fooRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectedRuntime: fooRuntime, |  | ||||||
| 		}, |  | ||||||
| 		"should return error if runtime handler is required but not configured": { |  | ||||||
| 			sandboxConfig:  &runtime.PodSandboxConfig{}, |  | ||||||
| 			runtimeHandler: "bar", |  | ||||||
| 			runtimes: map[string]criconfig.Runtime{ |  | ||||||
| 				criconfig.RuntimeDefault: defaultRuntime, |  | ||||||
| 				"foo":                    fooRuntime, |  | ||||||
| 			}, |  | ||||||
| 			expectErr: true, |  | ||||||
| 		}, |  | ||||||
| 	} { |  | ||||||
| 		t.Run(desc, func(t *testing.T) { |  | ||||||
| 			cri := newTestCRIService() |  | ||||||
| 			cri.config = criconfig.Config{ |  | ||||||
| 				PluginConfig: criconfig.DefaultConfig(), |  | ||||||
| 			} |  | ||||||
| 			cri.config.ContainerdConfig.DefaultRuntimeName = criconfig.RuntimeDefault |  | ||||||
| 			cri.config.ContainerdConfig.Runtimes = test.runtimes |  | ||||||
| 			r, err := cri.getSandboxRuntime(test.sandboxConfig, test.runtimeHandler) |  | ||||||
| 			assert.Equal(t, test.expectErr, err != nil) |  | ||||||
| 			assert.Equal(t, test.expectedRuntime, r) |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -20,7 +20,6 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"strconv" | 	"strconv" | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd" |  | ||||||
| 	"github.com/containerd/containerd/oci" | 	"github.com/containerd/containerd/oci" | ||||||
| 	"github.com/containerd/containerd/snapshots" | 	"github.com/containerd/containerd/snapshots" | ||||||
| 	imagespec "github.com/opencontainers/image-spec/specs-go/v1" | 	imagespec "github.com/opencontainers/image-spec/specs-go/v1" | ||||||
| @@ -104,11 +103,6 @@ func (c *criService) cleanupSandboxFiles(id string, config *runtime.PodSandboxCo | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // No task options needed for windows. |  | ||||||
| func (c *criService) taskOpts(runtimeType string) []containerd.NewTaskOpts { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *criService) updateNetNamespacePath(spec *runtimespec.Spec, nsPath string) { | func (c *criService) updateNetNamespacePath(spec *runtimespec.Spec, nsPath string) { | ||||||
| 	spec.Windows.Network.NetworkNamespace = nsPath | 	spec.Windows.Network.NetworkNamespace = nsPath | ||||||
| } | } | ||||||
|   | |||||||
| @@ -93,10 +93,6 @@ const ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | 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 is the runc runtime that supports multiple containers per shim | ||||||
| 	RuntimeRuncV2 = "io.containerd.runc.v2" | 	RuntimeRuncV2 = "io.containerd.runc.v2" | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -1,183 +0,0 @@ | |||||||
| file { |  | ||||||
|   name: "github.com/containerd/containerd/linux/runctypes/runc.proto" |  | ||||||
|   package: "containerd.linux.runc" |  | ||||||
|   dependency: "gogoproto/gogo.proto" |  | ||||||
|   message_type { |  | ||||||
|     name: "RuncOptions" |  | ||||||
|     field { |  | ||||||
|       name: "runtime" |  | ||||||
|       number: 1 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_STRING |  | ||||||
|       json_name: "runtime" |  | ||||||
|     } |  | ||||||
|     field { |  | ||||||
|       name: "runtime_root" |  | ||||||
|       number: 2 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_STRING |  | ||||||
|       json_name: "runtimeRoot" |  | ||||||
|     } |  | ||||||
|     field { |  | ||||||
|       name: "criu_path" |  | ||||||
|       number: 3 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_STRING |  | ||||||
|       json_name: "criuPath" |  | ||||||
|     } |  | ||||||
|     field { |  | ||||||
|       name: "systemd_cgroup" |  | ||||||
|       number: 4 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_BOOL |  | ||||||
|       json_name: "systemdCgroup" |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   message_type { |  | ||||||
|     name: "CreateOptions" |  | ||||||
|     field { |  | ||||||
|       name: "no_pivot_root" |  | ||||||
|       number: 1 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_BOOL |  | ||||||
|       json_name: "noPivotRoot" |  | ||||||
|     } |  | ||||||
|     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: "no_new_keyring" |  | ||||||
|       number: 8 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_BOOL |  | ||||||
|       json_name: "noNewKeyring" |  | ||||||
|     } |  | ||||||
|     field { |  | ||||||
|       name: "shim_cgroup" |  | ||||||
|       number: 9 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_STRING |  | ||||||
|       json_name: "shimCgroup" |  | ||||||
|     } |  | ||||||
|     field { |  | ||||||
|       name: "io_uid" |  | ||||||
|       number: 10 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_UINT32 |  | ||||||
|       json_name: "ioUid" |  | ||||||
|     } |  | ||||||
|     field { |  | ||||||
|       name: "io_gid" |  | ||||||
|       number: 11 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_UINT32 |  | ||||||
|       json_name: "ioGid" |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   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" |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   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/linux/runctypes;runctypes" |  | ||||||
|   } |  | ||||||
|   weak_dependency: 0 |  | ||||||
|   syntax: "proto3" |  | ||||||
| } |  | ||||||
| @@ -1,17 +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 runctypes |  | ||||||
| @@ -1,212 +0,0 @@ | |||||||
| file { |  | ||||||
|   name: "github.com/containerd/containerd/runtime/linux/runctypes/runc.proto" |  | ||||||
|   package: "containerd.linux.runc" |  | ||||||
|   message_type { |  | ||||||
|     name: "RuncOptions" |  | ||||||
|     field { |  | ||||||
|       name: "runtime" |  | ||||||
|       number: 1 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_STRING |  | ||||||
|       json_name: "runtime" |  | ||||||
|     } |  | ||||||
|     field { |  | ||||||
|       name: "runtime_root" |  | ||||||
|       number: 2 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_STRING |  | ||||||
|       json_name: "runtimeRoot" |  | ||||||
|     } |  | ||||||
|     field { |  | ||||||
|       name: "criu_path" |  | ||||||
|       number: 3 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_STRING |  | ||||||
|       options { |  | ||||||
|         deprecated: true |  | ||||||
|       } |  | ||||||
|       json_name: "criuPath" |  | ||||||
|     } |  | ||||||
|     field { |  | ||||||
|       name: "systemd_cgroup" |  | ||||||
|       number: 4 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_BOOL |  | ||||||
|       json_name: "systemdCgroup" |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   message_type { |  | ||||||
|     name: "CreateOptions" |  | ||||||
|     field { |  | ||||||
|       name: "no_pivot_root" |  | ||||||
|       number: 1 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_BOOL |  | ||||||
|       json_name: "noPivotRoot" |  | ||||||
|     } |  | ||||||
|     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: "no_new_keyring" |  | ||||||
|       number: 8 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_BOOL |  | ||||||
|       json_name: "noNewKeyring" |  | ||||||
|     } |  | ||||||
|     field { |  | ||||||
|       name: "shim_cgroup" |  | ||||||
|       number: 9 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_STRING |  | ||||||
|       json_name: "shimCgroup" |  | ||||||
|     } |  | ||||||
|     field { |  | ||||||
|       name: "io_uid" |  | ||||||
|       number: 10 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_UINT32 |  | ||||||
|       json_name: "ioUid" |  | ||||||
|     } |  | ||||||
|     field { |  | ||||||
|       name: "io_gid" |  | ||||||
|       number: 11 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       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" |  | ||||||
|     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: "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" |  | ||||||
|     field { |  | ||||||
|       name: "exec_id" |  | ||||||
|       number: 1 |  | ||||||
|       label: LABEL_OPTIONAL |  | ||||||
|       type: TYPE_STRING |  | ||||||
|       json_name: "execId" |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   options { |  | ||||||
|     go_package: "github.com/containerd/containerd/runtime/linux/runctypes;runctypes" |  | ||||||
|   } |  | ||||||
|   syntax: "proto3" |  | ||||||
| } |  | ||||||
| @@ -1,581 +0,0 @@ | |||||||
| // Code generated by protoc-gen-go. DO NOT EDIT. |  | ||||||
| // versions: |  | ||||||
| // 	protoc-gen-go v1.28.1 |  | ||||||
| // 	protoc        v3.20.1 |  | ||||||
| // source: github.com/containerd/containerd/runtime/linux/runctypes/runc.proto |  | ||||||
|  |  | ||||||
| package runctypes |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	protoreflect "google.golang.org/protobuf/reflect/protoreflect" |  | ||||||
| 	protoimpl "google.golang.org/protobuf/runtime/protoimpl" |  | ||||||
| 	reflect "reflect" |  | ||||||
| 	sync "sync" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	// Verify that this generated code is sufficiently up-to-date. |  | ||||||
| 	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) |  | ||||||
| 	// Verify that runtime/protoimpl is sufficiently up-to-date. |  | ||||||
| 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type RuncOptions struct { |  | ||||||
| 	state         protoimpl.MessageState |  | ||||||
| 	sizeCache     protoimpl.SizeCache |  | ||||||
| 	unknownFields protoimpl.UnknownFields |  | ||||||
|  |  | ||||||
| 	Runtime     string `protobuf:"bytes,1,opt,name=runtime,proto3" json:"runtime,omitempty"` |  | ||||||
| 	RuntimeRoot string `protobuf:"bytes,2,opt,name=runtime_root,json=runtimeRoot,proto3" json:"runtime_root,omitempty"` |  | ||||||
| 	// criu binary path. |  | ||||||
| 	// |  | ||||||
| 	// Deprecated: runc option --criu is now ignored (with a warning), and the |  | ||||||
| 	// option will be removed entirely in a future release. Users who need a non- |  | ||||||
| 	// standard criu binary should rely on the standard way of looking up binaries |  | ||||||
| 	// in $PATH. |  | ||||||
| 	// |  | ||||||
| 	// Deprecated: Do not use. |  | ||||||
| 	CriuPath      string `protobuf:"bytes,3,opt,name=criu_path,json=criuPath,proto3" json:"criu_path,omitempty"` |  | ||||||
| 	SystemdCgroup bool   `protobuf:"varint,4,opt,name=systemd_cgroup,json=systemdCgroup,proto3" json:"systemd_cgroup,omitempty"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *RuncOptions) Reset() { |  | ||||||
| 	*x = RuncOptions{} |  | ||||||
| 	if protoimpl.UnsafeEnabled { |  | ||||||
| 		mi := &file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes[0] |  | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |  | ||||||
| 		ms.StoreMessageInfo(mi) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *RuncOptions) String() string { |  | ||||||
| 	return protoimpl.X.MessageStringOf(x) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (*RuncOptions) ProtoMessage() {} |  | ||||||
|  |  | ||||||
| func (x *RuncOptions) ProtoReflect() protoreflect.Message { |  | ||||||
| 	mi := &file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes[0] |  | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { |  | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |  | ||||||
| 		if ms.LoadMessageInfo() == nil { |  | ||||||
| 			ms.StoreMessageInfo(mi) |  | ||||||
| 		} |  | ||||||
| 		return ms |  | ||||||
| 	} |  | ||||||
| 	return mi.MessageOf(x) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Deprecated: Use RuncOptions.ProtoReflect.Descriptor instead. |  | ||||||
| func (*RuncOptions) Descriptor() ([]byte, []int) { |  | ||||||
| 	return file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDescGZIP(), []int{0} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *RuncOptions) GetRuntime() string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.Runtime |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *RuncOptions) GetRuntimeRoot() string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.RuntimeRoot |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Deprecated: Do not use. |  | ||||||
| func (x *RuncOptions) GetCriuPath() string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.CriuPath |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *RuncOptions) GetSystemdCgroup() bool { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.SystemdCgroup |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type CreateOptions struct { |  | ||||||
| 	state         protoimpl.MessageState |  | ||||||
| 	sizeCache     protoimpl.SizeCache |  | ||||||
| 	unknownFields protoimpl.UnknownFields |  | ||||||
|  |  | ||||||
| 	NoPivotRoot         bool     `protobuf:"varint,1,opt,name=no_pivot_root,json=noPivotRoot,proto3" json:"no_pivot_root,omitempty"` |  | ||||||
| 	OpenTcp             bool     `protobuf:"varint,2,opt,name=open_tcp,json=openTcp,proto3" json:"open_tcp,omitempty"` |  | ||||||
| 	ExternalUnixSockets bool     `protobuf:"varint,3,opt,name=external_unix_sockets,json=externalUnixSockets,proto3" json:"external_unix_sockets,omitempty"` |  | ||||||
| 	Terminal            bool     `protobuf:"varint,4,opt,name=terminal,proto3" json:"terminal,omitempty"` |  | ||||||
| 	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,proto3" json:"empty_namespaces,omitempty"` |  | ||||||
| 	CgroupsMode         string   `protobuf:"bytes,7,opt,name=cgroups_mode,json=cgroupsMode,proto3" json:"cgroups_mode,omitempty"` |  | ||||||
| 	NoNewKeyring        bool     `protobuf:"varint,8,opt,name=no_new_keyring,json=noNewKeyring,proto3" json:"no_new_keyring,omitempty"` |  | ||||||
| 	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 (x *CreateOptions) Reset() { |  | ||||||
| 	*x = CreateOptions{} |  | ||||||
| 	if protoimpl.UnsafeEnabled { |  | ||||||
| 		mi := &file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes[1] |  | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |  | ||||||
| 		ms.StoreMessageInfo(mi) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) String() string { |  | ||||||
| 	return protoimpl.X.MessageStringOf(x) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (*CreateOptions) ProtoMessage() {} |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) ProtoReflect() protoreflect.Message { |  | ||||||
| 	mi := &file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes[1] |  | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { |  | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |  | ||||||
| 		if ms.LoadMessageInfo() == nil { |  | ||||||
| 			ms.StoreMessageInfo(mi) |  | ||||||
| 		} |  | ||||||
| 		return ms |  | ||||||
| 	} |  | ||||||
| 	return mi.MessageOf(x) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Deprecated: Use CreateOptions.ProtoReflect.Descriptor instead. |  | ||||||
| func (*CreateOptions) Descriptor() ([]byte, []int) { |  | ||||||
| 	return file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDescGZIP(), []int{1} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetNoPivotRoot() bool { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.NoPivotRoot |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetOpenTcp() bool { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.OpenTcp |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetExternalUnixSockets() bool { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.ExternalUnixSockets |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetTerminal() bool { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.Terminal |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetFileLocks() bool { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.FileLocks |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetEmptyNamespaces() []string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.EmptyNamespaces |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetCgroupsMode() string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.CgroupsMode |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetNoNewKeyring() bool { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.NoNewKeyring |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetShimCgroup() string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.ShimCgroup |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetIoUid() uint32 { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.IoUid |  | ||||||
| 	} |  | ||||||
| 	return 0 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetIoGid() uint32 { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.IoGid |  | ||||||
| 	} |  | ||||||
| 	return 0 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetCriuWorkPath() string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.CriuWorkPath |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CreateOptions) GetCriuImagePath() string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.CriuImagePath |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type CheckpointOptions struct { |  | ||||||
| 	state         protoimpl.MessageState |  | ||||||
| 	sizeCache     protoimpl.SizeCache |  | ||||||
| 	unknownFields protoimpl.UnknownFields |  | ||||||
|  |  | ||||||
| 	Exit                bool     `protobuf:"varint,1,opt,name=exit,proto3" json:"exit,omitempty"` |  | ||||||
| 	OpenTcp             bool     `protobuf:"varint,2,opt,name=open_tcp,json=openTcp,proto3" json:"open_tcp,omitempty"` |  | ||||||
| 	ExternalUnixSockets bool     `protobuf:"varint,3,opt,name=external_unix_sockets,json=externalUnixSockets,proto3" json:"external_unix_sockets,omitempty"` |  | ||||||
| 	Terminal            bool     `protobuf:"varint,4,opt,name=terminal,proto3" json:"terminal,omitempty"` |  | ||||||
| 	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,proto3" 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 (x *CheckpointOptions) Reset() { |  | ||||||
| 	*x = CheckpointOptions{} |  | ||||||
| 	if protoimpl.UnsafeEnabled { |  | ||||||
| 		mi := &file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes[2] |  | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |  | ||||||
| 		ms.StoreMessageInfo(mi) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CheckpointOptions) String() string { |  | ||||||
| 	return protoimpl.X.MessageStringOf(x) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (*CheckpointOptions) ProtoMessage() {} |  | ||||||
|  |  | ||||||
| func (x *CheckpointOptions) ProtoReflect() protoreflect.Message { |  | ||||||
| 	mi := &file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes[2] |  | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { |  | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |  | ||||||
| 		if ms.LoadMessageInfo() == nil { |  | ||||||
| 			ms.StoreMessageInfo(mi) |  | ||||||
| 		} |  | ||||||
| 		return ms |  | ||||||
| 	} |  | ||||||
| 	return mi.MessageOf(x) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Deprecated: Use CheckpointOptions.ProtoReflect.Descriptor instead. |  | ||||||
| func (*CheckpointOptions) Descriptor() ([]byte, []int) { |  | ||||||
| 	return file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDescGZIP(), []int{2} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CheckpointOptions) GetExit() bool { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.Exit |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CheckpointOptions) GetOpenTcp() bool { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.OpenTcp |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CheckpointOptions) GetExternalUnixSockets() bool { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.ExternalUnixSockets |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CheckpointOptions) GetTerminal() bool { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.Terminal |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CheckpointOptions) GetFileLocks() bool { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.FileLocks |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CheckpointOptions) GetEmptyNamespaces() []string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.EmptyNamespaces |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CheckpointOptions) GetCgroupsMode() string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.CgroupsMode |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CheckpointOptions) GetWorkPath() string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.WorkPath |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *CheckpointOptions) GetImagePath() string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.ImagePath |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type ProcessDetails struct { |  | ||||||
| 	state         protoimpl.MessageState |  | ||||||
| 	sizeCache     protoimpl.SizeCache |  | ||||||
| 	unknownFields protoimpl.UnknownFields |  | ||||||
|  |  | ||||||
| 	ExecID string `protobuf:"bytes,1,opt,name=exec_id,json=execId,proto3" json:"exec_id,omitempty"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *ProcessDetails) Reset() { |  | ||||||
| 	*x = ProcessDetails{} |  | ||||||
| 	if protoimpl.UnsafeEnabled { |  | ||||||
| 		mi := &file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes[3] |  | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |  | ||||||
| 		ms.StoreMessageInfo(mi) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *ProcessDetails) String() string { |  | ||||||
| 	return protoimpl.X.MessageStringOf(x) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (*ProcessDetails) ProtoMessage() {} |  | ||||||
|  |  | ||||||
| func (x *ProcessDetails) ProtoReflect() protoreflect.Message { |  | ||||||
| 	mi := &file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes[3] |  | ||||||
| 	if protoimpl.UnsafeEnabled && x != nil { |  | ||||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) |  | ||||||
| 		if ms.LoadMessageInfo() == nil { |  | ||||||
| 			ms.StoreMessageInfo(mi) |  | ||||||
| 		} |  | ||||||
| 		return ms |  | ||||||
| 	} |  | ||||||
| 	return mi.MessageOf(x) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Deprecated: Use ProcessDetails.ProtoReflect.Descriptor instead. |  | ||||||
| func (*ProcessDetails) Descriptor() ([]byte, []int) { |  | ||||||
| 	return file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDescGZIP(), []int{3} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *ProcessDetails) GetExecID() string { |  | ||||||
| 	if x != nil { |  | ||||||
| 		return x.ExecID |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var File_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto protoreflect.FileDescriptor |  | ||||||
|  |  | ||||||
| var file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDesc = []byte{ |  | ||||||
| 	0x0a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, |  | ||||||
| 	0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, |  | ||||||
| 	0x72, 0x64, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x6c, 0x69, 0x6e, 0x75, 0x78, |  | ||||||
| 	0x2f, 0x72, 0x75, 0x6e, 0x63, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x72, 0x75, 0x6e, 0x63, 0x2e, |  | ||||||
| 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x15, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, |  | ||||||
| 	0x64, 0x2e, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2e, 0x72, 0x75, 0x6e, 0x63, 0x22, 0x92, 0x01, 0x0a, |  | ||||||
| 	0x0b, 0x52, 0x75, 0x6e, 0x63, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x18, 0x0a, 0x07, |  | ||||||
| 	0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, |  | ||||||
| 	0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, |  | ||||||
| 	0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x75, |  | ||||||
| 	0x6e, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x1f, 0x0a, 0x09, 0x63, 0x72, 0x69, |  | ||||||
| 	0x75, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, |  | ||||||
| 	0x52, 0x08, 0x63, 0x72, 0x69, 0x75, 0x50, 0x61, 0x74, 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x79, |  | ||||||
| 	0x73, 0x74, 0x65, 0x6d, 0x64, 0x5f, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x04, 0x20, 0x01, |  | ||||||
| 	0x28, 0x08, 0x52, 0x0d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x64, 0x43, 0x67, 0x72, 0x6f, 0x75, |  | ||||||
| 	0x70, 0x22, 0xce, 0x03, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, |  | ||||||
| 	0x6f, 0x6e, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x5f, 0x70, 0x69, 0x76, 0x6f, 0x74, 0x5f, |  | ||||||
| 	0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x50, 0x69, |  | ||||||
| 	0x76, 0x6f, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x70, 0x65, 0x6e, 0x5f, |  | ||||||
| 	0x74, 0x63, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6f, 0x70, 0x65, 0x6e, 0x54, |  | ||||||
| 	0x63, 0x70, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x75, |  | ||||||
| 	0x6e, 0x69, 0x78, 0x5f, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, |  | ||||||
| 	0x08, 0x52, 0x13, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x55, 0x6e, 0x69, 0x78, 0x53, |  | ||||||
| 	0x6f, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, |  | ||||||
| 	0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, |  | ||||||
| 	0x61, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x6b, 0x73, |  | ||||||
| 	0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x6b, |  | ||||||
| 	0x73, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, |  | ||||||
| 	0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x65, 0x6d, 0x70, |  | ||||||
| 	0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, |  | ||||||
| 	0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, |  | ||||||
| 	0x28, 0x09, 0x52, 0x0b, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x12, |  | ||||||
| 	0x24, 0x0a, 0x0e, 0x6e, 0x6f, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x6b, 0x65, 0x79, 0x72, 0x69, 0x6e, |  | ||||||
| 	0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x6e, 0x6f, 0x4e, 0x65, 0x77, 0x4b, 0x65, |  | ||||||
| 	0x79, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x68, 0x69, 0x6d, 0x5f, 0x63, 0x67, |  | ||||||
| 	0x72, 0x6f, 0x75, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x68, 0x69, 0x6d, |  | ||||||
| 	0x43, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x15, 0x0a, 0x06, 0x69, 0x6f, 0x5f, 0x75, 0x69, 0x64, |  | ||||||
| 	0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6f, 0x55, 0x69, 0x64, 0x12, 0x15, 0x0a, |  | ||||||
| 	0x06, 0x69, 0x6f, 0x5f, 0x67, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, |  | ||||||
| 	0x6f, 0x47, 0x69, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x63, 0x72, 0x69, 0x75, 0x5f, 0x77, 0x6f, 0x72, |  | ||||||
| 	0x6b, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x72, |  | ||||||
| 	0x69, 0x75, 0x57, 0x6f, 0x72, 0x6b, 0x50, 0x61, 0x74, 0x68, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x72, |  | ||||||
| 	0x69, 0x75, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0d, 0x20, |  | ||||||
| 	0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x72, 0x69, 0x75, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x50, 0x61, |  | ||||||
| 	0x74, 0x68, 0x22, 0xbb, 0x02, 0x0a, 0x11, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, |  | ||||||
| 	0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78, 0x69, 0x74, |  | ||||||
| 	0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x65, 0x78, 0x69, 0x74, 0x12, 0x19, 0x0a, 0x08, |  | ||||||
| 	0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x74, 0x63, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, |  | ||||||
| 	0x6f, 0x70, 0x65, 0x6e, 0x54, 0x63, 0x70, 0x12, 0x32, 0x0a, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, |  | ||||||
| 	0x6e, 0x61, 0x6c, 0x5f, 0x75, 0x6e, 0x69, 0x78, 0x5f, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x73, |  | ||||||
| 	0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, |  | ||||||
| 	0x55, 0x6e, 0x69, 0x78, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x74, |  | ||||||
| 	0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, |  | ||||||
| 	0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x5f, |  | ||||||
| 	0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x66, 0x69, 0x6c, |  | ||||||
| 	0x65, 0x4c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, |  | ||||||
| 	0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, |  | ||||||
| 	0x52, 0x0f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, |  | ||||||
| 	0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x5f, 0x6d, 0x6f, 0x64, |  | ||||||
| 	0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, |  | ||||||
| 	0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x70, 0x61, 0x74, |  | ||||||
| 	0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x50, 0x61, 0x74, |  | ||||||
| 	0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, |  | ||||||
| 	0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x50, 0x61, 0x74, 0x68, |  | ||||||
| 	0x22, 0x29, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, |  | ||||||
| 	0x6c, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, |  | ||||||
| 	0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, 0x64, 0x42, 0x44, 0x5a, 0x42, 0x67, |  | ||||||
| 	0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, |  | ||||||
| 	0x6e, 0x65, 0x72, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2f, |  | ||||||
| 	0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2f, 0x72, 0x75, |  | ||||||
| 	0x6e, 0x63, 0x74, 0x79, 0x70, 0x65, 0x73, 0x3b, 0x72, 0x75, 0x6e, 0x63, 0x74, 0x79, 0x70, 0x65, |  | ||||||
| 	0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDescOnce sync.Once |  | ||||||
| 	file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDescData = file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDesc |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDescGZIP() []byte { |  | ||||||
| 	file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDescOnce.Do(func() { |  | ||||||
| 		file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDescData) |  | ||||||
| 	}) |  | ||||||
| 	return file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDescData |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes = make([]protoimpl.MessageInfo, 4) |  | ||||||
| var file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_goTypes = []interface{}{ |  | ||||||
| 	(*RuncOptions)(nil),       // 0: containerd.linux.runc.RuncOptions |  | ||||||
| 	(*CreateOptions)(nil),     // 1: containerd.linux.runc.CreateOptions |  | ||||||
| 	(*CheckpointOptions)(nil), // 2: containerd.linux.runc.CheckpointOptions |  | ||||||
| 	(*ProcessDetails)(nil),    // 3: containerd.linux.runc.ProcessDetails |  | ||||||
| } |  | ||||||
| var file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_depIdxs = []int32{ |  | ||||||
| 	0, // [0:0] is the sub-list for method output_type |  | ||||||
| 	0, // [0:0] is the sub-list for method input_type |  | ||||||
| 	0, // [0:0] is the sub-list for extension type_name |  | ||||||
| 	0, // [0:0] is the sub-list for extension extendee |  | ||||||
| 	0, // [0:0] is the sub-list for field type_name |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func init() { file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_init() } |  | ||||||
| func file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_init() { |  | ||||||
| 	if File_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if !protoimpl.UnsafeEnabled { |  | ||||||
| 		file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { |  | ||||||
| 			switch v := v.(*RuncOptions); i { |  | ||||||
| 			case 0: |  | ||||||
| 				return &v.state |  | ||||||
| 			case 1: |  | ||||||
| 				return &v.sizeCache |  | ||||||
| 			case 2: |  | ||||||
| 				return &v.unknownFields |  | ||||||
| 			default: |  | ||||||
| 				return nil |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { |  | ||||||
| 			switch v := v.(*CreateOptions); i { |  | ||||||
| 			case 0: |  | ||||||
| 				return &v.state |  | ||||||
| 			case 1: |  | ||||||
| 				return &v.sizeCache |  | ||||||
| 			case 2: |  | ||||||
| 				return &v.unknownFields |  | ||||||
| 			default: |  | ||||||
| 				return nil |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { |  | ||||||
| 			switch v := v.(*CheckpointOptions); i { |  | ||||||
| 			case 0: |  | ||||||
| 				return &v.state |  | ||||||
| 			case 1: |  | ||||||
| 				return &v.sizeCache |  | ||||||
| 			case 2: |  | ||||||
| 				return &v.unknownFields |  | ||||||
| 			default: |  | ||||||
| 				return nil |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { |  | ||||||
| 			switch v := v.(*ProcessDetails); i { |  | ||||||
| 			case 0: |  | ||||||
| 				return &v.state |  | ||||||
| 			case 1: |  | ||||||
| 				return &v.sizeCache |  | ||||||
| 			case 2: |  | ||||||
| 				return &v.unknownFields |  | ||||||
| 			default: |  | ||||||
| 				return nil |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	type x struct{} |  | ||||||
| 	out := protoimpl.TypeBuilder{ |  | ||||||
| 		File: protoimpl.DescBuilder{ |  | ||||||
| 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(), |  | ||||||
| 			RawDescriptor: file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDesc, |  | ||||||
| 			NumEnums:      0, |  | ||||||
| 			NumMessages:   4, |  | ||||||
| 			NumExtensions: 0, |  | ||||||
| 			NumServices:   0, |  | ||||||
| 		}, |  | ||||||
| 		GoTypes:           file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_goTypes, |  | ||||||
| 		DependencyIndexes: file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_depIdxs, |  | ||||||
| 		MessageInfos:      file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_msgTypes, |  | ||||||
| 	}.Build() |  | ||||||
| 	File_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto = out.File |  | ||||||
| 	file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_rawDesc = nil |  | ||||||
| 	file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_goTypes = nil |  | ||||||
| 	file_github_com_containerd_containerd_runtime_linux_runctypes_runc_proto_depIdxs = nil |  | ||||||
| } |  | ||||||
| @@ -1,50 +0,0 @@ | |||||||
| syntax = "proto3"; |  | ||||||
|  |  | ||||||
| package containerd.linux.runc; |  | ||||||
|  |  | ||||||
| option go_package = "github.com/containerd/containerd/runtime/linux/runctypes;runctypes"; |  | ||||||
|  |  | ||||||
| message RuncOptions { |  | ||||||
| 	string runtime = 1; |  | ||||||
| 	string runtime_root = 2; |  | ||||||
| 	// criu binary path. |  | ||||||
| 	// |  | ||||||
| 	// Deprecated: runc option --criu is now ignored (with a warning), and the |  | ||||||
| 	// option will be removed entirely in a future release. Users who need a non- |  | ||||||
| 	// standard criu binary should rely on the standard way of looking up binaries |  | ||||||
| 	// in $PATH. |  | ||||||
| 	string criu_path = 3 [deprecated = true]; |  | ||||||
| 	bool systemd_cgroup = 4; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message CreateOptions { |  | ||||||
| 	bool no_pivot_root = 1; |  | ||||||
| 	bool open_tcp = 2; |  | ||||||
| 	bool external_unix_sockets = 3; |  | ||||||
| 	bool terminal = 4; |  | ||||||
| 	bool file_locks = 5; |  | ||||||
| 	repeated string empty_namespaces = 6; |  | ||||||
| 	string cgroups_mode = 7; |  | ||||||
| 	bool no_new_keyring = 8; |  | ||||||
| 	string shim_cgroup = 9; |  | ||||||
| 	uint32 io_uid = 10; |  | ||||||
| 	uint32 io_gid = 11; |  | ||||||
| 	string criu_work_path = 12; |  | ||||||
| 	string criu_image_path = 13; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message CheckpointOptions { |  | ||||||
| 	bool exit = 1; |  | ||||||
| 	bool open_tcp = 2; |  | ||||||
| 	bool external_unix_sockets = 3; |  | ||||||
| 	bool terminal = 4; |  | ||||||
| 	bool file_locks = 5; |  | ||||||
| 	repeated string empty_namespaces = 6; |  | ||||||
| 	string cgroups_mode = 7; |  | ||||||
| 	string work_path = 8; |  | ||||||
| 	string image_path = 9; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message ProcessDetails { |  | ||||||
| 	string exec_id = 1; |  | ||||||
| } |  | ||||||
| @@ -1,248 +0,0 @@ | |||||||
| //go:build linux |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|    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 linux |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"crypto/sha256" |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/events/exchange" |  | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v1/shim" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v1/shim/client" |  | ||||||
| 	"github.com/opencontainers/runtime-spec/specs-go" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // loadBundle loads an existing bundle from disk |  | ||||||
| func loadBundle(id, path, workdir string) *bundle { |  | ||||||
| 	return &bundle{ |  | ||||||
| 		id:      id, |  | ||||||
| 		path:    path, |  | ||||||
| 		workDir: workdir, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // newBundle creates a new bundle on disk at the provided path for the given id |  | ||||||
| func newBundle(id, path, workDir string, spec []byte) (b *bundle, err error) { |  | ||||||
| 	if err := os.MkdirAll(path, 0711); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	path = filepath.Join(path, id) |  | ||||||
| 	if err := os.Mkdir(path, 0700); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	defer func() { |  | ||||||
| 		if err != nil { |  | ||||||
| 			os.RemoveAll(path) |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
| 	if err := prepareBundleDirectoryPermissions(path, spec); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	workDir = filepath.Join(workDir, id) |  | ||||||
| 	if err := os.MkdirAll(workDir, 0711); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	defer func() { |  | ||||||
| 		if err != nil { |  | ||||||
| 			os.RemoveAll(workDir) |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
| 	rootfs := filepath.Join(path, "rootfs") |  | ||||||
| 	if err := os.MkdirAll(rootfs, 0711); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	err = os.WriteFile(filepath.Join(path, configFilename), spec, 0666) |  | ||||||
| 	return &bundle{ |  | ||||||
| 		id:      id, |  | ||||||
| 		path:    path, |  | ||||||
| 		workDir: workDir, |  | ||||||
| 	}, err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // prepareBundleDirectoryPermissions prepares the permissions of the bundle |  | ||||||
| // directory. When user namespaces are enabled, the permissions are modified |  | ||||||
| // to allow the remapped root GID to access the bundle. |  | ||||||
| func prepareBundleDirectoryPermissions(path string, spec []byte) error { |  | ||||||
| 	gid, err := remappedGID(spec) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	if gid == 0 { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	if err := os.Chown(path, -1, int(gid)); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	return os.Chmod(path, 0710) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ociSpecUserNS is a subset of specs.Spec used to reduce garbage during |  | ||||||
| // unmarshal. |  | ||||||
| type ociSpecUserNS struct { |  | ||||||
| 	Linux *linuxSpecUserNS |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // linuxSpecUserNS is a subset of specs.Linux used to reduce garbage during |  | ||||||
| // unmarshal. |  | ||||||
| type linuxSpecUserNS struct { |  | ||||||
| 	GIDMappings []specs.LinuxIDMapping |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // remappedGID reads the remapped GID 0 from the OCI spec, if it exists. If |  | ||||||
| // there is no remapping, remappedGID returns 0. If the spec cannot be parsed, |  | ||||||
| // remappedGID returns an error. |  | ||||||
| func remappedGID(spec []byte) (uint32, error) { |  | ||||||
| 	var ociSpec ociSpecUserNS |  | ||||||
| 	err := json.Unmarshal(spec, &ociSpec) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return 0, err |  | ||||||
| 	} |  | ||||||
| 	if ociSpec.Linux == nil || len(ociSpec.Linux.GIDMappings) == 0 { |  | ||||||
| 		return 0, nil |  | ||||||
| 	} |  | ||||||
| 	for _, mapping := range ociSpec.Linux.GIDMappings { |  | ||||||
| 		if mapping.ContainerID == 0 { |  | ||||||
| 			return mapping.HostID, nil |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return 0, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type bundle struct { |  | ||||||
| 	id      string |  | ||||||
| 	path    string |  | ||||||
| 	workDir string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ShimOpt specifies shim options for initialization and connection |  | ||||||
| type ShimOpt func(*bundle, string, *runctypes.RuncOptions) (shim.Config, client.Opt) |  | ||||||
|  |  | ||||||
| // ShimRemote is a ShimOpt for connecting and starting a remote shim |  | ||||||
| func ShimRemote(c *Config, daemonAddress, cgroup string, exitHandler func()) ShimOpt { |  | ||||||
| 	return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) { |  | ||||||
| 		config := b.shimConfig(ns, c, ropts) |  | ||||||
| 		return config, |  | ||||||
| 			client.WithStart(c.Shim, b.shimAddress(ns, daemonAddress), daemonAddress, cgroup, c.ShimDebug, exitHandler) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ShimLocal is a ShimOpt for using an in process shim implementation |  | ||||||
| func ShimLocal(c *Config, exchange *exchange.Exchange) ShimOpt { |  | ||||||
| 	return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) { |  | ||||||
| 		return b.shimConfig(ns, c, ropts), client.WithLocal(exchange) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ShimConnect is a ShimOpt for connecting to an existing remote shim |  | ||||||
| func ShimConnect(c *Config, onClose func()) ShimOpt { |  | ||||||
| 	return func(b *bundle, ns string, ropts *runctypes.RuncOptions) (shim.Config, client.Opt) { |  | ||||||
| 		return b.shimConfig(ns, c, ropts), client.WithConnect(b.decideShimAddress(ns), onClose) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewShimClient connects to the shim managing the bundle and tasks creating it if needed |  | ||||||
| func (b *bundle) NewShimClient(ctx context.Context, namespace string, getClientOpts ShimOpt, runcOpts *runctypes.RuncOptions) (*client.Client, error) { |  | ||||||
| 	cfg, opt := getClientOpts(b, namespace, runcOpts) |  | ||||||
| 	return client.New(ctx, cfg, opt) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Delete deletes the bundle from disk |  | ||||||
| func (b *bundle) Delete() error { |  | ||||||
| 	address, _ := b.loadAddress() |  | ||||||
| 	if address != "" { |  | ||||||
| 		// we don't care about errors here |  | ||||||
| 		client.RemoveSocket(address) |  | ||||||
| 	} |  | ||||||
| 	err := atomicDelete(b.path) |  | ||||||
| 	if err == nil { |  | ||||||
| 		return atomicDelete(b.workDir) |  | ||||||
| 	} |  | ||||||
| 	// error removing the bundle path; still attempt removing work dir |  | ||||||
| 	err2 := atomicDelete(b.workDir) |  | ||||||
| 	if err2 == nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	return fmt.Errorf("failed to remove both bundle and workdir locations: %v: %w", err2, err) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (b *bundle) legacyShimAddress(namespace string) string { |  | ||||||
| 	return filepath.Join(string(filepath.Separator), "containerd-shim", namespace, b.id, "shim.sock") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const socketRoot = "/run/containerd" |  | ||||||
|  |  | ||||||
| func (b *bundle) shimAddress(namespace, socketPath string) string { |  | ||||||
| 	d := sha256.Sum256([]byte(filepath.Join(socketPath, namespace, b.id))) |  | ||||||
| 	return fmt.Sprintf("unix://%s/%x", filepath.Join(socketRoot, "s"), d) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (b *bundle) loadAddress() (string, error) { |  | ||||||
| 	addressPath := filepath.Join(b.path, "address") |  | ||||||
| 	data, err := os.ReadFile(addressPath) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	return string(data), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (b *bundle) decideShimAddress(namespace string) string { |  | ||||||
| 	address, err := b.loadAddress() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return b.legacyShimAddress(namespace) |  | ||||||
| 	} |  | ||||||
| 	return address |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (b *bundle) shimConfig(namespace string, c *Config, runcOptions *runctypes.RuncOptions) shim.Config { |  | ||||||
| 	var ( |  | ||||||
| 		runtimeRoot   = c.RuntimeRoot |  | ||||||
| 		systemdCgroup bool |  | ||||||
| 	) |  | ||||||
| 	if runcOptions != nil { |  | ||||||
| 		systemdCgroup = runcOptions.SystemdCgroup |  | ||||||
| 		if runcOptions.RuntimeRoot != "" { |  | ||||||
| 			runtimeRoot = runcOptions.RuntimeRoot |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return shim.Config{ |  | ||||||
| 		Path:          b.path, |  | ||||||
| 		WorkDir:       b.workDir, |  | ||||||
| 		Namespace:     namespace, |  | ||||||
| 		RuntimeRoot:   runtimeRoot, |  | ||||||
| 		SystemdCgroup: systemdCgroup, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // atomicDelete renames the path to a hidden file before removal |  | ||||||
| func atomicDelete(path string) error { |  | ||||||
| 	// create a hidden dir for an atomic removal |  | ||||||
| 	atomicPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path))) |  | ||||||
| 	if err := os.Rename(path, atomicPath); err != nil { |  | ||||||
| 		if os.IsNotExist(err) { |  | ||||||
| 			return nil |  | ||||||
| 		} |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	return os.RemoveAll(atomicPath) |  | ||||||
| } |  | ||||||
| @@ -1,141 +0,0 @@ | |||||||
| //go:build linux |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|    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 linux |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
| 	"strconv" |  | ||||||
| 	"syscall" |  | ||||||
| 	"testing" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/oci" |  | ||||||
| 	"github.com/containerd/continuity/testutil" |  | ||||||
| 	"github.com/opencontainers/runtime-spec/specs-go" |  | ||||||
| 	"github.com/stretchr/testify/assert" |  | ||||||
| 	"github.com/stretchr/testify/require" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func TestNewBundle(t *testing.T) { |  | ||||||
| 	testutil.RequiresRoot(t) |  | ||||||
| 	tests := []struct { |  | ||||||
| 		userns bool |  | ||||||
| 	}{{ |  | ||||||
| 		userns: false, |  | ||||||
| 	}, { |  | ||||||
| 		userns: true, |  | ||||||
| 	}} |  | ||||||
| 	const usernsGID = 4200 |  | ||||||
|  |  | ||||||
| 	for i, tc := range tests { |  | ||||||
| 		t.Run(strconv.Itoa(i), func(t *testing.T) { |  | ||||||
| 			dir := t.TempDir() |  | ||||||
| 			work := filepath.Join(dir, "work") |  | ||||||
| 			state := filepath.Join(dir, "state") |  | ||||||
| 			id := fmt.Sprintf("new-bundle-%d", i) |  | ||||||
| 			spec := oci.Spec{} |  | ||||||
| 			if tc.userns { |  | ||||||
| 				spec.Linux = &specs.Linux{ |  | ||||||
| 					GIDMappings: []specs.LinuxIDMapping{{ContainerID: 0, HostID: usernsGID}}, |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 			specBytes, err := json.Marshal(&spec) |  | ||||||
| 			require.NoError(t, err, "failed to marshal spec") |  | ||||||
|  |  | ||||||
| 			b, err := newBundle(id, work, state, specBytes) |  | ||||||
| 			require.NoError(t, err, "newBundle should succeed") |  | ||||||
| 			require.NotNil(t, b, "bundle should not be nil") |  | ||||||
|  |  | ||||||
| 			fi, err := os.Stat(b.path) |  | ||||||
| 			assert.NoError(t, err, "should be able to stat bundle path") |  | ||||||
| 			if tc.userns { |  | ||||||
| 				assert.Equal(t, os.ModeDir|0710, fi.Mode(), "bundle path should be a directory with perm 0710") |  | ||||||
| 			} else { |  | ||||||
| 				assert.Equal(t, os.ModeDir|0700, fi.Mode(), "bundle path should be a directory with perm 0700") |  | ||||||
| 			} |  | ||||||
| 			stat, ok := fi.Sys().(*syscall.Stat_t) |  | ||||||
| 			require.True(t, ok, "should assert to *syscall.Stat_t") |  | ||||||
| 			expectedGID := uint32(0) |  | ||||||
| 			if tc.userns { |  | ||||||
| 				expectedGID = usernsGID |  | ||||||
| 			} |  | ||||||
| 			assert.Equal(t, expectedGID, stat.Gid, "gid should match") |  | ||||||
|  |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestRemappedGID(t *testing.T) { |  | ||||||
| 	tests := []struct { |  | ||||||
| 		spec oci.Spec |  | ||||||
| 		gid  uint32 |  | ||||||
| 	}{{ |  | ||||||
| 		// empty spec |  | ||||||
| 		spec: oci.Spec{}, |  | ||||||
| 		gid:  0, |  | ||||||
| 	}, { |  | ||||||
| 		// empty Linux section |  | ||||||
| 		spec: oci.Spec{ |  | ||||||
| 			Linux: &specs.Linux{}, |  | ||||||
| 		}, |  | ||||||
| 		gid: 0, |  | ||||||
| 	}, { |  | ||||||
| 		// empty ID mappings |  | ||||||
| 		spec: oci.Spec{ |  | ||||||
| 			Linux: &specs.Linux{ |  | ||||||
| 				GIDMappings: make([]specs.LinuxIDMapping, 0), |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		gid: 0, |  | ||||||
| 	}, { |  | ||||||
| 		// valid ID mapping |  | ||||||
| 		spec: oci.Spec{ |  | ||||||
| 			Linux: &specs.Linux{ |  | ||||||
| 				GIDMappings: []specs.LinuxIDMapping{{ |  | ||||||
| 					ContainerID: 0, |  | ||||||
| 					HostID:      1000, |  | ||||||
| 				}}, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		gid: 1000, |  | ||||||
| 	}, { |  | ||||||
| 		// missing ID mapping |  | ||||||
| 		spec: oci.Spec{ |  | ||||||
| 			Linux: &specs.Linux{ |  | ||||||
| 				GIDMappings: []specs.LinuxIDMapping{{ |  | ||||||
| 					ContainerID: 100, |  | ||||||
| 					HostID:      1000, |  | ||||||
| 				}}, |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 		gid: 0, |  | ||||||
| 	}} |  | ||||||
|  |  | ||||||
| 	for i, tc := range tests { |  | ||||||
| 		t.Run(strconv.Itoa(i), func(t *testing.T) { |  | ||||||
| 			s, err := json.Marshal(tc.spec) |  | ||||||
| 			require.NoError(t, err, "failed to marshal spec") |  | ||||||
| 			gid, err := remappedGID(s) |  | ||||||
| 			assert.NoError(t, err, "should unmarshal successfully") |  | ||||||
| 			assert.Equal(t, tc.gid, gid, "expected GID to match") |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,171 +0,0 @@ | |||||||
| //go:build linux |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|    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 linux |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"errors" |  | ||||||
|  |  | ||||||
| 	eventstypes "github.com/containerd/containerd/api/events" |  | ||||||
| 	"github.com/containerd/containerd/api/types/task" |  | ||||||
| 	"github.com/containerd/containerd/errdefs" |  | ||||||
| 	"github.com/containerd/containerd/protobuf" |  | ||||||
| 	"github.com/containerd/containerd/runtime" |  | ||||||
| 	shim "github.com/containerd/containerd/runtime/v1/shim/v1" |  | ||||||
| 	"github.com/containerd/ttrpc" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Process implements a linux process |  | ||||||
| type Process struct { |  | ||||||
| 	id string |  | ||||||
| 	t  *Task |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ID of the process |  | ||||||
| func (p *Process) ID() string { |  | ||||||
| 	return p.id |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Kill sends the provided signal to the underlying process |  | ||||||
| // |  | ||||||
| // Unable to kill all processes in the task using this method on a process |  | ||||||
| func (p *Process) Kill(ctx context.Context, signal uint32, _ bool) error { |  | ||||||
| 	_, err := p.t.shim.Kill(ctx, &shim.KillRequest{ |  | ||||||
| 		Signal: signal, |  | ||||||
| 		ID:     p.id, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func statusFromProto(from task.Status) runtime.Status { |  | ||||||
| 	var status runtime.Status |  | ||||||
| 	switch from { |  | ||||||
| 	case task.Status_CREATED: |  | ||||||
| 		status = runtime.CreatedStatus |  | ||||||
| 	case task.Status_RUNNING: |  | ||||||
| 		status = runtime.RunningStatus |  | ||||||
| 	case task.Status_STOPPED: |  | ||||||
| 		status = runtime.StoppedStatus |  | ||||||
| 	case task.Status_PAUSED: |  | ||||||
| 		status = runtime.PausedStatus |  | ||||||
| 	case task.Status_PAUSING: |  | ||||||
| 		status = runtime.PausingStatus |  | ||||||
| 	} |  | ||||||
| 	return status |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // State of process |  | ||||||
| func (p *Process) State(ctx context.Context) (runtime.State, error) { |  | ||||||
| 	// use the container status for the status of the process |  | ||||||
| 	response, err := p.t.shim.State(ctx, &shim.StateRequest{ |  | ||||||
| 		ID: p.id, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		if !errors.Is(err, ttrpc.ErrClosed) { |  | ||||||
| 			return runtime.State{}, errdefs.FromGRPC(err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// We treat ttrpc.ErrClosed as the shim being closed, but really this |  | ||||||
| 		// likely means that the process no longer exists. We'll have to plumb |  | ||||||
| 		// the connection differently if this causes problems. |  | ||||||
| 		return runtime.State{}, errdefs.ErrNotFound |  | ||||||
| 	} |  | ||||||
| 	return runtime.State{ |  | ||||||
| 		Pid:        response.Pid, |  | ||||||
| 		Status:     statusFromProto(response.Status), |  | ||||||
| 		Stdin:      response.Stdin, |  | ||||||
| 		Stdout:     response.Stdout, |  | ||||||
| 		Stderr:     response.Stderr, |  | ||||||
| 		Terminal:   response.Terminal, |  | ||||||
| 		ExitStatus: response.ExitStatus, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ResizePty changes the side of the process's PTY to the provided width and height |  | ||||||
| func (p *Process) ResizePty(ctx context.Context, size runtime.ConsoleSize) error { |  | ||||||
| 	_, err := p.t.shim.ResizePty(ctx, &shim.ResizePtyRequest{ |  | ||||||
| 		ID:     p.id, |  | ||||||
| 		Width:  size.Width, |  | ||||||
| 		Height: size.Height, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		err = errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // CloseIO closes the provided IO pipe for the process |  | ||||||
| func (p *Process) CloseIO(ctx context.Context) error { |  | ||||||
| 	_, err := p.t.shim.CloseIO(ctx, &shim.CloseIORequest{ |  | ||||||
| 		ID:    p.id, |  | ||||||
| 		Stdin: true, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Start the process |  | ||||||
| func (p *Process) Start(ctx context.Context) error { |  | ||||||
| 	r, err := p.t.shim.Start(ctx, &shim.StartRequest{ |  | ||||||
| 		ID: p.id, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	p.t.events.Publish(ctx, runtime.TaskExecStartedEventTopic, &eventstypes.TaskExecStarted{ |  | ||||||
| 		ContainerID: p.t.id, |  | ||||||
| 		Pid:         r.Pid, |  | ||||||
| 		ExecID:      p.id, |  | ||||||
| 	}) |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Wait on the process to exit and return the exit status and timestamp |  | ||||||
| func (p *Process) Wait(ctx context.Context) (*runtime.Exit, error) { |  | ||||||
| 	r, err := p.t.shim.Wait(ctx, &shim.WaitRequest{ |  | ||||||
| 		ID: p.id, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &runtime.Exit{ |  | ||||||
| 		Timestamp: protobuf.FromTimestamp(r.ExitedAt), |  | ||||||
| 		Status:    r.ExitStatus, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Delete the process and return the exit status |  | ||||||
| func (p *Process) Delete(ctx context.Context) (*runtime.Exit, error) { |  | ||||||
| 	r, err := p.t.shim.DeleteProcess(ctx, &shim.DeleteProcessRequest{ |  | ||||||
| 		ID: p.id, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return &runtime.Exit{ |  | ||||||
| 		Status:    r.ExitStatus, |  | ||||||
| 		Timestamp: protobuf.FromTimestamp(r.ExitedAt), |  | ||||||
| 		Pid:       r.Pid, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
| @@ -1,546 +0,0 @@ | |||||||
| //go:build linux |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|    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 linux |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" |  | ||||||
| 	"io" |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	eventstypes "github.com/containerd/containerd/api/events" |  | ||||||
| 	"github.com/containerd/containerd/api/types" |  | ||||||
| 	"github.com/containerd/containerd/containers" |  | ||||||
| 	"github.com/containerd/containerd/errdefs" |  | ||||||
| 	"github.com/containerd/containerd/events/exchange" |  | ||||||
| 	"github.com/containerd/containerd/identifiers" |  | ||||||
| 	"github.com/containerd/containerd/log" |  | ||||||
| 	"github.com/containerd/containerd/metadata" |  | ||||||
| 	"github.com/containerd/containerd/mount" |  | ||||||
| 	"github.com/containerd/containerd/namespaces" |  | ||||||
| 	"github.com/containerd/containerd/pkg/cleanup" |  | ||||||
| 	"github.com/containerd/containerd/pkg/process" |  | ||||||
| 	"github.com/containerd/containerd/platforms" |  | ||||||
| 	"github.com/containerd/containerd/plugin" |  | ||||||
| 	"github.com/containerd/containerd/protobuf" |  | ||||||
| 	ptypes "github.com/containerd/containerd/protobuf/types" |  | ||||||
| 	"github.com/containerd/containerd/runtime" |  | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	v1 "github.com/containerd/containerd/runtime/v1" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v1/shim/v1" |  | ||||||
| 	"github.com/containerd/go-runc" |  | ||||||
| 	"github.com/containerd/typeurl/v2" |  | ||||||
| 	ocispec "github.com/opencontainers/image-spec/specs-go/v1" |  | ||||||
| 	"golang.org/x/sys/unix" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	pluginID = fmt.Sprintf("%s.%s", plugin.RuntimePlugin, "linux") |  | ||||||
| 	empty    = &ptypes.Empty{} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	configFilename = "config.json" |  | ||||||
| 	defaultRuntime = "runc" |  | ||||||
| 	defaultShim    = "containerd-shim" |  | ||||||
|  |  | ||||||
| 	// cleanupTimeout is default timeout for cleanup operations |  | ||||||
| 	cleanupTimeout = 1 * time.Minute |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func init() { |  | ||||||
| 	plugin.Register(&plugin.Registration{ |  | ||||||
| 		Type:   plugin.RuntimePlugin, |  | ||||||
| 		ID:     "linux", |  | ||||||
| 		InitFn: New, |  | ||||||
| 		Requires: []plugin.Type{ |  | ||||||
| 			plugin.EventPlugin, |  | ||||||
| 			plugin.MetadataPlugin, |  | ||||||
| 		}, |  | ||||||
| 		Config: &Config{ |  | ||||||
| 			Shim:    defaultShim, |  | ||||||
| 			Runtime: defaultRuntime, |  | ||||||
| 		}, |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var _ = (runtime.PlatformRuntime)(&Runtime{}) |  | ||||||
|  |  | ||||||
| // Config options for the runtime |  | ||||||
| type Config struct { |  | ||||||
| 	// Shim is a path or name of binary implementing the Shim GRPC API |  | ||||||
| 	Shim string `toml:"shim"` |  | ||||||
| 	// Runtime is a path or name of an OCI runtime used by the shim |  | ||||||
| 	Runtime string `toml:"runtime"` |  | ||||||
| 	// RuntimeRoot is the path that shall be used by the OCI runtime for its data |  | ||||||
| 	RuntimeRoot string `toml:"runtime_root"` |  | ||||||
| 	// NoShim calls runc directly from within the pkg |  | ||||||
| 	NoShim bool `toml:"no_shim"` |  | ||||||
| 	// Debug enable debug on the shim |  | ||||||
| 	ShimDebug bool `toml:"shim_debug"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // New returns a configured runtime |  | ||||||
| func New(ic *plugin.InitContext) (interface{}, error) { |  | ||||||
| 	ic.Meta.Platforms = []ocispec.Platform{platforms.DefaultSpec()} |  | ||||||
|  |  | ||||||
| 	if err := os.MkdirAll(ic.Root, 0711); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := os.MkdirAll(ic.State, 0711); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	m, err := ic.Get(plugin.MetadataPlugin) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ep, err := ic.GetByID(plugin.EventPlugin, "exchange") |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	cfg := ic.Config.(*Config) |  | ||||||
| 	r := &Runtime{ |  | ||||||
| 		root:       ic.Root, |  | ||||||
| 		state:      ic.State, |  | ||||||
| 		tasks:      runtime.NewNSMap[runtime.Task](), |  | ||||||
| 		containers: metadata.NewContainerStore(m.(*metadata.DB)), |  | ||||||
| 		address:    ic.Address, |  | ||||||
| 		events:     ep.(*exchange.Exchange), |  | ||||||
| 		config:     cfg, |  | ||||||
| 	} |  | ||||||
| 	tasks, err := r.restoreTasks(ic.Context) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	for _, t := range tasks { |  | ||||||
| 		if err := r.tasks.AddWithNamespace(t.namespace, t); err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return r, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Runtime for a linux based system |  | ||||||
| type Runtime struct { |  | ||||||
| 	root    string |  | ||||||
| 	state   string |  | ||||||
| 	address string |  | ||||||
|  |  | ||||||
| 	tasks      *runtime.NSMap[runtime.Task] |  | ||||||
| 	containers containers.Store |  | ||||||
| 	events     *exchange.Exchange |  | ||||||
|  |  | ||||||
| 	config *Config |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ID of the runtime |  | ||||||
| func (r *Runtime) ID() string { |  | ||||||
| 	return pluginID |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Create a new task |  | ||||||
| func (r *Runtime) Create(ctx context.Context, id string, opts runtime.CreateOpts) (_ runtime.Task, err error) { |  | ||||||
| 	namespace, err := namespaces.NamespaceRequired(ctx) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	ctx = log.WithLogger(ctx, log.G(ctx).WithError(err).WithFields(log.Fields{ |  | ||||||
| 		"id":        id, |  | ||||||
| 		"namespace": namespace, |  | ||||||
| 	})) |  | ||||||
|  |  | ||||||
| 	if err := identifiers.Validate(id); err != nil { |  | ||||||
| 		return nil, fmt.Errorf("invalid task id: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ropts, err := r.getRuncOptions(ctx, id) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	bundle, err := newBundle(id, |  | ||||||
| 		filepath.Join(r.state, namespace), |  | ||||||
| 		filepath.Join(r.root, namespace), |  | ||||||
| 		opts.Spec.GetValue()) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	defer func() { |  | ||||||
| 		if err != nil { |  | ||||||
| 			bundle.Delete() |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
|  |  | ||||||
| 	shimopt := ShimLocal(r.config, r.events) |  | ||||||
| 	if !r.config.NoShim { |  | ||||||
| 		var cgroup string |  | ||||||
| 		if opts.TaskOptions != nil && opts.TaskOptions.GetValue() != nil { |  | ||||||
| 			v, err := typeurl.UnmarshalAny(opts.TaskOptions) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return nil, err |  | ||||||
| 			} |  | ||||||
| 			cgroup = v.(*runctypes.CreateOptions).ShimCgroup |  | ||||||
| 		} |  | ||||||
| 		exitHandler := func() { |  | ||||||
| 			log.G(ctx).WithField("id", id).Info("shim reaped") |  | ||||||
|  |  | ||||||
| 			if _, err := r.tasks.Get(ctx, id); err != nil { |  | ||||||
| 				// Task was never started or was already successfully deleted |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if err = r.cleanupAfterDeadShim(cleanup.Background(ctx), bundle, namespace, id); err != nil { |  | ||||||
| 				log.G(ctx).WithError(err).Warn("failed to clean up after killed shim") |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		shimopt = ShimRemote(r.config, r.address, cgroup, exitHandler) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	s, err := bundle.NewShimClient(ctx, namespace, shimopt, ropts) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	defer func() { |  | ||||||
| 		if err != nil { |  | ||||||
| 			deferCtx, deferCancel := context.WithTimeout(cleanup.Background(ctx), cleanupTimeout) |  | ||||||
| 			defer deferCancel() |  | ||||||
| 			if kerr := s.KillShim(deferCtx); kerr != nil { |  | ||||||
| 				log.G(ctx).WithError(kerr).Error("failed to kill shim") |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
|  |  | ||||||
| 	rt := r.config.Runtime |  | ||||||
| 	if ropts != nil && ropts.Runtime != "" { |  | ||||||
| 		rt = ropts.Runtime |  | ||||||
| 	} |  | ||||||
| 	sopts := &shim.CreateTaskRequest{ |  | ||||||
| 		ID:         id, |  | ||||||
| 		Bundle:     bundle.path, |  | ||||||
| 		Runtime:    rt, |  | ||||||
| 		Stdin:      opts.IO.Stdin, |  | ||||||
| 		Stdout:     opts.IO.Stdout, |  | ||||||
| 		Stderr:     opts.IO.Stderr, |  | ||||||
| 		Terminal:   opts.IO.Terminal, |  | ||||||
| 		Checkpoint: opts.Checkpoint, |  | ||||||
| 		Options:    protobuf.FromAny(opts.TaskOptions), |  | ||||||
| 	} |  | ||||||
| 	for _, m := range opts.Rootfs { |  | ||||||
| 		sopts.Rootfs = append(sopts.Rootfs, &types.Mount{ |  | ||||||
| 			Type:    m.Type, |  | ||||||
| 			Source:  m.Source, |  | ||||||
| 			Target:  m.Target, |  | ||||||
| 			Options: m.Options, |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 	cr, err := s.Create(ctx, sopts) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	t, err := newTask(id, namespace, int(cr.Pid), s, r.events, r.tasks, bundle) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := r.tasks.Add(ctx, t); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	r.events.Publish(ctx, runtime.TaskCreateEventTopic, &eventstypes.TaskCreate{ |  | ||||||
| 		ContainerID: sopts.ID, |  | ||||||
| 		Bundle:      sopts.Bundle, |  | ||||||
| 		Rootfs:      sopts.Rootfs, |  | ||||||
| 		IO: &eventstypes.TaskIO{ |  | ||||||
| 			Stdin:    sopts.Stdin, |  | ||||||
| 			Stdout:   sopts.Stdout, |  | ||||||
| 			Stderr:   sopts.Stderr, |  | ||||||
| 			Terminal: sopts.Terminal, |  | ||||||
| 		}, |  | ||||||
| 		Checkpoint: sopts.Checkpoint, |  | ||||||
| 		Pid:        uint32(t.pid), |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	return t, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Tasks returns all tasks known to the runtime |  | ||||||
| func (r *Runtime) Tasks(ctx context.Context, all bool) ([]runtime.Task, error) { |  | ||||||
| 	return r.tasks.GetAll(ctx, all) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *Runtime) restoreTasks(ctx context.Context) ([]*Task, error) { |  | ||||||
| 	dir, err := os.ReadDir(r.state) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	var o []*Task |  | ||||||
| 	for _, namespace := range dir { |  | ||||||
| 		if !namespace.IsDir() { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		name := namespace.Name() |  | ||||||
| 		// skip hidden directories |  | ||||||
| 		if len(name) > 0 && name[0] == '.' { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		log.G(ctx).WithField("namespace", name).Debug("loading tasks in namespace") |  | ||||||
| 		tasks, err := r.loadTasks(ctx, name) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		o = append(o, tasks...) |  | ||||||
| 	} |  | ||||||
| 	return o, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Get a specific task by task id |  | ||||||
| func (r *Runtime) Get(ctx context.Context, id string) (runtime.Task, error) { |  | ||||||
| 	return r.tasks.Get(ctx, id) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Add a runtime task |  | ||||||
| func (r *Runtime) Add(ctx context.Context, task runtime.Task) error { |  | ||||||
| 	return r.tasks.Add(ctx, task) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Delete a runtime task |  | ||||||
| func (r *Runtime) Delete(ctx context.Context, id string) (*runtime.Exit, error) { |  | ||||||
| 	task, err := r.tasks.Get(ctx, id) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	s := task.(*Task) |  | ||||||
| 	exit, err := s.Delete(ctx) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	r.tasks.Delete(ctx, id) |  | ||||||
| 	return exit, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *Runtime) loadTasks(ctx context.Context, ns string) ([]*Task, error) { |  | ||||||
| 	dir, err := os.ReadDir(filepath.Join(r.state, ns)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	var o []*Task |  | ||||||
| 	for _, path := range dir { |  | ||||||
| 		if !path.IsDir() { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		id := path.Name() |  | ||||||
| 		// skip hidden directories |  | ||||||
| 		if len(id) > 0 && id[0] == '.' { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		bundle := loadBundle( |  | ||||||
| 			id, |  | ||||||
| 			filepath.Join(r.state, ns, id), |  | ||||||
| 			filepath.Join(r.root, ns, id), |  | ||||||
| 		) |  | ||||||
| 		ctx = namespaces.WithNamespace(ctx, ns) |  | ||||||
| 		ctx = log.WithLogger(ctx, log.G(ctx).WithError(err).WithFields(log.Fields{ |  | ||||||
| 			"id":        id, |  | ||||||
| 			"namespace": ns, |  | ||||||
| 		})) |  | ||||||
|  |  | ||||||
| 		pid, _ := runc.ReadPidFile(filepath.Join(bundle.path, process.InitPidFile)) |  | ||||||
| 		shimExit := make(chan struct{}) |  | ||||||
| 		s, err := bundle.NewShimClient(ctx, ns, ShimConnect(r.config, func() { |  | ||||||
| 			defer close(shimExit) |  | ||||||
| 			if _, err := r.tasks.Get(ctx, id); err != nil { |  | ||||||
| 				// Task was never started or was already successfully deleted |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if err := r.cleanupAfterDeadShim(ctx, bundle, ns, id); err != nil { |  | ||||||
| 				log.G(ctx).WithError(err).WithField("bundle", bundle.path). |  | ||||||
| 					Error("cleaning up after dead shim") |  | ||||||
| 			} |  | ||||||
| 		}), nil) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.G(ctx).WithError(err).Error("connecting to shim") |  | ||||||
| 			err := r.cleanupAfterDeadShim(ctx, bundle, ns, id) |  | ||||||
| 			if err != nil { |  | ||||||
| 				log.G(ctx).WithError(err).WithField("bundle", bundle.path). |  | ||||||
| 					Error("cleaning up after dead shim") |  | ||||||
| 			} |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		logDirPath := filepath.Join(r.root, ns, id) |  | ||||||
|  |  | ||||||
| 		copyAndClose := func(dst io.Writer, src io.ReadWriteCloser) { |  | ||||||
| 			copyDone := make(chan struct{}) |  | ||||||
| 			go func() { |  | ||||||
| 				io.Copy(dst, src) |  | ||||||
| 				close(copyDone) |  | ||||||
| 			}() |  | ||||||
| 			select { |  | ||||||
| 			case <-shimExit: |  | ||||||
| 			case <-copyDone: |  | ||||||
| 			} |  | ||||||
| 			src.Close() |  | ||||||
| 		} |  | ||||||
| 		shimStdoutLog, err := v1.OpenShimStdoutLog(ctx, logDirPath) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.G(ctx).WithError(err).WithField("logDirPath", logDirPath). |  | ||||||
| 				Error("opening shim stdout log pipe") |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if r.config.ShimDebug { |  | ||||||
| 			go copyAndClose(os.Stdout, shimStdoutLog) |  | ||||||
| 		} else { |  | ||||||
| 			go copyAndClose(io.Discard, shimStdoutLog) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		shimStderrLog, err := v1.OpenShimStderrLog(ctx, logDirPath) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.G(ctx).WithError(err).WithField("logDirPath", logDirPath). |  | ||||||
| 				Error("opening shim stderr log pipe") |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if r.config.ShimDebug { |  | ||||||
| 			go copyAndClose(os.Stderr, shimStderrLog) |  | ||||||
| 		} else { |  | ||||||
| 			go copyAndClose(io.Discard, shimStderrLog) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		t, err := newTask(id, ns, pid, s, r.events, r.tasks, bundle) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.G(ctx).WithError(err).Error("loading task type") |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		o = append(o, t) |  | ||||||
| 	} |  | ||||||
| 	return o, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *Runtime) cleanupAfterDeadShim(ctx context.Context, bundle *bundle, ns, id string) error { |  | ||||||
| 	log.G(ctx).Warn("cleaning up after shim dead") |  | ||||||
|  |  | ||||||
| 	pid, _ := runc.ReadPidFile(filepath.Join(bundle.path, process.InitPidFile)) |  | ||||||
| 	if err := r.terminate(ctx, bundle, ns, id); err != nil { |  | ||||||
| 		if r.config.ShimDebug { |  | ||||||
| 			return fmt.Errorf("failed to terminate task, leaving bundle for debugging: %w", err) |  | ||||||
| 		} |  | ||||||
| 		log.G(ctx).WithError(err).Warn("failed to terminate task") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Notify Client |  | ||||||
| 	exitedAt := time.Now().UTC() |  | ||||||
| 	r.events.Publish(ctx, runtime.TaskExitEventTopic, &eventstypes.TaskExit{ |  | ||||||
| 		ContainerID: id, |  | ||||||
| 		ID:          id, |  | ||||||
| 		Pid:         uint32(pid), |  | ||||||
| 		ExitStatus:  128 + uint32(unix.SIGKILL), |  | ||||||
| 		ExitedAt:    protobuf.ToTimestamp(exitedAt), |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	r.tasks.Delete(ctx, id) |  | ||||||
| 	if err := bundle.Delete(); err != nil { |  | ||||||
| 		log.G(ctx).WithError(err).Error("delete bundle") |  | ||||||
| 	} |  | ||||||
| 	// kill shim |  | ||||||
| 	if shimPid, err := runc.ReadPidFile(filepath.Join(bundle.path, "shim.pid")); err == nil && shimPid > 0 { |  | ||||||
| 		unix.Kill(shimPid, unix.SIGKILL) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	r.events.Publish(ctx, runtime.TaskDeleteEventTopic, &eventstypes.TaskDelete{ |  | ||||||
| 		ContainerID: id, |  | ||||||
| 		Pid:         uint32(pid), |  | ||||||
| 		ExitStatus:  128 + uint32(unix.SIGKILL), |  | ||||||
| 		ExitedAt:    protobuf.ToTimestamp(exitedAt), |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *Runtime) terminate(ctx context.Context, bundle *bundle, ns, id string) error { |  | ||||||
| 	rt, err := r.getRuntime(ctx, ns, id) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	if err := rt.Delete(ctx, id, &runc.DeleteOpts{ |  | ||||||
| 		Force: true, |  | ||||||
| 	}); err != nil { |  | ||||||
| 		log.G(ctx).WithError(err).Warnf("delete runtime state %s", id) |  | ||||||
| 	} |  | ||||||
| 	if err := mount.Unmount(filepath.Join(bundle.path, "rootfs"), 0); err != nil { |  | ||||||
| 		log.G(ctx).WithError(err).WithFields(log.Fields{ |  | ||||||
| 			"path": bundle.path, |  | ||||||
| 			"id":   id, |  | ||||||
| 		}).Warnf("unmount task rootfs") |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *Runtime) getRuntime(ctx context.Context, ns, id string) (*runc.Runc, error) { |  | ||||||
| 	ropts, err := r.getRuncOptions(ctx, id) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var ( |  | ||||||
| 		cmd  = r.config.Runtime |  | ||||||
| 		root = process.RuncRoot |  | ||||||
| 	) |  | ||||||
| 	if ropts != nil { |  | ||||||
| 		if ropts.Runtime != "" { |  | ||||||
| 			cmd = ropts.Runtime |  | ||||||
| 		} |  | ||||||
| 		if ropts.RuntimeRoot != "" { |  | ||||||
| 			root = ropts.RuntimeRoot |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return &runc.Runc{ |  | ||||||
| 		Command:      cmd, |  | ||||||
| 		LogFormat:    runc.JSON, |  | ||||||
| 		PdeathSignal: unix.SIGKILL, |  | ||||||
| 		Root:         filepath.Join(root, ns), |  | ||||||
| 		Debug:        r.config.ShimDebug, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *Runtime) getRuncOptions(ctx context.Context, id string) (*runctypes.RuncOptions, error) { |  | ||||||
| 	container, err := r.containers.Get(ctx, id) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if container.Runtime.Options != nil && container.Runtime.Options.GetValue() != nil { |  | ||||||
| 		v, err := typeurl.UnmarshalAny(container.Runtime.Options) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		ropts, ok := v.(*runctypes.RuncOptions) |  | ||||||
| 		if !ok { |  | ||||||
| 			return nil, errors.New("invalid runtime options format") |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return ropts, nil |  | ||||||
| 	} |  | ||||||
| 	return &runctypes.RuncOptions{}, nil |  | ||||||
| } |  | ||||||
| @@ -1,353 +0,0 @@ | |||||||
| //go:build linux |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|    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 linux |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" |  | ||||||
| 	"sync" |  | ||||||
|  |  | ||||||
| 	cgroups "github.com/containerd/cgroups/v3/cgroup1" |  | ||||||
| 	eventstypes "github.com/containerd/containerd/api/events" |  | ||||||
| 	"github.com/containerd/containerd/errdefs" |  | ||||||
| 	"github.com/containerd/containerd/events/exchange" |  | ||||||
| 	"github.com/containerd/containerd/identifiers" |  | ||||||
| 	"github.com/containerd/containerd/log" |  | ||||||
| 	"github.com/containerd/containerd/protobuf" |  | ||||||
| 	"github.com/containerd/containerd/protobuf/types" |  | ||||||
| 	"github.com/containerd/containerd/runtime" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v1/shim/client" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v1/shim/v1" |  | ||||||
| 	"github.com/containerd/ttrpc" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Task on a linux based system |  | ||||||
| type Task struct { |  | ||||||
| 	mu        sync.Mutex |  | ||||||
| 	id        string |  | ||||||
| 	pid       int |  | ||||||
| 	shim      *client.Client |  | ||||||
| 	namespace string |  | ||||||
| 	cg        cgroups.Cgroup |  | ||||||
| 	events    *exchange.Exchange |  | ||||||
| 	tasks     *runtime.NSMap[runtime.Task] |  | ||||||
| 	bundle    *bundle |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newTask(id, namespace string, pid int, shim *client.Client, events *exchange.Exchange, list *runtime.NSMap[runtime.Task], bundle *bundle) (*Task, error) { |  | ||||||
| 	var ( |  | ||||||
| 		err error |  | ||||||
| 		cg  cgroups.Cgroup |  | ||||||
| 	) |  | ||||||
| 	if pid > 0 { |  | ||||||
| 		cg, err = cgroups.Load(cgroups.PidPath(pid)) |  | ||||||
| 		if err != nil && err != cgroups.ErrCgroupDeleted { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return &Task{ |  | ||||||
| 		id:        id, |  | ||||||
| 		pid:       pid, |  | ||||||
| 		shim:      shim, |  | ||||||
| 		namespace: namespace, |  | ||||||
| 		cg:        cg, |  | ||||||
| 		events:    events, |  | ||||||
| 		tasks:     list, |  | ||||||
| 		bundle:    bundle, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ID of the task |  | ||||||
| func (t *Task) ID() string { |  | ||||||
| 	return t.id |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Namespace of the task |  | ||||||
| func (t *Task) Namespace() string { |  | ||||||
| 	return t.namespace |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // PID of the task |  | ||||||
| func (t *Task) PID(_ context.Context) (uint32, error) { |  | ||||||
| 	return uint32(t.pid), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Delete the task and return the exit status |  | ||||||
| func (t *Task) Delete(ctx context.Context) (*runtime.Exit, error) { |  | ||||||
| 	rsp, shimErr := t.shim.Delete(ctx, empty) |  | ||||||
| 	if shimErr != nil { |  | ||||||
| 		shimErr = errdefs.FromGRPC(shimErr) |  | ||||||
| 		if !errdefs.IsNotFound(shimErr) { |  | ||||||
| 			return nil, shimErr |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	t.tasks.Delete(ctx, t.id) |  | ||||||
| 	if err := t.shim.KillShim(ctx); err != nil { |  | ||||||
| 		log.G(ctx).WithError(err).Error("failed to kill shim") |  | ||||||
| 	} |  | ||||||
| 	if err := t.bundle.Delete(); err != nil { |  | ||||||
| 		log.G(ctx).WithError(err).Error("failed to delete bundle") |  | ||||||
| 	} |  | ||||||
| 	if shimErr != nil { |  | ||||||
| 		return nil, shimErr |  | ||||||
| 	} |  | ||||||
| 	t.events.Publish(ctx, runtime.TaskDeleteEventTopic, &eventstypes.TaskDelete{ |  | ||||||
| 		ContainerID: t.id, |  | ||||||
| 		ExitStatus:  rsp.ExitStatus, |  | ||||||
| 		ExitedAt:    rsp.ExitedAt, |  | ||||||
| 		Pid:         rsp.Pid, |  | ||||||
| 	}) |  | ||||||
| 	return &runtime.Exit{ |  | ||||||
| 		Status:    rsp.ExitStatus, |  | ||||||
| 		Timestamp: protobuf.FromTimestamp(rsp.ExitedAt), |  | ||||||
| 		Pid:       rsp.Pid, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Start the task |  | ||||||
| func (t *Task) Start(ctx context.Context) error { |  | ||||||
| 	t.mu.Lock() |  | ||||||
| 	hasCgroup := t.cg != nil |  | ||||||
| 	t.mu.Unlock() |  | ||||||
| 	r, err := t.shim.Start(ctx, &shim.StartRequest{ |  | ||||||
| 		ID: t.id, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	t.pid = int(r.Pid) |  | ||||||
| 	if !hasCgroup { |  | ||||||
| 		cg, err := cgroups.Load(cgroups.PidPath(t.pid)) |  | ||||||
| 		if err != nil && err != cgroups.ErrCgroupDeleted { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		t.mu.Lock() |  | ||||||
| 		if err == cgroups.ErrCgroupDeleted { |  | ||||||
| 			t.cg = nil |  | ||||||
| 		} else { |  | ||||||
| 			t.cg = cg |  | ||||||
| 		} |  | ||||||
| 		t.mu.Unlock() |  | ||||||
| 	} |  | ||||||
| 	t.events.Publish(ctx, runtime.TaskStartEventTopic, &eventstypes.TaskStart{ |  | ||||||
| 		ContainerID: t.id, |  | ||||||
| 		Pid:         uint32(t.pid), |  | ||||||
| 	}) |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // State returns runtime information for the task |  | ||||||
| func (t *Task) State(ctx context.Context) (runtime.State, error) { |  | ||||||
| 	response, err := t.shim.State(ctx, &shim.StateRequest{ |  | ||||||
| 		ID: t.id, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		if !errors.Is(err, ttrpc.ErrClosed) { |  | ||||||
| 			return runtime.State{}, errdefs.FromGRPC(err) |  | ||||||
| 		} |  | ||||||
| 		return runtime.State{}, errdefs.ErrNotFound |  | ||||||
| 	} |  | ||||||
| 	return runtime.State{ |  | ||||||
| 		Pid:        response.Pid, |  | ||||||
| 		Status:     statusFromProto(response.Status), |  | ||||||
| 		Stdin:      response.Stdin, |  | ||||||
| 		Stdout:     response.Stdout, |  | ||||||
| 		Stderr:     response.Stderr, |  | ||||||
| 		Terminal:   response.Terminal, |  | ||||||
| 		ExitStatus: response.ExitStatus, |  | ||||||
| 		ExitedAt:   protobuf.FromTimestamp(response.ExitedAt), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Pause the task and all processes |  | ||||||
| func (t *Task) Pause(ctx context.Context) error { |  | ||||||
| 	if _, err := t.shim.Pause(ctx, empty); err != nil { |  | ||||||
| 		return errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	t.events.Publish(ctx, runtime.TaskPausedEventTopic, &eventstypes.TaskPaused{ |  | ||||||
| 		ContainerID: t.id, |  | ||||||
| 	}) |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Resume the task and all processes |  | ||||||
| func (t *Task) Resume(ctx context.Context) error { |  | ||||||
| 	if _, err := t.shim.Resume(ctx, empty); err != nil { |  | ||||||
| 		return errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	t.events.Publish(ctx, runtime.TaskResumedEventTopic, &eventstypes.TaskResumed{ |  | ||||||
| 		ContainerID: t.id, |  | ||||||
| 	}) |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Kill the task using the provided signal |  | ||||||
| // |  | ||||||
| // Optionally send the signal to all processes that are a child of the task |  | ||||||
| func (t *Task) Kill(ctx context.Context, signal uint32, all bool) error { |  | ||||||
| 	if _, err := t.shim.Kill(ctx, &shim.KillRequest{ |  | ||||||
| 		ID:     t.id, |  | ||||||
| 		Signal: signal, |  | ||||||
| 		All:    all, |  | ||||||
| 	}); err != nil { |  | ||||||
| 		return errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Exec creates a new process inside the task |  | ||||||
| func (t *Task) Exec(ctx context.Context, id string, opts runtime.ExecOpts) (runtime.ExecProcess, error) { |  | ||||||
| 	if err := identifiers.Validate(id); err != nil { |  | ||||||
| 		return nil, fmt.Errorf("invalid exec id: %w", err) |  | ||||||
| 	} |  | ||||||
| 	request := &shim.ExecProcessRequest{ |  | ||||||
| 		ID:       id, |  | ||||||
| 		Stdin:    opts.IO.Stdin, |  | ||||||
| 		Stdout:   opts.IO.Stdout, |  | ||||||
| 		Stderr:   opts.IO.Stderr, |  | ||||||
| 		Terminal: opts.IO.Terminal, |  | ||||||
| 		Spec:     opts.Spec, |  | ||||||
| 	} |  | ||||||
| 	if _, err := t.shim.Exec(ctx, request); err != nil { |  | ||||||
| 		return nil, errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return &Process{ |  | ||||||
| 		id: id, |  | ||||||
| 		t:  t, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Pids returns all system level process ids running inside the task |  | ||||||
| func (t *Task) Pids(ctx context.Context) ([]runtime.ProcessInfo, error) { |  | ||||||
| 	resp, err := t.shim.ListPids(ctx, &shim.ListPidsRequest{ |  | ||||||
| 		ID: t.id, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	var processList []runtime.ProcessInfo |  | ||||||
| 	for _, p := range resp.Processes { |  | ||||||
| 		processList = append(processList, runtime.ProcessInfo{ |  | ||||||
| 			Pid:  p.Pid, |  | ||||||
| 			Info: p.Info, |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 	return processList, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ResizePty changes the side of the task's PTY to the provided width and height |  | ||||||
| func (t *Task) ResizePty(ctx context.Context, size runtime.ConsoleSize) error { |  | ||||||
| 	_, err := t.shim.ResizePty(ctx, &shim.ResizePtyRequest{ |  | ||||||
| 		ID:     t.id, |  | ||||||
| 		Width:  size.Width, |  | ||||||
| 		Height: size.Height, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		err = errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // CloseIO closes the provided IO on the task |  | ||||||
| func (t *Task) CloseIO(ctx context.Context) error { |  | ||||||
| 	_, err := t.shim.CloseIO(ctx, &shim.CloseIORequest{ |  | ||||||
| 		ID:    t.id, |  | ||||||
| 		Stdin: true, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		err = errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Checkpoint creates a system level dump of the task and process information that can be later restored |  | ||||||
| func (t *Task) Checkpoint(ctx context.Context, path string, options *types.Any) error { |  | ||||||
| 	r := &shim.CheckpointTaskRequest{ |  | ||||||
| 		Path:    path, |  | ||||||
| 		Options: options, |  | ||||||
| 	} |  | ||||||
| 	if _, err := t.shim.Checkpoint(ctx, r); err != nil { |  | ||||||
| 		return errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	t.events.Publish(ctx, runtime.TaskCheckpointedEventTopic, &eventstypes.TaskCheckpointed{ |  | ||||||
| 		ContainerID: t.id, |  | ||||||
| 	}) |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Update changes runtime information of a running task |  | ||||||
| func (t *Task) Update(ctx context.Context, resources *types.Any, _ map[string]string) error { |  | ||||||
| 	if _, err := t.shim.Update(ctx, &shim.UpdateTaskRequest{ |  | ||||||
| 		Resources: resources, |  | ||||||
| 	}); err != nil { |  | ||||||
| 		return errdefs.FromGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Process returns a specific process inside the task by the process id |  | ||||||
| func (t *Task) Process(ctx context.Context, id string) (runtime.ExecProcess, error) { |  | ||||||
| 	p := &Process{ |  | ||||||
| 		id: id, |  | ||||||
| 		t:  t, |  | ||||||
| 	} |  | ||||||
| 	if _, err := p.State(ctx); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return p, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Stats returns runtime specific system level metric information for the task |  | ||||||
| func (t *Task) Stats(ctx context.Context) (*types.Any, error) { |  | ||||||
| 	t.mu.Lock() |  | ||||||
| 	defer t.mu.Unlock() |  | ||||||
| 	if t.cg == nil { |  | ||||||
| 		return nil, fmt.Errorf("cgroup does not exist: %w", errdefs.ErrNotFound) |  | ||||||
| 	} |  | ||||||
| 	stats, err := t.cg.Stat(cgroups.IgnoreNotExist) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return protobuf.MarshalAnyToProto(stats) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Cgroup returns the underlying cgroup for a linux task |  | ||||||
| func (t *Task) Cgroup() (cgroups.Cgroup, error) { |  | ||||||
| 	t.mu.Lock() |  | ||||||
| 	defer t.mu.Unlock() |  | ||||||
| 	if t.cg == nil { |  | ||||||
| 		return nil, fmt.Errorf("cgroup does not exist: %w", errdefs.ErrNotFound) |  | ||||||
| 	} |  | ||||||
| 	return t.cg, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Wait for the task to exit returning the status and timestamp |  | ||||||
| func (t *Task) Wait(ctx context.Context) (*runtime.Exit, error) { |  | ||||||
| 	r, err := t.shim.Wait(ctx, &shim.WaitRequest{ |  | ||||||
| 		ID: t.id, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &runtime.Exit{ |  | ||||||
| 		Timestamp: protobuf.FromTimestamp(r.ExitedAt), |  | ||||||
| 		Status:    r.ExitStatus, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
| @@ -1,38 +0,0 @@ | |||||||
| //go: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 v1 |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"io" |  | ||||||
| 	"path/filepath" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/fifo" |  | ||||||
| 	"golang.org/x/sys/unix" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // OpenShimStdoutLog opens the shim log for reading |  | ||||||
| func OpenShimStdoutLog(ctx context.Context, logDirPath string) (io.ReadWriteCloser, error) { |  | ||||||
| 	return fifo.OpenFifo(ctx, filepath.Join(logDirPath, "shim.stdout.log"), unix.O_RDWR|unix.O_CREAT, 0700) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // OpenShimStderrLog opens the shim log |  | ||||||
| func OpenShimStderrLog(ctx context.Context, logDirPath string) (io.ReadWriteCloser, error) { |  | ||||||
| 	return fifo.OpenFifo(ctx, filepath.Join(logDirPath, "shim.stderr.log"), unix.O_RDWR|unix.O_CREAT, 0700) |  | ||||||
| } |  | ||||||
| @@ -1,430 +0,0 @@ | |||||||
| //go: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 client |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" |  | ||||||
| 	"io" |  | ||||||
| 	"net" |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
| 	"strconv" |  | ||||||
| 	"strings" |  | ||||||
| 	"sync" |  | ||||||
| 	"syscall" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/events" |  | ||||||
| 	"github.com/containerd/containerd/log" |  | ||||||
| 	ptypes "github.com/containerd/containerd/protobuf/types" |  | ||||||
| 	v1 "github.com/containerd/containerd/runtime/v1" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v1/shim" |  | ||||||
| 	shimapi "github.com/containerd/containerd/runtime/v1/shim/v1" |  | ||||||
| 	"github.com/containerd/containerd/sys" |  | ||||||
| 	"github.com/containerd/ttrpc" |  | ||||||
| 	exec "golang.org/x/sys/execabs" |  | ||||||
| 	"golang.org/x/sys/unix" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var empty = &ptypes.Empty{} |  | ||||||
|  |  | ||||||
| // Opt is an option for a shim client configuration |  | ||||||
| type Opt func(context.Context, shim.Config) (shimapi.ShimService, io.Closer, error) |  | ||||||
|  |  | ||||||
| // WithStart executes a new shim process |  | ||||||
| func WithStart(binary, address, daemonAddress, cgroup string, debug bool, exitHandler func()) Opt { |  | ||||||
| 	return func(ctx context.Context, config shim.Config) (_ shimapi.ShimService, _ io.Closer, err error) { |  | ||||||
| 		socket, err := newSocket(address) |  | ||||||
| 		if err != nil { |  | ||||||
| 			if !eaddrinuse(err) { |  | ||||||
| 				return nil, nil, err |  | ||||||
| 			} |  | ||||||
| 			if err := RemoveSocket(address); err != nil { |  | ||||||
| 				return nil, nil, fmt.Errorf("remove already used socket: %w", err) |  | ||||||
| 			} |  | ||||||
| 			if socket, err = newSocket(address); err != nil { |  | ||||||
| 				return nil, nil, err |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		f, err := socket.File() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, nil, fmt.Errorf("failed to get fd for socket %s: %w", address, err) |  | ||||||
| 		} |  | ||||||
| 		defer f.Close() |  | ||||||
|  |  | ||||||
| 		stdoutCopy := io.Discard |  | ||||||
| 		stderrCopy := io.Discard |  | ||||||
| 		stdoutLog, err := v1.OpenShimStdoutLog(ctx, config.WorkDir) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, nil, fmt.Errorf("failed to create stdout log: %w", err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		stderrLog, err := v1.OpenShimStderrLog(ctx, config.WorkDir) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, nil, fmt.Errorf("failed to create stderr log: %w", err) |  | ||||||
| 		} |  | ||||||
| 		if debug { |  | ||||||
| 			stdoutCopy = os.Stdout |  | ||||||
| 			stderrCopy = os.Stderr |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		go io.Copy(stdoutCopy, stdoutLog) |  | ||||||
| 		go io.Copy(stderrCopy, stderrLog) |  | ||||||
|  |  | ||||||
| 		cmd, err := newCommand(binary, daemonAddress, debug, config, f, stdoutLog, stderrLog) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, nil, err |  | ||||||
| 		} |  | ||||||
| 		if err := cmd.Start(); err != nil { |  | ||||||
| 			return nil, nil, fmt.Errorf("failed to start shim: %w", err) |  | ||||||
| 		} |  | ||||||
| 		defer func() { |  | ||||||
| 			if err != nil { |  | ||||||
| 				cmd.Process.Kill() |  | ||||||
| 			} |  | ||||||
| 		}() |  | ||||||
| 		go func() { |  | ||||||
| 			cmd.Wait() |  | ||||||
| 			exitHandler() |  | ||||||
| 			if stdoutLog != nil { |  | ||||||
| 				stdoutLog.Close() |  | ||||||
| 			} |  | ||||||
| 			if stderrLog != nil { |  | ||||||
| 				stderrLog.Close() |  | ||||||
| 			} |  | ||||||
| 			socket.Close() |  | ||||||
| 			RemoveSocket(address) |  | ||||||
| 		}() |  | ||||||
| 		log.G(ctx).WithFields(log.Fields{ |  | ||||||
| 			"pid":     cmd.Process.Pid, |  | ||||||
| 			"address": address, |  | ||||||
| 			"debug":   debug, |  | ||||||
| 		}).Infof("shim %s started", binary) |  | ||||||
|  |  | ||||||
| 		if err := writeFile(filepath.Join(config.Path, "address"), address); err != nil { |  | ||||||
| 			return nil, nil, err |  | ||||||
| 		} |  | ||||||
| 		if err := writeFile(filepath.Join(config.Path, "shim.pid"), strconv.Itoa(cmd.Process.Pid)); err != nil { |  | ||||||
| 			return nil, nil, err |  | ||||||
| 		} |  | ||||||
| 		// set shim in cgroup if it is provided |  | ||||||
| 		if cgroup != "" { |  | ||||||
| 			if err := setCgroup(cgroup, cmd); err != nil { |  | ||||||
| 				return nil, nil, err |  | ||||||
| 			} |  | ||||||
| 			log.G(ctx).WithFields(log.Fields{ |  | ||||||
| 				"pid":     cmd.Process.Pid, |  | ||||||
| 				"address": address, |  | ||||||
| 			}).Infof("shim placed in cgroup %s", cgroup) |  | ||||||
| 		} |  | ||||||
| 		if err = setupOOMScore(cmd.Process.Pid); err != nil { |  | ||||||
| 			return nil, nil, err |  | ||||||
| 		} |  | ||||||
| 		c, clo, err := WithConnect(address, func() {})(ctx, config) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, nil, fmt.Errorf("failed to connect: %w", err) |  | ||||||
| 		} |  | ||||||
| 		return c, clo, nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func eaddrinuse(err error) bool { |  | ||||||
| 	cause := errors.Unwrap(err) |  | ||||||
| 	netErr, ok := cause.(*net.OpError) |  | ||||||
| 	if !ok { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	if netErr.Op != "listen" { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	syscallErr, ok := netErr.Err.(*os.SyscallError) |  | ||||||
| 	if !ok { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	errno, ok := syscallErr.Err.(syscall.Errno) |  | ||||||
| 	if !ok { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	return errno == syscall.EADDRINUSE |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // setupOOMScore gets containerd's oom score and adds +1 to it |  | ||||||
| // to ensure a shim has a lower* score than the daemons |  | ||||||
| // if not already at the maximum OOM Score |  | ||||||
| func setupOOMScore(shimPid int) error { |  | ||||||
| 	pid := os.Getpid() |  | ||||||
| 	score, err := sys.GetOOMScoreAdj(pid) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("get daemon OOM score: %w", err) |  | ||||||
| 	} |  | ||||||
| 	shimScore := score + 1 |  | ||||||
| 	if err := sys.AdjustOOMScore(shimPid, shimScore); err != nil { |  | ||||||
| 		return fmt.Errorf("set shim OOM score: %w", err) |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newCommand(binary, daemonAddress string, debug bool, config shim.Config, socket *os.File, stdout, stderr io.Writer) (*exec.Cmd, error) { |  | ||||||
| 	selfExe, err := os.Executable() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	args := []string{ |  | ||||||
| 		"-namespace", config.Namespace, |  | ||||||
| 		"-workdir", config.WorkDir, |  | ||||||
| 		"-address", daemonAddress, |  | ||||||
| 		"-containerd-binary", selfExe, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if config.RuntimeRoot != "" { |  | ||||||
| 		args = append(args, "-runtime-root", config.RuntimeRoot) |  | ||||||
| 	} |  | ||||||
| 	if config.SystemdCgroup { |  | ||||||
| 		args = append(args, "-systemd-cgroup") |  | ||||||
| 	} |  | ||||||
| 	if debug { |  | ||||||
| 		args = append(args, "-debug") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	cmd := exec.Command(binary, args...) |  | ||||||
| 	cmd.Dir = config.Path |  | ||||||
| 	// make sure the shim can be re-parented to system init |  | ||||||
| 	// and is cloned in a new mount namespace because the overlay/filesystems |  | ||||||
| 	// will be mounted by the shim |  | ||||||
| 	cmd.SysProcAttr = getSysProcAttr() |  | ||||||
| 	cmd.ExtraFiles = append(cmd.ExtraFiles, socket) |  | ||||||
| 	cmd.Env = append(os.Environ(), "GOMAXPROCS=2") |  | ||||||
| 	cmd.Stdout = stdout |  | ||||||
| 	cmd.Stderr = stderr |  | ||||||
| 	return cmd, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // writeFile writes a address file atomically |  | ||||||
| func writeFile(path, address string) error { |  | ||||||
| 	path, err := filepath.Abs(path) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	tempPath := filepath.Join(filepath.Dir(path), fmt.Sprintf(".%s", filepath.Base(path))) |  | ||||||
| 	f, err := os.OpenFile(tempPath, os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_SYNC, 0666) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	_, err = f.WriteString(address) |  | ||||||
| 	f.Close() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	return os.Rename(tempPath, path) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	abstractSocketPrefix = "\x00" |  | ||||||
| 	socketPathLimit      = 106 |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type socket string |  | ||||||
|  |  | ||||||
| func (s socket) isAbstract() bool { |  | ||||||
| 	return !strings.HasPrefix(string(s), "unix://") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s socket) path() string { |  | ||||||
| 	path := strings.TrimPrefix(string(s), "unix://") |  | ||||||
| 	// if there was no trim performed, we assume an abstract socket |  | ||||||
| 	if len(path) == len(s) { |  | ||||||
| 		path = abstractSocketPrefix + path |  | ||||||
| 	} |  | ||||||
| 	return path |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newSocket(address string) (*net.UnixListener, error) { |  | ||||||
| 	if len(address) > socketPathLimit { |  | ||||||
| 		return nil, fmt.Errorf("%q: unix socket path too long (> %d)", address, socketPathLimit) |  | ||||||
| 	} |  | ||||||
| 	var ( |  | ||||||
| 		sock = socket(address) |  | ||||||
| 		path = sock.path() |  | ||||||
| 	) |  | ||||||
| 	if !sock.isAbstract() { |  | ||||||
| 		if err := os.MkdirAll(filepath.Dir(path), 0600); err != nil { |  | ||||||
| 			return nil, fmt.Errorf("%s: %w", path, err) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	l, err := net.Listen("unix", path) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("failed to listen to unix socket %q (abstract: %t): %w", address, sock.isAbstract(), err) |  | ||||||
| 	} |  | ||||||
| 	if err := os.Chmod(path, 0600); err != nil { |  | ||||||
| 		l.Close() |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return l.(*net.UnixListener), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // RemoveSocket removes the socket at the specified address if |  | ||||||
| // it exists on the filesystem |  | ||||||
| func RemoveSocket(address string) error { |  | ||||||
| 	sock := socket(address) |  | ||||||
| 	if !sock.isAbstract() { |  | ||||||
| 		return os.Remove(sock.path()) |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // AnonDialer returns a dialer for a socket |  | ||||||
| // |  | ||||||
| // NOTE: It is only used for testing. |  | ||||||
| func AnonDialer(address string, timeout time.Duration) (net.Conn, error) { |  | ||||||
| 	return anonDialer(address, timeout) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func connect(address string, d func(string, time.Duration) (net.Conn, error)) (net.Conn, error) { |  | ||||||
| 	return d(address, 100*time.Second) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func anonDialer(address string, timeout time.Duration) (net.Conn, error) { |  | ||||||
| 	return net.DialTimeout("unix", socket(address).path(), timeout) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // WithConnect connects to an existing shim |  | ||||||
| func WithConnect(address string, onClose func()) Opt { |  | ||||||
| 	return func(ctx context.Context, config shim.Config) (shimapi.ShimService, io.Closer, error) { |  | ||||||
| 		conn, err := connect(address, anonDialer) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, nil, err |  | ||||||
| 		} |  | ||||||
| 		client := ttrpc.NewClient(conn, ttrpc.WithOnClose(onClose)) |  | ||||||
| 		return shimapi.NewShimClient(client), conn, nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // WithLocal uses an in process shim |  | ||||||
| func WithLocal(publisher events.Publisher) func(context.Context, shim.Config) (shimapi.ShimService, io.Closer, error) { |  | ||||||
| 	return func(ctx context.Context, config shim.Config) (shimapi.ShimService, io.Closer, error) { |  | ||||||
| 		service, err := shim.NewService(config, publisher) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, nil, err |  | ||||||
| 		} |  | ||||||
| 		return shim.NewLocal(service), nil, nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // New returns a new shim client |  | ||||||
| func New(ctx context.Context, config shim.Config, opt Opt) (*Client, error) { |  | ||||||
| 	s, c, err := opt(ctx, config) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &Client{ |  | ||||||
| 		ShimService: s, |  | ||||||
| 		c:           c, |  | ||||||
| 		exitCh:      make(chan struct{}), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Client is a shim client containing the connection to a shim |  | ||||||
| type Client struct { |  | ||||||
| 	shimapi.ShimService |  | ||||||
|  |  | ||||||
| 	c        io.Closer |  | ||||||
| 	exitCh   chan struct{} |  | ||||||
| 	exitOnce sync.Once |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // IsAlive returns true if the shim can be contacted. |  | ||||||
| // NOTE: a negative answer doesn't mean that the process is gone. |  | ||||||
| func (c *Client) IsAlive(ctx context.Context) (bool, error) { |  | ||||||
| 	_, err := c.ShimInfo(ctx, empty) |  | ||||||
| 	if err != nil { |  | ||||||
| 		// TODO(stevvooe): There are some error conditions that need to be |  | ||||||
| 		// handle with unix sockets existence to give the right answer here. |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
| 	return true, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // StopShim signals the shim to exit and wait for the process to disappear |  | ||||||
| func (c *Client) StopShim(ctx context.Context) error { |  | ||||||
| 	return c.signalShim(ctx, unix.SIGTERM) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // KillShim kills the shim forcefully and wait for the process to disappear |  | ||||||
| func (c *Client) KillShim(ctx context.Context) error { |  | ||||||
| 	return c.signalShim(ctx, unix.SIGKILL) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Close the client connection |  | ||||||
| func (c *Client) Close() error { |  | ||||||
| 	if c.c == nil { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	return c.c.Close() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *Client) signalShim(ctx context.Context, sig syscall.Signal) error { |  | ||||||
| 	info, err := c.ShimInfo(ctx, empty) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	pid := int(info.ShimPid) |  | ||||||
| 	// make sure we don't kill ourselves if we are running a local shim |  | ||||||
| 	if os.Getpid() == pid { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	if err := unix.Kill(pid, sig); err != nil && err != unix.ESRCH { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	// wait for shim to die after being signaled |  | ||||||
| 	select { |  | ||||||
| 	case <-ctx.Done(): |  | ||||||
| 		return ctx.Err() |  | ||||||
| 	case <-c.waitForExit(ctx, pid): |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *Client) waitForExit(ctx context.Context, pid int) <-chan struct{} { |  | ||||||
| 	go c.exitOnce.Do(func() { |  | ||||||
| 		defer close(c.exitCh) |  | ||||||
|  |  | ||||||
| 		ticker := time.NewTicker(10 * time.Millisecond) |  | ||||||
| 		defer ticker.Stop() |  | ||||||
|  |  | ||||||
| 		for { |  | ||||||
| 			// use kill(pid, 0) here because the shim could have been reparented |  | ||||||
| 			// and we are no longer able to waitpid(pid, ...) on the shim |  | ||||||
| 			if err := unix.Kill(pid, 0); err == unix.ESRCH { |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			select { |  | ||||||
| 			case <-ticker.C: |  | ||||||
| 			case <-ctx.Done(): |  | ||||||
| 				log.G(ctx).WithField("pid", pid).Warn("timed out while waiting for shim to exit") |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
| 	return c.exitCh |  | ||||||
| } |  | ||||||
| @@ -1,42 +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 client |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"syscall" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/cgroups/v3/cgroup1" |  | ||||||
| 	exec "golang.org/x/sys/execabs" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func getSysProcAttr() *syscall.SysProcAttr { |  | ||||||
| 	return &syscall.SysProcAttr{ |  | ||||||
| 		Setpgid: true, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func setCgroup(cgroupPath string, cmd *exec.Cmd) error { |  | ||||||
| 	cg, err := cgroup1.Load(cgroup1.StaticPath(cgroupPath)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("failed to load cgroup %s: %w", cgroupPath, err) |  | ||||||
| 	} |  | ||||||
| 	if err := cg.AddProc(uint64(cmd.Process.Pid)); err != nil { |  | ||||||
| 		return fmt.Errorf("failed to join cgroup %s: %w", cgroupPath, err) |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| //go:build !linux && !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 client |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"syscall" |  | ||||||
|  |  | ||||||
| 	exec "golang.org/x/sys/execabs" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func getSysProcAttr() *syscall.SysProcAttr { |  | ||||||
| 	return &syscall.SysProcAttr{ |  | ||||||
| 		Setpgid: true, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func setCgroup(cgroupPath string, cmd *exec.Cmd) error { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,107 +0,0 @@ | |||||||
| //go: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 shim |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"path/filepath" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/mount" |  | ||||||
| 	ptypes "github.com/containerd/containerd/protobuf/types" |  | ||||||
| 	shimapi "github.com/containerd/containerd/runtime/v1/shim/v1" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // NewLocal returns a shim client implementation for issue commands to a shim |  | ||||||
| func NewLocal(s *Service) shimapi.ShimService { |  | ||||||
| 	return &local{ |  | ||||||
| 		s: s, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type local struct { |  | ||||||
| 	s *Service |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) Create(ctx context.Context, in *shimapi.CreateTaskRequest) (*shimapi.CreateTaskResponse, error) { |  | ||||||
| 	return c.s.Create(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) Start(ctx context.Context, in *shimapi.StartRequest) (*shimapi.StartResponse, error) { |  | ||||||
| 	return c.s.Start(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) Delete(ctx context.Context, in *ptypes.Empty) (*shimapi.DeleteResponse, error) { |  | ||||||
| 	// make sure we unmount the containers rootfs for this local |  | ||||||
| 	if err := mount.Unmount(filepath.Join(c.s.config.Path, "rootfs"), 0); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return c.s.Delete(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) DeleteProcess(ctx context.Context, in *shimapi.DeleteProcessRequest) (*shimapi.DeleteResponse, error) { |  | ||||||
| 	return c.s.DeleteProcess(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) Exec(ctx context.Context, in *shimapi.ExecProcessRequest) (*ptypes.Empty, error) { |  | ||||||
| 	return c.s.Exec(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) ResizePty(ctx context.Context, in *shimapi.ResizePtyRequest) (*ptypes.Empty, error) { |  | ||||||
| 	return c.s.ResizePty(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) State(ctx context.Context, in *shimapi.StateRequest) (*shimapi.StateResponse, error) { |  | ||||||
| 	return c.s.State(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) Pause(ctx context.Context, in *ptypes.Empty) (*ptypes.Empty, error) { |  | ||||||
| 	return c.s.Pause(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) Resume(ctx context.Context, in *ptypes.Empty) (*ptypes.Empty, error) { |  | ||||||
| 	return c.s.Resume(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) Kill(ctx context.Context, in *shimapi.KillRequest) (*ptypes.Empty, error) { |  | ||||||
| 	return c.s.Kill(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) ListPids(ctx context.Context, in *shimapi.ListPidsRequest) (*shimapi.ListPidsResponse, error) { |  | ||||||
| 	return c.s.ListPids(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) CloseIO(ctx context.Context, in *shimapi.CloseIORequest) (*ptypes.Empty, error) { |  | ||||||
| 	return c.s.CloseIO(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) Checkpoint(ctx context.Context, in *shimapi.CheckpointTaskRequest) (*ptypes.Empty, error) { |  | ||||||
| 	return c.s.Checkpoint(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) ShimInfo(ctx context.Context, in *ptypes.Empty) (*shimapi.ShimInfoResponse, error) { |  | ||||||
| 	return c.s.ShimInfo(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) Update(ctx context.Context, in *shimapi.UpdateTaskRequest) (*ptypes.Empty, error) { |  | ||||||
| 	return c.s.Update(ctx, in) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *local) Wait(ctx context.Context, in *shimapi.WaitRequest) (*shimapi.WaitResponse, error) { |  | ||||||
| 	return c.s.Wait(ctx, in) |  | ||||||
| } |  | ||||||
| @@ -1,679 +0,0 @@ | |||||||
| //go: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 shim |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
| 	"sync" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/console" |  | ||||||
| 	eventstypes "github.com/containerd/containerd/api/events" |  | ||||||
| 	"github.com/containerd/containerd/api/types/task" |  | ||||||
| 	"github.com/containerd/containerd/errdefs" |  | ||||||
| 	"github.com/containerd/containerd/events" |  | ||||||
| 	"github.com/containerd/containerd/log" |  | ||||||
| 	"github.com/containerd/containerd/mount" |  | ||||||
| 	"github.com/containerd/containerd/namespaces" |  | ||||||
| 	"github.com/containerd/containerd/pkg/process" |  | ||||||
| 	"github.com/containerd/containerd/pkg/stdio" |  | ||||||
| 	"github.com/containerd/containerd/protobuf" |  | ||||||
| 	ptypes "github.com/containerd/containerd/protobuf/types" |  | ||||||
| 	"github.com/containerd/containerd/runtime" |  | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	shimapi "github.com/containerd/containerd/runtime/v1/shim/v1" |  | ||||||
| 	"github.com/containerd/containerd/sys/reaper" |  | ||||||
| 	runc "github.com/containerd/go-runc" |  | ||||||
| 	"github.com/containerd/typeurl/v2" |  | ||||||
| 	specs "github.com/opencontainers/runtime-spec/specs-go" |  | ||||||
| 	"github.com/sirupsen/logrus" |  | ||||||
| 	"google.golang.org/grpc/codes" |  | ||||||
| 	"google.golang.org/grpc/status" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	empty   = &ptypes.Empty{} |  | ||||||
| 	bufPool = sync.Pool{ |  | ||||||
| 		New: func() interface{} { |  | ||||||
| 			buffer := make([]byte, 4096) |  | ||||||
| 			return &buffer |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Config contains shim specific configuration |  | ||||||
| type Config struct { |  | ||||||
| 	Path      string |  | ||||||
| 	Namespace string |  | ||||||
| 	WorkDir   string |  | ||||||
| 	// Criu is the path to the criu binary used for checkpoint and restore. |  | ||||||
| 	// |  | ||||||
| 	// Deprecated: runc option --criu is now ignored (with a warning), and the |  | ||||||
| 	// option will be removed entirely in a future release. Users who need a non- |  | ||||||
| 	// standard criu binary should rely on the standard way of looking up binaries |  | ||||||
| 	// in $PATH. |  | ||||||
| 	Criu          string |  | ||||||
| 	RuntimeRoot   string |  | ||||||
| 	SystemdCgroup bool |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewService returns a new shim service that can be used via GRPC |  | ||||||
| func NewService(config Config, publisher events.Publisher) (*Service, error) { |  | ||||||
| 	if config.Namespace == "" { |  | ||||||
| 		return nil, fmt.Errorf("shim namespace cannot be empty") |  | ||||||
| 	} |  | ||||||
| 	ctx := namespaces.WithNamespace(context.Background(), config.Namespace) |  | ||||||
| 	ctx = log.WithLogger(ctx, logrus.WithFields(log.Fields{ |  | ||||||
| 		"namespace": config.Namespace, |  | ||||||
| 		"path":      config.Path, |  | ||||||
| 		"pid":       os.Getpid(), |  | ||||||
| 	})) |  | ||||||
| 	s := &Service{ |  | ||||||
| 		config:    config, |  | ||||||
| 		context:   ctx, |  | ||||||
| 		processes: make(map[string]process.Process), |  | ||||||
| 		events:    make(chan interface{}, 128), |  | ||||||
| 		ec:        reaper.Default.Subscribe(), |  | ||||||
| 	} |  | ||||||
| 	go s.processExits() |  | ||||||
| 	if err := s.initPlatform(); err != nil { |  | ||||||
| 		return nil, fmt.Errorf("failed to initialized platform behavior: %w", err) |  | ||||||
| 	} |  | ||||||
| 	go s.forward(publisher) |  | ||||||
| 	return s, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Service is the shim implementation of a remote shim over GRPC |  | ||||||
| type Service struct { |  | ||||||
| 	mu sync.Mutex |  | ||||||
|  |  | ||||||
| 	config    Config |  | ||||||
| 	context   context.Context |  | ||||||
| 	processes map[string]process.Process |  | ||||||
| 	events    chan interface{} |  | ||||||
| 	platform  stdio.Platform |  | ||||||
| 	ec        chan runc.Exit |  | ||||||
|  |  | ||||||
| 	// Filled by Create() |  | ||||||
| 	id     string |  | ||||||
| 	bundle string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Create a new initial process and container with the underlying OCI runtime |  | ||||||
| func (s *Service) Create(ctx context.Context, r *shimapi.CreateTaskRequest) (_ *shimapi.CreateTaskResponse, err error) { |  | ||||||
| 	var pmounts []process.Mount |  | ||||||
| 	for _, m := range r.Rootfs { |  | ||||||
| 		pmounts = append(pmounts, process.Mount{ |  | ||||||
| 			Type:    m.Type, |  | ||||||
| 			Source:  m.Source, |  | ||||||
| 			Target:  m.Target, |  | ||||||
| 			Options: m.Options, |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	rootfs := "" |  | ||||||
| 	if len(pmounts) > 0 { |  | ||||||
| 		rootfs = filepath.Join(r.Bundle, "rootfs") |  | ||||||
| 		if err := os.Mkdir(rootfs, 0711); err != nil && !os.IsExist(err) { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	config := &process.CreateConfig{ |  | ||||||
| 		ID:               r.ID, |  | ||||||
| 		Bundle:           r.Bundle, |  | ||||||
| 		Runtime:          r.Runtime, |  | ||||||
| 		Rootfs:           pmounts, |  | ||||||
| 		Terminal:         r.Terminal, |  | ||||||
| 		Stdin:            r.Stdin, |  | ||||||
| 		Stdout:           r.Stdout, |  | ||||||
| 		Stderr:           r.Stderr, |  | ||||||
| 		Checkpoint:       r.Checkpoint, |  | ||||||
| 		ParentCheckpoint: r.ParentCheckpoint, |  | ||||||
| 		Options:          r.Options, |  | ||||||
| 	} |  | ||||||
| 	var mounts []mount.Mount |  | ||||||
| 	for _, pm := range pmounts { |  | ||||||
| 		mounts = append(mounts, mount.Mount{ |  | ||||||
| 			Type:    pm.Type, |  | ||||||
| 			Source:  pm.Source, |  | ||||||
| 			Target:  pm.Target, |  | ||||||
| 			Options: pm.Options, |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 	defer func() { |  | ||||||
| 		if err != nil { |  | ||||||
| 			if err2 := mount.UnmountMounts(mounts, rootfs, 0); err2 != nil { |  | ||||||
| 				log.G(ctx).WithError(err2).Warn("Failed to cleanup rootfs mount") |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
| 	if err := mount.All(mounts, rootfs); err != nil { |  | ||||||
| 		return nil, fmt.Errorf("failed to mount rootfs component: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	defer s.mu.Unlock() |  | ||||||
|  |  | ||||||
| 	process, err := newInit( |  | ||||||
| 		ctx, |  | ||||||
| 		s.config.Path, |  | ||||||
| 		s.config.WorkDir, |  | ||||||
| 		s.config.RuntimeRoot, |  | ||||||
| 		s.config.Namespace, |  | ||||||
| 		s.config.SystemdCgroup, |  | ||||||
| 		s.platform, |  | ||||||
| 		config, |  | ||||||
| 		rootfs, |  | ||||||
| 	) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	if err := process.Create(ctx, config); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	// save the main task id and bundle to the shim for additional requests |  | ||||||
| 	s.id = r.ID |  | ||||||
| 	s.bundle = r.Bundle |  | ||||||
| 	pid := process.Pid() |  | ||||||
| 	s.processes[r.ID] = process |  | ||||||
| 	return &shimapi.CreateTaskResponse{ |  | ||||||
| 		Pid: uint32(pid), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Start a process |  | ||||||
| func (s *Service) Start(ctx context.Context, r *shimapi.StartRequest) (*shimapi.StartResponse, error) { |  | ||||||
| 	p, err := s.getExecProcess(r.ID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := p.Start(ctx); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &shimapi.StartResponse{ |  | ||||||
| 		ID:  p.ID(), |  | ||||||
| 		Pid: uint32(p.Pid()), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Delete the initial process and container |  | ||||||
| func (s *Service) Delete(ctx context.Context, r *ptypes.Empty) (*shimapi.DeleteResponse, error) { |  | ||||||
| 	p, err := s.getInitProcess() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := p.Delete(ctx); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	delete(s.processes, s.id) |  | ||||||
| 	s.mu.Unlock() |  | ||||||
| 	s.platform.Close() |  | ||||||
| 	return &shimapi.DeleteResponse{ |  | ||||||
| 		ExitStatus: uint32(p.ExitStatus()), |  | ||||||
| 		ExitedAt:   protobuf.ToTimestamp(p.ExitedAt()), |  | ||||||
| 		Pid:        uint32(p.Pid()), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // DeleteProcess deletes an exec'd process |  | ||||||
| func (s *Service) DeleteProcess(ctx context.Context, r *shimapi.DeleteProcessRequest) (*shimapi.DeleteResponse, error) { |  | ||||||
| 	if r.ID == s.id { |  | ||||||
| 		return nil, status.Errorf(codes.InvalidArgument, "cannot delete init process with DeleteProcess") |  | ||||||
| 	} |  | ||||||
| 	p, err := s.getExecProcess(r.ID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := p.Delete(ctx); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	delete(s.processes, r.ID) |  | ||||||
| 	s.mu.Unlock() |  | ||||||
| 	return &shimapi.DeleteResponse{ |  | ||||||
| 		ExitStatus: uint32(p.ExitStatus()), |  | ||||||
| 		ExitedAt:   protobuf.ToTimestamp(p.ExitedAt()), |  | ||||||
| 		Pid:        uint32(p.Pid()), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Exec an additional process inside the container |  | ||||||
| func (s *Service) Exec(ctx context.Context, r *shimapi.ExecProcessRequest) (*ptypes.Empty, error) { |  | ||||||
| 	s.mu.Lock() |  | ||||||
|  |  | ||||||
| 	if p := s.processes[r.ID]; p != nil { |  | ||||||
| 		s.mu.Unlock() |  | ||||||
| 		return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ID) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	p := s.processes[s.id] |  | ||||||
| 	s.mu.Unlock() |  | ||||||
| 	if p == nil { |  | ||||||
| 		return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	process, err := p.(*process.Init).Exec(ctx, s.config.Path, &process.ExecConfig{ |  | ||||||
| 		ID:       r.ID, |  | ||||||
| 		Terminal: r.Terminal, |  | ||||||
| 		Stdin:    r.Stdin, |  | ||||||
| 		Stdout:   r.Stdout, |  | ||||||
| 		Stderr:   r.Stderr, |  | ||||||
| 		Spec:     r.Spec, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	s.processes[r.ID] = process |  | ||||||
| 	s.mu.Unlock() |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ResizePty of a process |  | ||||||
| func (s *Service) ResizePty(ctx context.Context, r *shimapi.ResizePtyRequest) (*ptypes.Empty, error) { |  | ||||||
| 	if r.ID == "" { |  | ||||||
| 		return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, "id not provided") |  | ||||||
| 	} |  | ||||||
| 	ws := console.WinSize{ |  | ||||||
| 		Width:  uint16(r.Width), |  | ||||||
| 		Height: uint16(r.Height), |  | ||||||
| 	} |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	p := s.processes[r.ID] |  | ||||||
| 	s.mu.Unlock() |  | ||||||
| 	if p == nil { |  | ||||||
| 		return nil, fmt.Errorf("process does not exist %s", r.ID) |  | ||||||
| 	} |  | ||||||
| 	if err := p.Resize(ws); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // State returns runtime state information for a process |  | ||||||
| func (s *Service) State(ctx context.Context, r *shimapi.StateRequest) (*shimapi.StateResponse, error) { |  | ||||||
| 	p, err := s.getExecProcess(r.ID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	st, err := p.Status(ctx) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	status := task.Status_UNKNOWN |  | ||||||
| 	switch st { |  | ||||||
| 	case "created": |  | ||||||
| 		status = task.Status_CREATED |  | ||||||
| 	case "running": |  | ||||||
| 		status = task.Status_RUNNING |  | ||||||
| 	case "stopped": |  | ||||||
| 		status = task.Status_STOPPED |  | ||||||
| 	case "paused": |  | ||||||
| 		status = task.Status_PAUSED |  | ||||||
| 	case "pausing": |  | ||||||
| 		status = task.Status_PAUSING |  | ||||||
| 	} |  | ||||||
| 	sio := p.Stdio() |  | ||||||
| 	return &shimapi.StateResponse{ |  | ||||||
| 		ID:         p.ID(), |  | ||||||
| 		Bundle:     s.bundle, |  | ||||||
| 		Pid:        uint32(p.Pid()), |  | ||||||
| 		Status:     status, |  | ||||||
| 		Stdin:      sio.Stdin, |  | ||||||
| 		Stdout:     sio.Stdout, |  | ||||||
| 		Stderr:     sio.Stderr, |  | ||||||
| 		Terminal:   sio.Terminal, |  | ||||||
| 		ExitStatus: uint32(p.ExitStatus()), |  | ||||||
| 		ExitedAt:   protobuf.ToTimestamp(p.ExitedAt()), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Pause the container |  | ||||||
| func (s *Service) Pause(ctx context.Context, r *ptypes.Empty) (*ptypes.Empty, error) { |  | ||||||
| 	p, err := s.getInitProcess() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := p.(*process.Init).Pause(ctx); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Resume the container |  | ||||||
| func (s *Service) Resume(ctx context.Context, r *ptypes.Empty) (*ptypes.Empty, error) { |  | ||||||
| 	p, err := s.getInitProcess() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := p.(*process.Init).Resume(ctx); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Kill a process with the provided signal |  | ||||||
| func (s *Service) Kill(ctx context.Context, r *shimapi.KillRequest) (*ptypes.Empty, error) { |  | ||||||
| 	if r.ID == "" { |  | ||||||
| 		p, err := s.getInitProcess() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		if err := p.Kill(ctx, r.Signal, r.All); err != nil { |  | ||||||
| 			return nil, errdefs.ToGRPC(err) |  | ||||||
| 		} |  | ||||||
| 		return empty, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	p, err := s.getExecProcess(r.ID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := p.Kill(ctx, r.Signal, r.All); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ListPids returns all pids inside the container |  | ||||||
| func (s *Service) ListPids(ctx context.Context, r *shimapi.ListPidsRequest) (*shimapi.ListPidsResponse, error) { |  | ||||||
| 	pids, err := s.getContainerPids(ctx, r.ID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	var processes []*task.ProcessInfo |  | ||||||
|  |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	defer s.mu.Unlock() |  | ||||||
| 	for _, pid := range pids { |  | ||||||
| 		pInfo := task.ProcessInfo{ |  | ||||||
| 			Pid: pid, |  | ||||||
| 		} |  | ||||||
| 		for _, p := range s.processes { |  | ||||||
| 			if p.Pid() == int(pid) { |  | ||||||
| 				d := &runctypes.ProcessDetails{ |  | ||||||
| 					ExecID: p.ID(), |  | ||||||
| 				} |  | ||||||
| 				a, err := typeurl.MarshalAny(d) |  | ||||||
| 				if err != nil { |  | ||||||
| 					return nil, fmt.Errorf("failed to marshal process %d info: %w", pid, err) |  | ||||||
| 				} |  | ||||||
| 				pInfo.Info = protobuf.FromAny(a) |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		processes = append(processes, &pInfo) |  | ||||||
| 	} |  | ||||||
| 	return &shimapi.ListPidsResponse{ |  | ||||||
| 		Processes: processes, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // CloseIO of a process |  | ||||||
| func (s *Service) CloseIO(ctx context.Context, r *shimapi.CloseIORequest) (*ptypes.Empty, error) { |  | ||||||
| 	p, err := s.getExecProcess(r.ID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if stdin := p.Stdin(); stdin != nil { |  | ||||||
| 		if err := stdin.Close(); err != nil { |  | ||||||
| 			return nil, fmt.Errorf("close stdin: %w", err) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Checkpoint the container |  | ||||||
| func (s *Service) Checkpoint(ctx context.Context, r *shimapi.CheckpointTaskRequest) (*ptypes.Empty, error) { |  | ||||||
| 	p, err := s.getInitProcess() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	var options *runctypes.CheckpointOptions |  | ||||||
| 	if r.Options != nil { |  | ||||||
| 		v, err := typeurl.UnmarshalAny(r.Options) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		options = v.(*runctypes.CheckpointOptions) |  | ||||||
| 	} |  | ||||||
| 	if err := p.(*process.Init).Checkpoint(ctx, &process.CheckpointConfig{ |  | ||||||
| 		Path:                     r.Path, |  | ||||||
| 		Exit:                     options.Exit, |  | ||||||
| 		AllowOpenTCP:             options.OpenTcp, |  | ||||||
| 		AllowExternalUnixSockets: options.ExternalUnixSockets, |  | ||||||
| 		AllowTerminal:            options.Terminal, |  | ||||||
| 		FileLocks:                options.FileLocks, |  | ||||||
| 		EmptyNamespaces:          options.EmptyNamespaces, |  | ||||||
| 		WorkDir:                  options.WorkPath, |  | ||||||
| 	}); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ShimInfo returns shim information such as the shim's pid |  | ||||||
| func (s *Service) ShimInfo(ctx context.Context, r *ptypes.Empty) (*shimapi.ShimInfoResponse, error) { |  | ||||||
| 	return &shimapi.ShimInfoResponse{ |  | ||||||
| 		ShimPid: uint32(os.Getpid()), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Update a running container |  | ||||||
| func (s *Service) Update(ctx context.Context, r *shimapi.UpdateTaskRequest) (*ptypes.Empty, error) { |  | ||||||
| 	p, err := s.getInitProcess() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := p.(*process.Init).Update(ctx, r.Resources); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Wait for a process to exit |  | ||||||
| func (s *Service) Wait(ctx context.Context, r *shimapi.WaitRequest) (*shimapi.WaitResponse, error) { |  | ||||||
| 	p, err := s.getExecProcess(r.ID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	p.Wait() |  | ||||||
|  |  | ||||||
| 	return &shimapi.WaitResponse{ |  | ||||||
| 		ExitStatus: uint32(p.ExitStatus()), |  | ||||||
| 		ExitedAt:   protobuf.ToTimestamp(p.ExitedAt()), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Service) processExits() { |  | ||||||
| 	for e := range s.ec { |  | ||||||
| 		s.checkProcesses(e) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Service) checkProcesses(e runc.Exit) { |  | ||||||
| 	var p process.Process |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	for _, proc := range s.processes { |  | ||||||
| 		if proc.Pid() == e.Pid { |  | ||||||
| 			p = proc |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	s.mu.Unlock() |  | ||||||
| 	if p == nil { |  | ||||||
| 		log.G(s.context).Debugf("process with id:%d wasn't found", e.Pid) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if ip, ok := p.(*process.Init); ok { |  | ||||||
| 		// Ensure all children are killed |  | ||||||
| 		if shouldKillAllOnExit(s.context, s.bundle) { |  | ||||||
| 			if err := ip.KillAll(s.context); err != nil { |  | ||||||
| 				log.G(s.context).WithError(err).WithField("id", ip.ID()). |  | ||||||
| 					Error("failed to kill init's children") |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	p.SetExited(e.Status) |  | ||||||
| 	s.events <- &eventstypes.TaskExit{ |  | ||||||
| 		ContainerID: s.id, |  | ||||||
| 		ID:          p.ID(), |  | ||||||
| 		Pid:         uint32(e.Pid), |  | ||||||
| 		ExitStatus:  uint32(e.Status), |  | ||||||
| 		ExitedAt:    protobuf.ToTimestamp(p.ExitedAt()), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func shouldKillAllOnExit(ctx context.Context, bundlePath string) bool { |  | ||||||
| 	var bundleSpec specs.Spec |  | ||||||
| 	bundleConfigContents, err := os.ReadFile(filepath.Join(bundlePath, "config.json")) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.G(ctx).WithError(err).Error("shouldKillAllOnExit: failed to read config.json") |  | ||||||
| 		return true |  | ||||||
| 	} |  | ||||||
| 	if err := json.Unmarshal(bundleConfigContents, &bundleSpec); err != nil { |  | ||||||
| 		log.G(ctx).WithError(err).Error("shouldKillAllOnExit: failed to unmarshal bundle json") |  | ||||||
| 		return true |  | ||||||
| 	} |  | ||||||
| 	if bundleSpec.Linux != nil { |  | ||||||
| 		for _, ns := range bundleSpec.Linux.Namespaces { |  | ||||||
| 			if ns.Type == specs.PIDNamespace && ns.Path == "" { |  | ||||||
| 				return false |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Service) getContainerPids(ctx context.Context, id string) ([]uint32, error) { |  | ||||||
| 	p, err := s.getInitProcess() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ps, err := p.(*process.Init).Runtime().Ps(ctx, id) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	pids := make([]uint32, 0, len(ps)) |  | ||||||
| 	for _, pid := range ps { |  | ||||||
| 		pids = append(pids, uint32(pid)) |  | ||||||
| 	} |  | ||||||
| 	return pids, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Service) forward(publisher events.Publisher) { |  | ||||||
| 	for e := range s.events { |  | ||||||
| 		if err := publisher.Publish(s.context, getTopic(s.context, e), e); err != nil { |  | ||||||
| 			log.G(s.context).WithError(err).Error("post event") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // getInitProcess returns initial process |  | ||||||
| func (s *Service) getInitProcess() (process.Process, error) { |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	defer s.mu.Unlock() |  | ||||||
|  |  | ||||||
| 	p := s.processes[s.id] |  | ||||||
| 	if p == nil { |  | ||||||
| 		return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") |  | ||||||
| 	} |  | ||||||
| 	return p, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // getExecProcess returns exec process |  | ||||||
| func (s *Service) getExecProcess(id string) (process.Process, error) { |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	defer s.mu.Unlock() |  | ||||||
|  |  | ||||||
| 	p := s.processes[id] |  | ||||||
| 	if p == nil { |  | ||||||
| 		return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process %s does not exist", id) |  | ||||||
| 	} |  | ||||||
| 	return p, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func getTopic(ctx context.Context, e interface{}) string { |  | ||||||
| 	switch e.(type) { |  | ||||||
| 	case *eventstypes.TaskCreate: |  | ||||||
| 		return runtime.TaskCreateEventTopic |  | ||||||
| 	case *eventstypes.TaskStart: |  | ||||||
| 		return runtime.TaskStartEventTopic |  | ||||||
| 	case *eventstypes.TaskOOM: |  | ||||||
| 		return runtime.TaskOOMEventTopic |  | ||||||
| 	case *eventstypes.TaskExit: |  | ||||||
| 		return runtime.TaskExitEventTopic |  | ||||||
| 	case *eventstypes.TaskDelete: |  | ||||||
| 		return runtime.TaskDeleteEventTopic |  | ||||||
| 	case *eventstypes.TaskExecAdded: |  | ||||||
| 		return runtime.TaskExecAddedEventTopic |  | ||||||
| 	case *eventstypes.TaskExecStarted: |  | ||||||
| 		return runtime.TaskExecStartedEventTopic |  | ||||||
| 	case *eventstypes.TaskPaused: |  | ||||||
| 		return runtime.TaskPausedEventTopic |  | ||||||
| 	case *eventstypes.TaskResumed: |  | ||||||
| 		return runtime.TaskResumedEventTopic |  | ||||||
| 	case *eventstypes.TaskCheckpointed: |  | ||||||
| 		return runtime.TaskCheckpointedEventTopic |  | ||||||
| 	default: |  | ||||||
| 		logrus.Warnf("no topic for type %#v", e) |  | ||||||
| 	} |  | ||||||
| 	return runtime.TaskUnknownTopic |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newInit(ctx context.Context, path, workDir, runtimeRoot, namespace string, systemdCgroup bool, platform stdio.Platform, r *process.CreateConfig, rootfs string) (*process.Init, error) { |  | ||||||
| 	options := &runctypes.CreateOptions{} |  | ||||||
| 	if r.Options != nil { |  | ||||||
| 		v, err := typeurl.UnmarshalAny(r.Options) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		options = v.(*runctypes.CreateOptions) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	runtime := process.NewRunc(runtimeRoot, path, namespace, r.Runtime, systemdCgroup) |  | ||||||
| 	p := process.New(r.ID, runtime, stdio.Stdio{ |  | ||||||
| 		Stdin:    r.Stdin, |  | ||||||
| 		Stdout:   r.Stdout, |  | ||||||
| 		Stderr:   r.Stderr, |  | ||||||
| 		Terminal: r.Terminal, |  | ||||||
| 	}) |  | ||||||
| 	p.Bundle = r.Bundle |  | ||||||
| 	p.Platform = platform |  | ||||||
| 	p.Rootfs = rootfs |  | ||||||
| 	p.WorkDir = workDir |  | ||||||
| 	p.IoUID = int(options.IoUid) |  | ||||||
| 	p.IoGID = int(options.IoGid) |  | ||||||
| 	p.NoPivotRoot = options.NoPivotRoot |  | ||||||
| 	p.NoNewKeyring = options.NoNewKeyring |  | ||||||
| 	p.CriuWorkPath = options.CriuWorkPath |  | ||||||
| 	if p.CriuWorkPath == "" { |  | ||||||
| 		// if criu work path not set, use container WorkDir |  | ||||||
| 		p.CriuWorkPath = p.WorkDir |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return p, nil |  | ||||||
| } |  | ||||||
| @@ -1,193 +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 shim |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" |  | ||||||
| 	"io" |  | ||||||
| 	"net/url" |  | ||||||
| 	"os" |  | ||||||
| 	"sync" |  | ||||||
| 	"syscall" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/console" |  | ||||||
| 	"github.com/containerd/containerd/namespaces" |  | ||||||
| 	"github.com/containerd/containerd/pkg/process" |  | ||||||
| 	"github.com/containerd/fifo" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type linuxPlatform struct { |  | ||||||
| 	epoller *console.Epoller |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *linuxPlatform) CopyConsole(ctx context.Context, console console.Console, id, stdin, stdout, stderr string, wg *sync.WaitGroup) (cons console.Console, retErr error) { |  | ||||||
| 	if p.epoller == nil { |  | ||||||
| 		return nil, errors.New("uninitialized epoller") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	epollConsole, err := p.epoller.Add(console) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	var cwg sync.WaitGroup |  | ||||||
|  |  | ||||||
| 	if stdin != "" { |  | ||||||
| 		in, err := fifo.OpenFifo(ctx, stdin, syscall.O_RDONLY, 0) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		cwg.Add(1) |  | ||||||
| 		go func() { |  | ||||||
| 			cwg.Done() |  | ||||||
| 			bp := bufPool.Get().(*[]byte) |  | ||||||
| 			defer bufPool.Put(bp) |  | ||||||
| 			io.CopyBuffer(epollConsole, in, *bp) |  | ||||||
| 			// we need to shutdown epollConsole when pipe broken |  | ||||||
| 			epollConsole.Shutdown(p.epoller.CloseConsole) |  | ||||||
| 			epollConsole.Close() |  | ||||||
| 			in.Close() |  | ||||||
| 		}() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	uri, err := url.Parse(stdout) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("unable to parse stdout uri: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	switch uri.Scheme { |  | ||||||
| 	case "binary": |  | ||||||
| 		ns, err := namespaces.NamespaceRequired(ctx) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		cmd := process.NewBinaryCmd(uri, id, ns) |  | ||||||
|  |  | ||||||
| 		// In case of unexpected errors during logging binary start, close open pipes |  | ||||||
| 		var filesToClose []*os.File |  | ||||||
|  |  | ||||||
| 		defer func() { |  | ||||||
| 			if retErr != nil { |  | ||||||
| 				process.CloseFiles(filesToClose...) |  | ||||||
| 			} |  | ||||||
| 		}() |  | ||||||
|  |  | ||||||
| 		// Create pipe to be used by logging binary for Stdout |  | ||||||
| 		outR, outW, err := os.Pipe() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, fmt.Errorf("failed to create stdout pipes: %w", err) |  | ||||||
| 		} |  | ||||||
| 		filesToClose = append(filesToClose, outR) |  | ||||||
|  |  | ||||||
| 		// Stderr is created for logging binary but unused when terminal is true |  | ||||||
| 		serrR, _, err := os.Pipe() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, fmt.Errorf("failed to create stderr pipes: %w", err) |  | ||||||
| 		} |  | ||||||
| 		filesToClose = append(filesToClose, serrR) |  | ||||||
|  |  | ||||||
| 		r, w, err := os.Pipe() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		filesToClose = append(filesToClose, r) |  | ||||||
|  |  | ||||||
| 		cmd.ExtraFiles = append(cmd.ExtraFiles, outR, serrR, w) |  | ||||||
|  |  | ||||||
| 		wg.Add(1) |  | ||||||
| 		cwg.Add(1) |  | ||||||
| 		go func() { |  | ||||||
| 			cwg.Done() |  | ||||||
| 			io.Copy(outW, epollConsole) |  | ||||||
| 			outW.Close() |  | ||||||
| 			wg.Done() |  | ||||||
| 		}() |  | ||||||
|  |  | ||||||
| 		if err := cmd.Start(); err != nil { |  | ||||||
| 			return nil, fmt.Errorf("failed to start logging binary process: %w", err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Close our side of the pipe after start |  | ||||||
| 		if err := w.Close(); err != nil { |  | ||||||
| 			return nil, fmt.Errorf("failed to close write pipe after start: %w", err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Wait for the logging binary to be ready |  | ||||||
| 		b := make([]byte, 1) |  | ||||||
| 		if _, err := r.Read(b); err != nil && err != io.EOF { |  | ||||||
| 			return nil, fmt.Errorf("failed to read from logging binary: %w", err) |  | ||||||
| 		} |  | ||||||
| 		cwg.Wait() |  | ||||||
|  |  | ||||||
| 	default: |  | ||||||
| 		outw, err := fifo.OpenFifo(ctx, stdout, syscall.O_WRONLY, 0) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		outr, err := fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY, 0) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		wg.Add(1) |  | ||||||
| 		cwg.Add(1) |  | ||||||
| 		go func() { |  | ||||||
| 			cwg.Done() |  | ||||||
| 			p := bufPool.Get().(*[]byte) |  | ||||||
| 			defer bufPool.Put(p) |  | ||||||
| 			io.CopyBuffer(outw, epollConsole, *p) |  | ||||||
| 			outw.Close() |  | ||||||
| 			outr.Close() |  | ||||||
| 			wg.Done() |  | ||||||
| 		}() |  | ||||||
| 		cwg.Wait() |  | ||||||
| 	} |  | ||||||
| 	return epollConsole, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *linuxPlatform) ShutdownConsole(ctx context.Context, cons console.Console) error { |  | ||||||
| 	if p.epoller == nil { |  | ||||||
| 		return errors.New("uninitialized epoller") |  | ||||||
| 	} |  | ||||||
| 	epollConsole, ok := cons.(*console.EpollConsole) |  | ||||||
| 	if !ok { |  | ||||||
| 		return fmt.Errorf("expected EpollConsole, got %#v", cons) |  | ||||||
| 	} |  | ||||||
| 	return epollConsole.Shutdown(p.epoller.CloseConsole) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *linuxPlatform) Close() error { |  | ||||||
| 	return p.epoller.Close() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // initialize a single epoll fd to manage our consoles. `initPlatform` should |  | ||||||
| // only be called once. |  | ||||||
| func (s *Service) initPlatform() error { |  | ||||||
| 	if s.platform != nil { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	epoller, err := console.NewEpoller() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("failed to initialize epoller: %w", err) |  | ||||||
| 	} |  | ||||||
| 	s.platform = &linuxPlatform{ |  | ||||||
| 		epoller: epoller, |  | ||||||
| 	} |  | ||||||
| 	go epoller.Wait() |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,160 +0,0 @@ | |||||||
| //go:build !windows && !linux |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|    Copyright The containerd Authors. |  | ||||||
|  |  | ||||||
|    Licensed under the Apache License, Version 2.0 (the "License"); |  | ||||||
|    you may not use this file except in compliance with the License. |  | ||||||
|    You may obtain a copy of the License at |  | ||||||
|  |  | ||||||
|        http://www.apache.org/licenses/LICENSE-2.0 |  | ||||||
|  |  | ||||||
|    Unless required by applicable law or agreed to in writing, software |  | ||||||
|    distributed under the License is distributed on an "AS IS" BASIS, |  | ||||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |  | ||||||
|    See the License for the specific language governing permissions and |  | ||||||
|    limitations under the License. |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| package shim |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"fmt" |  | ||||||
| 	"io" |  | ||||||
| 	"net/url" |  | ||||||
| 	"os" |  | ||||||
| 	"sync" |  | ||||||
| 	"syscall" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/console" |  | ||||||
| 	"github.com/containerd/containerd/namespaces" |  | ||||||
| 	"github.com/containerd/containerd/pkg/process" |  | ||||||
| 	"github.com/containerd/fifo" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type unixPlatform struct { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *unixPlatform) CopyConsole(ctx context.Context, console console.Console, id, stdin, stdout, stderr string, wg *sync.WaitGroup) (cons console.Console, retErr error) { |  | ||||||
| 	var cwg sync.WaitGroup |  | ||||||
| 	if stdin != "" { |  | ||||||
| 		in, err := fifo.OpenFifo(ctx, stdin, syscall.O_RDONLY, 0) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		cwg.Add(1) |  | ||||||
| 		go func() { |  | ||||||
| 			cwg.Done() |  | ||||||
| 			p := bufPool.Get().(*[]byte) |  | ||||||
| 			defer bufPool.Put(p) |  | ||||||
|  |  | ||||||
| 			io.CopyBuffer(console, in, *p) |  | ||||||
| 		}() |  | ||||||
| 	} |  | ||||||
| 	uri, err := url.Parse(stdout) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("unable to parse stdout uri: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	switch uri.Scheme { |  | ||||||
| 	case "binary": |  | ||||||
| 		ns, err := namespaces.NamespaceRequired(ctx) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		cmd := process.NewBinaryCmd(uri, id, ns) |  | ||||||
|  |  | ||||||
| 		// In case of unexpected errors during logging binary start, close open pipes |  | ||||||
| 		var filesToClose []*os.File |  | ||||||
|  |  | ||||||
| 		defer func() { |  | ||||||
| 			if retErr != nil { |  | ||||||
| 				process.CloseFiles(filesToClose...) |  | ||||||
| 			} |  | ||||||
| 		}() |  | ||||||
|  |  | ||||||
| 		// Create pipe to be used by logging binary for Stdout |  | ||||||
| 		outR, outW, err := os.Pipe() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, fmt.Errorf("failed to create stdout pipes: %w", err) |  | ||||||
| 		} |  | ||||||
| 		filesToClose = append(filesToClose, outR) |  | ||||||
|  |  | ||||||
| 		// Stderr is created for logging binary but unused when terminal is true |  | ||||||
| 		serrR, _, err := os.Pipe() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, fmt.Errorf("failed to create stderr pipes: %w", err) |  | ||||||
| 		} |  | ||||||
| 		filesToClose = append(filesToClose, serrR) |  | ||||||
|  |  | ||||||
| 		r, w, err := os.Pipe() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		filesToClose = append(filesToClose, r) |  | ||||||
|  |  | ||||||
| 		cmd.ExtraFiles = append(cmd.ExtraFiles, outR, serrR, w) |  | ||||||
|  |  | ||||||
| 		wg.Add(1) |  | ||||||
| 		cwg.Add(1) |  | ||||||
| 		go func() { |  | ||||||
| 			cwg.Done() |  | ||||||
| 			io.Copy(outW, console) |  | ||||||
| 			outW.Close() |  | ||||||
| 			wg.Done() |  | ||||||
| 		}() |  | ||||||
|  |  | ||||||
| 		if err := cmd.Start(); err != nil { |  | ||||||
| 			return nil, fmt.Errorf("failed to start logging binary process: %w", err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Close our side of the pipe after start |  | ||||||
| 		if err := w.Close(); err != nil { |  | ||||||
| 			return nil, fmt.Errorf("failed to close write pipe after start: %w", err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Wait for the logging binary to be ready |  | ||||||
| 		b := make([]byte, 1) |  | ||||||
| 		if _, err := r.Read(b); err != nil && err != io.EOF { |  | ||||||
| 			return nil, fmt.Errorf("failed to read from logging binary: %w", err) |  | ||||||
| 		} |  | ||||||
| 		cwg.Wait() |  | ||||||
|  |  | ||||||
| 	default: |  | ||||||
| 		outw, err := fifo.OpenFifo(ctx, stdout, syscall.O_WRONLY, 0) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		outr, err := fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY, 0) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		wg.Add(1) |  | ||||||
| 		cwg.Add(1) |  | ||||||
| 		go func() { |  | ||||||
| 			cwg.Done() |  | ||||||
| 			p := bufPool.Get().(*[]byte) |  | ||||||
| 			defer bufPool.Put(p) |  | ||||||
| 			io.CopyBuffer(outw, console, *p) |  | ||||||
| 			outw.Close() |  | ||||||
| 			outr.Close() |  | ||||||
| 			wg.Done() |  | ||||||
| 		}() |  | ||||||
| 		cwg.Wait() |  | ||||||
| 	} |  | ||||||
| 	return console, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *unixPlatform) ShutdownConsole(ctx context.Context, cons console.Console) error { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *unixPlatform) Close() error { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Service) initPlatform() error { |  | ||||||
| 	s.platform = &unixPlatform{} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,17 +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 shim |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,180 +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. |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| syntax = "proto3"; |  | ||||||
|  |  | ||||||
| package containerd.runtime.linux.shim.v1; |  | ||||||
|  |  | ||||||
| import "google/protobuf/any.proto"; |  | ||||||
| import "google/protobuf/empty.proto"; |  | ||||||
| import "google/protobuf/timestamp.proto"; |  | ||||||
| import "github.com/containerd/containerd/api/types/mount.proto"; |  | ||||||
| import "github.com/containerd/containerd/api/types/task/task.proto"; |  | ||||||
|  |  | ||||||
| option go_package = "github.com/containerd/containerd/runtime/v1/shim/v1;shim"; |  | ||||||
|  |  | ||||||
| // Shim service is launched for each container and is responsible for owning the IO |  | ||||||
| // for the container and its additional processes.  The shim is also the parent of |  | ||||||
| // each container and allows reattaching to the IO and receiving the exit status |  | ||||||
| // for the container processes. |  | ||||||
| service Shim { |  | ||||||
| 	// State returns shim and task state information. |  | ||||||
| 	rpc State(StateRequest) returns (StateResponse); |  | ||||||
|  |  | ||||||
| 	rpc Create(CreateTaskRequest) returns (CreateTaskResponse); |  | ||||||
|  |  | ||||||
| 	rpc Start(StartRequest) returns (StartResponse); |  | ||||||
|  |  | ||||||
| 	rpc Delete(google.protobuf.Empty) returns (DeleteResponse); |  | ||||||
|  |  | ||||||
| 	rpc DeleteProcess(DeleteProcessRequest) returns (DeleteResponse); |  | ||||||
|  |  | ||||||
| 	rpc ListPids(ListPidsRequest) returns (ListPidsResponse); |  | ||||||
|  |  | ||||||
| 	rpc Pause(google.protobuf.Empty) returns (google.protobuf.Empty); |  | ||||||
|  |  | ||||||
| 	rpc Resume(google.protobuf.Empty) returns (google.protobuf.Empty); |  | ||||||
|  |  | ||||||
| 	rpc Checkpoint(CheckpointTaskRequest) returns (google.protobuf.Empty); |  | ||||||
|  |  | ||||||
| 	rpc Kill(KillRequest) returns (google.protobuf.Empty); |  | ||||||
|  |  | ||||||
| 	rpc Exec(ExecProcessRequest) returns (google.protobuf.Empty); |  | ||||||
|  |  | ||||||
| 	rpc ResizePty(ResizePtyRequest) returns (google.protobuf.Empty); |  | ||||||
|  |  | ||||||
| 	rpc CloseIO(CloseIORequest) returns (google.protobuf.Empty); |  | ||||||
|  |  | ||||||
| 	// ShimInfo returns information about the shim. |  | ||||||
| 	rpc ShimInfo(google.protobuf.Empty) returns (ShimInfoResponse); |  | ||||||
|  |  | ||||||
| 	rpc Update(UpdateTaskRequest) returns (google.protobuf.Empty); |  | ||||||
|  |  | ||||||
| 	rpc Wait(WaitRequest) returns (WaitResponse); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message CreateTaskRequest { |  | ||||||
| 	string id = 1; |  | ||||||
| 	string bundle = 2; |  | ||||||
| 	string runtime = 3; |  | ||||||
| 	repeated containerd.types.Mount rootfs = 4; |  | ||||||
| 	bool terminal = 5; |  | ||||||
| 	string stdin = 6; |  | ||||||
| 	string stdout = 7; |  | ||||||
| 	string stderr = 8; |  | ||||||
| 	string checkpoint = 9; |  | ||||||
| 	string parent_checkpoint = 10; |  | ||||||
| 	google.protobuf.Any options = 11; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message CreateTaskResponse { |  | ||||||
| 	uint32 pid = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message DeleteResponse { |  | ||||||
| 	uint32 pid = 1; |  | ||||||
| 	uint32 exit_status = 2; |  | ||||||
| 	google.protobuf.Timestamp exited_at = 3; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message DeleteProcessRequest { |  | ||||||
| 	string id = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message ExecProcessRequest { |  | ||||||
| 	string id = 1; |  | ||||||
| 	bool terminal = 2; |  | ||||||
| 	string stdin = 3; |  | ||||||
| 	string stdout = 4; |  | ||||||
| 	string stderr = 5; |  | ||||||
| 	google.protobuf.Any spec = 6; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message ExecProcessResponse { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message ResizePtyRequest { |  | ||||||
| 	string id = 1; |  | ||||||
| 	uint32 width = 2; |  | ||||||
| 	uint32 height = 3; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message StateRequest { |  | ||||||
| 	string id = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message StateResponse { |  | ||||||
| 	string id = 1; |  | ||||||
| 	string bundle = 2; |  | ||||||
| 	uint32 pid = 3; |  | ||||||
| 	containerd.v1.types.Status status = 4; |  | ||||||
| 	string stdin = 5; |  | ||||||
| 	string stdout = 6; |  | ||||||
| 	string stderr = 7; |  | ||||||
| 	bool terminal = 8; |  | ||||||
| 	uint32 exit_status = 9; |  | ||||||
| 	google.protobuf.Timestamp exited_at = 10; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message KillRequest { |  | ||||||
| 	string id = 1; |  | ||||||
| 	uint32 signal = 2; |  | ||||||
| 	bool all = 3; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message CloseIORequest { |  | ||||||
| 	string id = 1; |  | ||||||
| 	bool stdin = 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message ListPidsRequest { |  | ||||||
| 	string id = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message ListPidsResponse { |  | ||||||
| 	repeated containerd.v1.types.ProcessInfo processes = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message CheckpointTaskRequest { |  | ||||||
| 	string path = 1; |  | ||||||
| 	google.protobuf.Any options = 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message ShimInfoResponse { |  | ||||||
| 	uint32 shim_pid = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message UpdateTaskRequest { |  | ||||||
| 	google.protobuf.Any resources = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message StartRequest { |  | ||||||
| 	string id = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message StartResponse { |  | ||||||
| 	string id = 1; |  | ||||||
| 	uint32 pid = 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message WaitRequest { |  | ||||||
| 	string id = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message WaitResponse { |  | ||||||
| 	uint32 exit_status = 1; |  | ||||||
| 	google.protobuf.Timestamp exited_at = 2; |  | ||||||
| } |  | ||||||
| @@ -1,285 +0,0 @@ | |||||||
| // Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. |  | ||||||
| // source: github.com/containerd/containerd/runtime/v1/shim/v1/shim.proto |  | ||||||
| package shim |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	context "context" |  | ||||||
| 	ttrpc "github.com/containerd/ttrpc" |  | ||||||
| 	emptypb "google.golang.org/protobuf/types/known/emptypb" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type ShimService interface { |  | ||||||
| 	State(context.Context, *StateRequest) (*StateResponse, error) |  | ||||||
| 	Create(context.Context, *CreateTaskRequest) (*CreateTaskResponse, error) |  | ||||||
| 	Start(context.Context, *StartRequest) (*StartResponse, error) |  | ||||||
| 	Delete(context.Context, *emptypb.Empty) (*DeleteResponse, error) |  | ||||||
| 	DeleteProcess(context.Context, *DeleteProcessRequest) (*DeleteResponse, error) |  | ||||||
| 	ListPids(context.Context, *ListPidsRequest) (*ListPidsResponse, error) |  | ||||||
| 	Pause(context.Context, *emptypb.Empty) (*emptypb.Empty, error) |  | ||||||
| 	Resume(context.Context, *emptypb.Empty) (*emptypb.Empty, error) |  | ||||||
| 	Checkpoint(context.Context, *CheckpointTaskRequest) (*emptypb.Empty, error) |  | ||||||
| 	Kill(context.Context, *KillRequest) (*emptypb.Empty, error) |  | ||||||
| 	Exec(context.Context, *ExecProcessRequest) (*emptypb.Empty, error) |  | ||||||
| 	ResizePty(context.Context, *ResizePtyRequest) (*emptypb.Empty, error) |  | ||||||
| 	CloseIO(context.Context, *CloseIORequest) (*emptypb.Empty, error) |  | ||||||
| 	ShimInfo(context.Context, *emptypb.Empty) (*ShimInfoResponse, error) |  | ||||||
| 	Update(context.Context, *UpdateTaskRequest) (*emptypb.Empty, error) |  | ||||||
| 	Wait(context.Context, *WaitRequest) (*WaitResponse, error) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func RegisterShimService(srv *ttrpc.Server, svc ShimService) { |  | ||||||
| 	srv.RegisterService("containerd.runtime.linux.shim.v1.Shim", &ttrpc.ServiceDesc{ |  | ||||||
| 		Methods: map[string]ttrpc.Method{ |  | ||||||
| 			"State": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req StateRequest |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.State(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"Create": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req CreateTaskRequest |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.Create(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"Start": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req StartRequest |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.Start(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"Delete": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req emptypb.Empty |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.Delete(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"DeleteProcess": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req DeleteProcessRequest |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.DeleteProcess(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"ListPids": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req ListPidsRequest |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.ListPids(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"Pause": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req emptypb.Empty |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.Pause(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"Resume": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req emptypb.Empty |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.Resume(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"Checkpoint": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req CheckpointTaskRequest |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.Checkpoint(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"Kill": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req KillRequest |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.Kill(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"Exec": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req ExecProcessRequest |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.Exec(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"ResizePty": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req ResizePtyRequest |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.ResizePty(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"CloseIO": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req CloseIORequest |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.CloseIO(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"ShimInfo": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req emptypb.Empty |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.ShimInfo(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"Update": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req UpdateTaskRequest |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.Update(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 			"Wait": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { |  | ||||||
| 				var req WaitRequest |  | ||||||
| 				if err := unmarshal(&req); err != nil { |  | ||||||
| 					return nil, err |  | ||||||
| 				} |  | ||||||
| 				return svc.Wait(ctx, &req) |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type shimClient struct { |  | ||||||
| 	client *ttrpc.Client |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewShimClient(client *ttrpc.Client) ShimService { |  | ||||||
| 	return &shimClient{ |  | ||||||
| 		client: client, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) State(ctx context.Context, req *StateRequest) (*StateResponse, error) { |  | ||||||
| 	var resp StateResponse |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "State", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) Create(ctx context.Context, req *CreateTaskRequest) (*CreateTaskResponse, error) { |  | ||||||
| 	var resp CreateTaskResponse |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Create", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) Start(ctx context.Context, req *StartRequest) (*StartResponse, error) { |  | ||||||
| 	var resp StartResponse |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Start", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) Delete(ctx context.Context, req *emptypb.Empty) (*DeleteResponse, error) { |  | ||||||
| 	var resp DeleteResponse |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Delete", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) DeleteProcess(ctx context.Context, req *DeleteProcessRequest) (*DeleteResponse, error) { |  | ||||||
| 	var resp DeleteResponse |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "DeleteProcess", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) ListPids(ctx context.Context, req *ListPidsRequest) (*ListPidsResponse, error) { |  | ||||||
| 	var resp ListPidsResponse |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "ListPids", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) Pause(ctx context.Context, req *emptypb.Empty) (*emptypb.Empty, error) { |  | ||||||
| 	var resp emptypb.Empty |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Pause", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) Resume(ctx context.Context, req *emptypb.Empty) (*emptypb.Empty, error) { |  | ||||||
| 	var resp emptypb.Empty |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Resume", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) Checkpoint(ctx context.Context, req *CheckpointTaskRequest) (*emptypb.Empty, error) { |  | ||||||
| 	var resp emptypb.Empty |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Checkpoint", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) Kill(ctx context.Context, req *KillRequest) (*emptypb.Empty, error) { |  | ||||||
| 	var resp emptypb.Empty |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Kill", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) Exec(ctx context.Context, req *ExecProcessRequest) (*emptypb.Empty, error) { |  | ||||||
| 	var resp emptypb.Empty |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Exec", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) ResizePty(ctx context.Context, req *ResizePtyRequest) (*emptypb.Empty, error) { |  | ||||||
| 	var resp emptypb.Empty |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "ResizePty", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) CloseIO(ctx context.Context, req *CloseIORequest) (*emptypb.Empty, error) { |  | ||||||
| 	var resp emptypb.Empty |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "CloseIO", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) ShimInfo(ctx context.Context, req *emptypb.Empty) (*ShimInfoResponse, error) { |  | ||||||
| 	var resp ShimInfoResponse |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "ShimInfo", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) Update(ctx context.Context, req *UpdateTaskRequest) (*emptypb.Empty, error) { |  | ||||||
| 	var resp emptypb.Empty |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Update", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *shimClient) Wait(ctx context.Context, req *WaitRequest) (*WaitResponse, error) { |  | ||||||
| 	var resp WaitResponse |  | ||||||
| 	if err := c.client.Call(ctx, "containerd.runtime.linux.shim.v1.Shim", "Wait", req, &resp); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &resp, nil |  | ||||||
| } |  | ||||||
| @@ -1,736 +0,0 @@ | |||||||
| //go:build linux |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|    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 v1 |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"fmt" |  | ||||||
| 	"io" |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
| 	goruntime "runtime" |  | ||||||
| 	"sync" |  | ||||||
| 	"syscall" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/cgroups/v3/cgroup1" |  | ||||||
| 	eventstypes "github.com/containerd/containerd/api/events" |  | ||||||
| 	taskAPI "github.com/containerd/containerd/api/runtime/task/v2" |  | ||||||
| 	"github.com/containerd/containerd/api/types/task" |  | ||||||
| 	"github.com/containerd/containerd/errdefs" |  | ||||||
| 	"github.com/containerd/containerd/mount" |  | ||||||
| 	"github.com/containerd/containerd/namespaces" |  | ||||||
| 	"github.com/containerd/containerd/pkg/oom" |  | ||||||
| 	oomv1 "github.com/containerd/containerd/pkg/oom/v1" |  | ||||||
| 	"github.com/containerd/containerd/pkg/process" |  | ||||||
| 	"github.com/containerd/containerd/pkg/schedcore" |  | ||||||
| 	"github.com/containerd/containerd/pkg/stdio" |  | ||||||
| 	"github.com/containerd/containerd/protobuf" |  | ||||||
| 	"github.com/containerd/containerd/protobuf/proto" |  | ||||||
| 	ptypes "github.com/containerd/containerd/protobuf/types" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v2/runc" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v2/runc/options" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v2/shim" |  | ||||||
| 	"github.com/containerd/containerd/sys/reaper" |  | ||||||
| 	runcC "github.com/containerd/go-runc" |  | ||||||
| 	"github.com/containerd/typeurl/v2" |  | ||||||
| 	"github.com/sirupsen/logrus" |  | ||||||
| 	exec "golang.org/x/sys/execabs" |  | ||||||
| 	"golang.org/x/sys/unix" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	_     = (taskAPI.TaskService)(&service{}) |  | ||||||
| 	empty = &ptypes.Empty{} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // New returns a new shim service that can be used via GRPC |  | ||||||
| func New(ctx context.Context, id string, publisher shim.Publisher, shutdown func()) (shim.Shim, error) { |  | ||||||
| 	ep, err := oomv1.New(publisher) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	go ep.Run(ctx) |  | ||||||
| 	s := &service{ |  | ||||||
| 		id:      id, |  | ||||||
| 		context: ctx, |  | ||||||
| 		events:  make(chan interface{}, 128), |  | ||||||
| 		ec:      reaper.Default.Subscribe(), |  | ||||||
| 		ep:      ep, |  | ||||||
| 		cancel:  shutdown, |  | ||||||
| 	} |  | ||||||
| 	go s.processExits() |  | ||||||
| 	runcC.Monitor = reaper.Default |  | ||||||
| 	if err := s.initPlatform(); err != nil { |  | ||||||
| 		shutdown() |  | ||||||
| 		return nil, fmt.Errorf("failed to initialized platform behavior: %w", err) |  | ||||||
| 	} |  | ||||||
| 	go s.forward(ctx, publisher) |  | ||||||
| 	return s, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // service is the shim implementation of a remote shim over GRPC |  | ||||||
| type service struct { |  | ||||||
| 	mu          sync.Mutex |  | ||||||
| 	eventSendMu sync.Mutex |  | ||||||
|  |  | ||||||
| 	context  context.Context |  | ||||||
| 	events   chan interface{} |  | ||||||
| 	platform stdio.Platform |  | ||||||
| 	ec       chan runcC.Exit |  | ||||||
| 	ep       oom.Watcher |  | ||||||
|  |  | ||||||
| 	id        string |  | ||||||
| 	container *runc.Container |  | ||||||
|  |  | ||||||
| 	cancel func() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newCommand(ctx context.Context, id, containerdAddress, containerdTTRPCAddress string) (*exec.Cmd, error) { |  | ||||||
| 	ns, err := namespaces.NamespaceRequired(ctx) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	self, err := os.Executable() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	cwd, err := os.Getwd() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	args := []string{ |  | ||||||
| 		"-namespace", ns, |  | ||||||
| 		"-id", id, |  | ||||||
| 		"-address", containerdAddress, |  | ||||||
| 	} |  | ||||||
| 	cmd := exec.Command(self, args...) |  | ||||||
| 	cmd.Dir = cwd |  | ||||||
| 	cmd.Env = append(os.Environ(), "GOMAXPROCS=2") |  | ||||||
| 	cmd.SysProcAttr = &syscall.SysProcAttr{ |  | ||||||
| 		Setpgid: true, |  | ||||||
| 	} |  | ||||||
| 	return cmd, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *service) StartShim(ctx context.Context, opts shim.StartOpts) (_ string, retErr error) { |  | ||||||
| 	cmd, err := newCommand(ctx, opts.ID, opts.Address, opts.TTRPCAddress) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	address, err := shim.SocketAddress(ctx, opts.Address, opts.ID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	socket, err := shim.NewSocket(address) |  | ||||||
| 	if err != nil { |  | ||||||
| 		if !shim.SocketEaddrinuse(err) { |  | ||||||
| 			return "", err |  | ||||||
| 		} |  | ||||||
| 		if err := shim.RemoveSocket(address); err != nil { |  | ||||||
| 			return "", fmt.Errorf("remove already used socket: %w", err) |  | ||||||
| 		} |  | ||||||
| 		if socket, err = shim.NewSocket(address); err != nil { |  | ||||||
| 			return "", err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	defer func() { |  | ||||||
| 		if retErr != nil { |  | ||||||
| 			socket.Close() |  | ||||||
| 			_ = shim.RemoveSocket(address) |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
| 	// make sure that reexec shim-v2 binary use the value if need |  | ||||||
| 	if err := shim.WriteAddress("address", address); err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	f, err := socket.File() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	cmd.ExtraFiles = append(cmd.ExtraFiles, f) |  | ||||||
|  |  | ||||||
| 	goruntime.LockOSThread() |  | ||||||
| 	if os.Getenv("SCHED_CORE") != "" { |  | ||||||
| 		if err := schedcore.Create(schedcore.ProcessGroup); err != nil { |  | ||||||
| 			return "", fmt.Errorf("enable sched core support: %w", err) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := cmd.Start(); err != nil { |  | ||||||
| 		f.Close() |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	goruntime.UnlockOSThread() |  | ||||||
|  |  | ||||||
| 	defer func() { |  | ||||||
| 		if retErr != nil { |  | ||||||
| 			cmd.Process.Kill() |  | ||||||
| 		} |  | ||||||
| 	}() |  | ||||||
| 	// make sure to wait after start |  | ||||||
| 	go cmd.Wait() |  | ||||||
| 	if err := shim.WritePidFile("shim.pid", cmd.Process.Pid); err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	if data, err := io.ReadAll(os.Stdin); err == nil { |  | ||||||
| 		if len(data) > 0 { |  | ||||||
| 			var any ptypes.Any |  | ||||||
| 			if err := proto.Unmarshal(data, &any); err != nil { |  | ||||||
| 				return "", err |  | ||||||
| 			} |  | ||||||
| 			v, err := typeurl.UnmarshalAny(&any) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return "", err |  | ||||||
| 			} |  | ||||||
| 			if opts, ok := v.(*options.Options); ok { |  | ||||||
| 				if opts.ShimCgroup != "" { |  | ||||||
| 					cg, err := cgroup1.Load(cgroup1.StaticPath(opts.ShimCgroup)) |  | ||||||
| 					if err != nil { |  | ||||||
| 						return "", fmt.Errorf("failed to load cgroup %s: %w", opts.ShimCgroup, err) |  | ||||||
| 					} |  | ||||||
| 					if err := cg.AddProc(uint64(cmd.Process.Pid)); err != nil { |  | ||||||
| 						return "", fmt.Errorf("failed to join cgroup %s: %w", opts.ShimCgroup, err) |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if err := shim.AdjustOOMScore(cmd.Process.Pid); err != nil { |  | ||||||
| 		return "", fmt.Errorf("failed to adjust OOM score for shim: %w", err) |  | ||||||
| 	} |  | ||||||
| 	return address, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *service) Cleanup(ctx context.Context) (*taskAPI.DeleteResponse, error) { |  | ||||||
| 	if address, err := shim.ReadAddress("address"); err == nil { |  | ||||||
| 		if err = shim.RemoveSocket(address); err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	path, err := os.Getwd() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	ns, err := namespaces.NamespaceRequired(ctx) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	runtime, err := runc.ReadRuntime(path) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	opts, err := runc.ReadOptions(path) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	root := process.RuncRoot |  | ||||||
| 	if opts != nil && opts.Root != "" { |  | ||||||
| 		root = opts.Root |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	r := process.NewRunc(root, path, ns, runtime, false) |  | ||||||
| 	if err := r.Delete(ctx, s.id, &runcC.DeleteOpts{ |  | ||||||
| 		Force: true, |  | ||||||
| 	}); err != nil { |  | ||||||
| 		logrus.WithError(err).Warn("failed to remove runc container") |  | ||||||
| 	} |  | ||||||
| 	if err := mount.UnmountRecursive(filepath.Join(path, "rootfs"), 0); err != nil { |  | ||||||
| 		logrus.WithError(err).Warn("failed to cleanup rootfs mount") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	pid, err := runcC.ReadPidFile(filepath.Join(path, process.InitPidFile)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logrus.WithError(err).Warn("failed to read init pid file") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return &taskAPI.DeleteResponse{ |  | ||||||
| 		ExitedAt:   protobuf.ToTimestamp(time.Now()), |  | ||||||
| 		ExitStatus: 128 + uint32(unix.SIGKILL), |  | ||||||
| 		Pid:        uint32(pid), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Create a new initial process and container with the underlying OCI runtime |  | ||||||
| func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *taskAPI.CreateTaskResponse, err error) { |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	defer s.mu.Unlock() |  | ||||||
|  |  | ||||||
| 	container, err := runc.NewContainer(ctx, s.platform, r) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	s.container = container |  | ||||||
|  |  | ||||||
| 	s.send(&eventstypes.TaskCreate{ |  | ||||||
| 		ContainerID: r.ID, |  | ||||||
| 		Bundle:      r.Bundle, |  | ||||||
| 		Rootfs:      r.Rootfs, |  | ||||||
| 		IO: &eventstypes.TaskIO{ |  | ||||||
| 			Stdin:    r.Stdin, |  | ||||||
| 			Stdout:   r.Stdout, |  | ||||||
| 			Stderr:   r.Stderr, |  | ||||||
| 			Terminal: r.Terminal, |  | ||||||
| 		}, |  | ||||||
| 		Checkpoint: r.Checkpoint, |  | ||||||
| 		Pid:        uint32(container.Pid()), |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	return &taskAPI.CreateTaskResponse{ |  | ||||||
| 		Pid: uint32(container.Pid()), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Start a process |  | ||||||
| func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.StartResponse, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// hold the send lock so that the start events are sent before any exit events in the error case |  | ||||||
| 	s.eventSendMu.Lock() |  | ||||||
| 	p, err := container.Start(ctx, r) |  | ||||||
| 	if err != nil { |  | ||||||
| 		s.eventSendMu.Unlock() |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	switch r.ExecID { |  | ||||||
| 	case "": |  | ||||||
| 		if cg, ok := container.Cgroup().(cgroup1.Cgroup); ok { |  | ||||||
| 			if err := s.ep.Add(container.ID, cg); err != nil { |  | ||||||
| 				logrus.WithError(err).Error("add cg to OOM monitor") |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			logrus.WithError(errdefs.ErrNotImplemented).Error("add cg to OOM monitor") |  | ||||||
| 		} |  | ||||||
| 		s.send(&eventstypes.TaskStart{ |  | ||||||
| 			ContainerID: container.ID, |  | ||||||
| 			Pid:         uint32(p.Pid()), |  | ||||||
| 		}) |  | ||||||
| 	default: |  | ||||||
| 		s.send(&eventstypes.TaskExecStarted{ |  | ||||||
| 			ContainerID: container.ID, |  | ||||||
| 			ExecID:      r.ExecID, |  | ||||||
| 			Pid:         uint32(p.Pid()), |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 	s.eventSendMu.Unlock() |  | ||||||
| 	return &taskAPI.StartResponse{ |  | ||||||
| 		Pid: uint32(p.Pid()), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Delete the initial process and container |  | ||||||
| func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAPI.DeleteResponse, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	p, err := container.Delete(ctx, r) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	// if we deleted our init task, close the platform and send the task delete event |  | ||||||
| 	if r.ExecID == "" { |  | ||||||
| 		if s.platform != nil { |  | ||||||
| 			s.platform.Close() |  | ||||||
| 		} |  | ||||||
| 		s.send(&eventstypes.TaskDelete{ |  | ||||||
| 			ContainerID: container.ID, |  | ||||||
| 			Pid:         uint32(p.Pid()), |  | ||||||
| 			ExitStatus:  uint32(p.ExitStatus()), |  | ||||||
| 			ExitedAt:    protobuf.ToTimestamp(p.ExitedAt()), |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 	return &taskAPI.DeleteResponse{ |  | ||||||
| 		ExitStatus: uint32(p.ExitStatus()), |  | ||||||
| 		ExitedAt:   protobuf.ToTimestamp(p.ExitedAt()), |  | ||||||
| 		Pid:        uint32(p.Pid()), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Exec an additional process inside the container |  | ||||||
| func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*ptypes.Empty, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	ok, cancel := container.ReserveProcess(r.ExecID) |  | ||||||
| 	if !ok { |  | ||||||
| 		return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ExecID) |  | ||||||
| 	} |  | ||||||
| 	process, err := container.Exec(ctx, r) |  | ||||||
| 	if err != nil { |  | ||||||
| 		cancel() |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	s.send(&eventstypes.TaskExecAdded{ |  | ||||||
| 		ContainerID: s.container.ID, |  | ||||||
| 		ExecID:      process.ID(), |  | ||||||
| 	}) |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ResizePty of a process |  | ||||||
| func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*ptypes.Empty, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := container.ResizePty(ctx, r); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // State returns runtime state information for a process |  | ||||||
| func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI.StateResponse, error) { |  | ||||||
| 	p, err := s.getProcess(r.ExecID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	st, err := p.Status(ctx) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	status := task.Status_UNKNOWN |  | ||||||
| 	switch st { |  | ||||||
| 	case "created": |  | ||||||
| 		status = task.Status_CREATED |  | ||||||
| 	case "running": |  | ||||||
| 		status = task.Status_RUNNING |  | ||||||
| 	case "stopped": |  | ||||||
| 		status = task.Status_STOPPED |  | ||||||
| 	case "paused": |  | ||||||
| 		status = task.Status_PAUSED |  | ||||||
| 	case "pausing": |  | ||||||
| 		status = task.Status_PAUSING |  | ||||||
| 	} |  | ||||||
| 	sio := p.Stdio() |  | ||||||
| 	return &taskAPI.StateResponse{ |  | ||||||
| 		ID:         p.ID(), |  | ||||||
| 		Bundle:     s.container.Bundle, |  | ||||||
| 		Pid:        uint32(p.Pid()), |  | ||||||
| 		Status:     status, |  | ||||||
| 		Stdin:      sio.Stdin, |  | ||||||
| 		Stdout:     sio.Stdout, |  | ||||||
| 		Stderr:     sio.Stderr, |  | ||||||
| 		Terminal:   sio.Terminal, |  | ||||||
| 		ExitStatus: uint32(p.ExitStatus()), |  | ||||||
| 		ExitedAt:   protobuf.ToTimestamp(p.ExitedAt()), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Pause the container |  | ||||||
| func (s *service) Pause(ctx context.Context, r *taskAPI.PauseRequest) (*ptypes.Empty, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := container.Pause(ctx); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	s.send(&eventstypes.TaskPaused{ |  | ||||||
| 		ContainerID: container.ID, |  | ||||||
| 	}) |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Resume the container |  | ||||||
| func (s *service) Resume(ctx context.Context, r *taskAPI.ResumeRequest) (*ptypes.Empty, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := container.Resume(ctx); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	s.send(&eventstypes.TaskResumed{ |  | ||||||
| 		ContainerID: container.ID, |  | ||||||
| 	}) |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Kill a process with the provided signal |  | ||||||
| func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*ptypes.Empty, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := container.Kill(ctx, r); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Pids returns all pids inside the container |  | ||||||
| func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.PidsResponse, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	pids, err := s.getContainerPids(ctx, r.ID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	var processes []*task.ProcessInfo |  | ||||||
| 	for _, pid := range pids { |  | ||||||
| 		pInfo := task.ProcessInfo{ |  | ||||||
| 			Pid: pid, |  | ||||||
| 		} |  | ||||||
| 		for _, p := range container.ExecdProcesses() { |  | ||||||
| 			if p.Pid() == int(pid) { |  | ||||||
| 				d := &options.ProcessDetails{ |  | ||||||
| 					ExecID: p.ID(), |  | ||||||
| 				} |  | ||||||
| 				a, err := protobuf.MarshalAnyToProto(d) |  | ||||||
| 				if err != nil { |  | ||||||
| 					return nil, fmt.Errorf("failed to marshal process %d info: %w", pid, err) |  | ||||||
| 				} |  | ||||||
| 				pInfo.Info = a |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		processes = append(processes, &pInfo) |  | ||||||
| 	} |  | ||||||
| 	return &taskAPI.PidsResponse{ |  | ||||||
| 		Processes: processes, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // CloseIO of a process |  | ||||||
| func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*ptypes.Empty, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := container.CloseIO(ctx, r); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Checkpoint the container |  | ||||||
| func (s *service) Checkpoint(ctx context.Context, r *taskAPI.CheckpointTaskRequest) (*ptypes.Empty, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := container.Checkpoint(ctx, r); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Update a running container |  | ||||||
| func (s *service) Update(ctx context.Context, r *taskAPI.UpdateTaskRequest) (*ptypes.Empty, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if err := container.Update(ctx, r); err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Wait for a process to exit |  | ||||||
| func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.WaitResponse, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	p, err := container.Process(r.ExecID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	p.Wait() |  | ||||||
|  |  | ||||||
| 	return &taskAPI.WaitResponse{ |  | ||||||
| 		ExitStatus: uint32(p.ExitStatus()), |  | ||||||
| 		ExitedAt:   protobuf.ToTimestamp(p.ExitedAt()), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Connect returns shim information such as the shim's pid |  | ||||||
| func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*taskAPI.ConnectResponse, error) { |  | ||||||
| 	var pid int |  | ||||||
| 	if s.container != nil { |  | ||||||
| 		pid = s.container.Pid() |  | ||||||
| 	} |  | ||||||
| 	return &taskAPI.ConnectResponse{ |  | ||||||
| 		ShimPid: uint32(os.Getpid()), |  | ||||||
| 		TaskPid: uint32(pid), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *service) Shutdown(ctx context.Context, r *taskAPI.ShutdownRequest) (*ptypes.Empty, error) { |  | ||||||
| 	// please make sure that temporary resource has been cleanup |  | ||||||
| 	// before shutdown service. |  | ||||||
| 	s.cancel() |  | ||||||
| 	close(s.events) |  | ||||||
| 	return empty, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	cgx := container.Cgroup() |  | ||||||
| 	if cgx == nil { |  | ||||||
| 		return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "cgroup does not exist") |  | ||||||
| 	} |  | ||||||
| 	cg, ok := cgx.(cgroup1.Cgroup) |  | ||||||
| 	if !ok { |  | ||||||
| 		return nil, errdefs.ToGRPCf(errdefs.ErrNotImplemented, "cgroup v2 not implemented for Stats") |  | ||||||
| 	} |  | ||||||
| 	if cg == nil { |  | ||||||
| 		return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "cgroup does not exist") |  | ||||||
| 	} |  | ||||||
| 	stats, err := cg.Stat(cgroup1.IgnoreNotExist) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	data, err := typeurl.MarshalAny(stats) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &taskAPI.StatsResponse{ |  | ||||||
| 		Stats: protobuf.FromAny(data), |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *service) processExits() { |  | ||||||
| 	for e := range s.ec { |  | ||||||
| 		s.checkProcesses(e) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *service) send(evt interface{}) { |  | ||||||
| 	s.events <- evt |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *service) sendL(evt interface{}) { |  | ||||||
| 	s.eventSendMu.Lock() |  | ||||||
| 	s.events <- evt |  | ||||||
| 	s.eventSendMu.Unlock() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *service) checkProcesses(e runcC.Exit) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, p := range container.All() { |  | ||||||
| 		if p.Pid() == e.Pid { |  | ||||||
| 			if runc.ShouldKillAllOnExit(s.context, container.Bundle) { |  | ||||||
| 				if ip, ok := p.(*process.Init); ok { |  | ||||||
| 					// Ensure all children are killed |  | ||||||
| 					if err := ip.KillAll(s.context); err != nil { |  | ||||||
| 						logrus.WithError(err).WithField("id", ip.ID()). |  | ||||||
| 							Error("failed to kill init's children") |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 			p.SetExited(e.Status) |  | ||||||
| 			s.sendL(&eventstypes.TaskExit{ |  | ||||||
| 				ContainerID: container.ID, |  | ||||||
| 				ID:          p.ID(), |  | ||||||
| 				Pid:         uint32(e.Pid), |  | ||||||
| 				ExitStatus:  uint32(e.Status), |  | ||||||
| 				ExitedAt:    protobuf.ToTimestamp(p.ExitedAt()), |  | ||||||
| 			}) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *service) getContainerPids(ctx context.Context, id string) ([]uint32, error) { |  | ||||||
| 	p, err := s.container.Process("") |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	ps, err := p.(*process.Init).Runtime().Ps(ctx, id) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	pids := make([]uint32, 0, len(ps)) |  | ||||||
| 	for _, pid := range ps { |  | ||||||
| 		pids = append(pids, uint32(pid)) |  | ||||||
| 	} |  | ||||||
| 	return pids, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *service) forward(ctx context.Context, publisher shim.Publisher) { |  | ||||||
| 	ns, _ := namespaces.Namespace(ctx) |  | ||||||
| 	ctx = namespaces.WithNamespace(context.Background(), ns) |  | ||||||
| 	for e := range s.events { |  | ||||||
| 		ctx, cancel := context.WithTimeout(ctx, 5*time.Second) |  | ||||||
| 		err := publisher.Publish(ctx, runc.GetTopic(e), e) |  | ||||||
| 		cancel() |  | ||||||
| 		if err != nil { |  | ||||||
| 			logrus.WithError(err).Error("post event") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	publisher.Close() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *service) getContainer() (*runc.Container, error) { |  | ||||||
| 	s.mu.Lock() |  | ||||||
| 	container := s.container |  | ||||||
| 	s.mu.Unlock() |  | ||||||
| 	if container == nil { |  | ||||||
| 		return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "container not created") |  | ||||||
| 	} |  | ||||||
| 	return container, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *service) getProcess(execID string) (process.Process, error) { |  | ||||||
| 	container, err := s.getContainer() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	p, err := container.Process(execID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPC(err) |  | ||||||
| 	} |  | ||||||
| 	return p, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // initialize a single epoll fd to manage our consoles. `initPlatform` should |  | ||||||
| // only be called once. |  | ||||||
| func (s *service) initPlatform() error { |  | ||||||
| 	if s.platform != nil { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	p, err := runc.NewPlatform() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	s.platform = p |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -23,7 +23,6 @@ import ( | |||||||
| 	"io" | 	"io" | ||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"strings" |  | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	api "github.com/containerd/containerd/api/services/tasks/v1" | 	api "github.com/containerd/containerd/api/services/tasks/v1" | ||||||
| @@ -47,7 +46,6 @@ import ( | |||||||
| 	"github.com/containerd/containerd/protobuf/proto" | 	"github.com/containerd/containerd/protobuf/proto" | ||||||
| 	ptypes "github.com/containerd/containerd/protobuf/types" | 	ptypes "github.com/containerd/containerd/protobuf/types" | ||||||
| 	"github.com/containerd/containerd/runtime" | 	"github.com/containerd/containerd/runtime" | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v2/runc/options" | 	"github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
| 	"github.com/containerd/containerd/services" | 	"github.com/containerd/containerd/services" | ||||||
| 	"github.com/containerd/typeurl/v2" | 	"github.com/containerd/typeurl/v2" | ||||||
| @@ -89,10 +87,6 @@ func init() { | |||||||
|  |  | ||||||
| func initFunc(ic *plugin.InitContext) (interface{}, error) { | func initFunc(ic *plugin.InitContext) (interface{}, error) { | ||||||
| 	config := ic.Config.(*Config) | 	config := ic.Config.(*Config) | ||||||
| 	runtimes, err := loadV1Runtimes(ic) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	v2r, err := ic.GetByID(plugin.RuntimePluginV2, "task") | 	v2r, err := ic.GetByID(plugin.RuntimePluginV2, "task") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -119,22 +113,13 @@ func initFunc(ic *plugin.InitContext) (interface{}, error) { | |||||||
|  |  | ||||||
| 	db := m.(*metadata.DB) | 	db := m.(*metadata.DB) | ||||||
| 	l := &local{ | 	l := &local{ | ||||||
| 		runtimes:   runtimes, |  | ||||||
| 		containers: metadata.NewContainerStore(db), | 		containers: metadata.NewContainerStore(db), | ||||||
| 		store:      db.ContentStore(), | 		store:      db.ContentStore(), | ||||||
| 		publisher:  ep.(events.Publisher), | 		publisher:  ep.(events.Publisher), | ||||||
| 		monitor:    monitor.(runtime.TaskMonitor), | 		monitor:    monitor.(runtime.TaskMonitor), | ||||||
| 		v2Runtime:  v2r.(runtime.PlatformRuntime), | 		v2Runtime:  v2r.(runtime.PlatformRuntime), | ||||||
| 	} | 	} | ||||||
| 	for _, r := range runtimes { |  | ||||||
| 		tasks, err := r.Tasks(ic.Context, true) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		for _, t := range tasks { |  | ||||||
| 			l.monitor.Monitor(t, nil) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	v2Tasks, err := l.v2Runtime.Tasks(ic.Context, true) | 	v2Tasks, err := l.v2Runtime.Tasks(ic.Context, true) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @@ -154,7 +139,6 @@ func initFunc(ic *plugin.InitContext) (interface{}, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| type local struct { | type local struct { | ||||||
| 	runtimes   map[string]runtime.PlatformRuntime |  | ||||||
| 	containers containers.Store | 	containers containers.Store | ||||||
| 	store      content.Store | 	store      content.Store | ||||||
| 	publisher  events.Publisher | 	publisher  events.Publisher | ||||||
| @@ -221,15 +205,9 @@ func (l *local) Create(ctx context.Context, r *api.CreateTaskRequest, _ ...grpc. | |||||||
| 			Options: m.Options, | 			Options: m.Options, | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| 	if strings.HasPrefix(container.Runtime.Name, "io.containerd.runtime.v1.") { |  | ||||||
| 		log.G(ctx).Warn("runtime v1 is deprecated since containerd v1.4, consider using runtime v2") | 	rtime := l.v2Runtime | ||||||
| 	} else if container.Runtime.Name == plugin.RuntimeRuncV1 { |  | ||||||
| 		log.G(ctx).Warnf("%q is deprecated since containerd v1.4, consider using %q", plugin.RuntimeRuncV1, plugin.RuntimeRuncV2) |  | ||||||
| 	} |  | ||||||
| 	rtime, err := l.getRuntime(container.Runtime.Name) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	_, err = rtime.Get(ctx, r.ContainerID) | 	_, err = rtime.Get(ctx, r.ContainerID) | ||||||
| 	if err != nil && !errdefs.IsNotFound(err) { | 	if err != nil && !errdefs.IsNotFound(err) { | ||||||
| 		return nil, errdefs.ToGRPC(err) | 		return nil, errdefs.ToGRPC(err) | ||||||
| @@ -284,14 +262,8 @@ func (l *local) Delete(ctx context.Context, r *api.DeleteTaskRequest, _ ...grpc. | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Find runtime manager |  | ||||||
| 	rtime, err := l.getRuntime(container.Runtime.Name) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Get task object | 	// Get task object | ||||||
| 	t, err := rtime.Get(ctx, container.ID) | 	t, err := l.v2Runtime.Get(ctx, container.ID) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, status.Errorf(codes.NotFound, "task %v not found", container.ID) | 		return nil, status.Errorf(codes.NotFound, "task %v not found", container.ID) | ||||||
| 	} | 	} | ||||||
| @@ -300,7 +272,7 @@ func (l *local) Delete(ctx context.Context, r *api.DeleteTaskRequest, _ ...grpc. | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	exit, err := rtime.Delete(ctx, r.ContainerID) | 	exit, err := l.v2Runtime.Delete(ctx, r.ContainerID) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, errdefs.ToGRPC(err) | 		return nil, errdefs.ToGRPC(err) | ||||||
| 	} | 	} | ||||||
| @@ -394,13 +366,11 @@ func (l *local) Get(ctx context.Context, r *api.GetRequest, _ ...grpc.CallOption | |||||||
|  |  | ||||||
| func (l *local) List(ctx context.Context, r *api.ListTasksRequest, _ ...grpc.CallOption) (*api.ListTasksResponse, error) { | func (l *local) List(ctx context.Context, r *api.ListTasksRequest, _ ...grpc.CallOption) (*api.ListTasksResponse, error) { | ||||||
| 	resp := &api.ListTasksResponse{} | 	resp := &api.ListTasksResponse{} | ||||||
| 	for _, r := range l.allRuntimes() { | 	tasks, err := l.v2Runtime.Tasks(ctx, false) | ||||||
| 		tasks, err := r.Tasks(ctx, false) | 	if err != nil { | ||||||
| 		if err != nil { | 		return nil, errdefs.ToGRPC(err) | ||||||
| 			return nil, errdefs.ToGRPC(err) |  | ||||||
| 		} |  | ||||||
| 		addTasks(ctx, resp, tasks) |  | ||||||
| 	} | 	} | ||||||
|  | 	addTasks(ctx, resp, tasks) | ||||||
| 	return resp, nil | 	return resp, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -623,13 +593,11 @@ func (l *local) Metrics(ctx context.Context, r *api.MetricsRequest, _ ...grpc.Ca | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	var resp api.MetricsResponse | 	var resp api.MetricsResponse | ||||||
| 	for _, r := range l.allRuntimes() { | 	tasks, err := l.v2Runtime.Tasks(ctx, false) | ||||||
| 		tasks, err := r.Tasks(ctx, false) | 	if err != nil { | ||||||
| 		if err != nil { | 		return nil, err | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		getTasksMetrics(ctx, filter, tasks, &resp) |  | ||||||
| 	} | 	} | ||||||
|  | 	getTasksMetrics(ctx, filter, tasks, &resp) | ||||||
| 	return &resp, nil | 	return &resp, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -725,34 +693,13 @@ func (l *local) getTask(ctx context.Context, id string) (runtime.Task, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (l *local) getTaskFromContainer(ctx context.Context, container *containers.Container) (runtime.Task, error) { | func (l *local) getTaskFromContainer(ctx context.Context, container *containers.Container) (runtime.Task, error) { | ||||||
| 	runtime, err := l.getRuntime(container.Runtime.Name) | 	t, err := l.v2Runtime.Get(ctx, container.ID) | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errdefs.ToGRPCf(err, "runtime for task %s", container.Runtime.Name) |  | ||||||
| 	} |  | ||||||
| 	t, err := runtime.Get(ctx, container.ID) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, status.Errorf(codes.NotFound, "task %v not found", container.ID) | 		return nil, status.Errorf(codes.NotFound, "task %v not found", container.ID) | ||||||
| 	} | 	} | ||||||
| 	return t, nil | 	return t, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (l *local) getRuntime(name string) (runtime.PlatformRuntime, error) { |  | ||||||
| 	runtime, ok := l.runtimes[name] |  | ||||||
| 	if !ok { |  | ||||||
| 		// one runtime to rule them all |  | ||||||
| 		return l.v2Runtime, nil |  | ||||||
| 	} |  | ||||||
| 	return runtime, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (l *local) allRuntimes() (o []runtime.PlatformRuntime) { |  | ||||||
| 	for _, r := range l.runtimes { |  | ||||||
| 		o = append(o, r) |  | ||||||
| 	} |  | ||||||
| 	o = append(o, l.v2Runtime) |  | ||||||
| 	return o |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // getCheckpointPath only suitable for runc runtime now | // getCheckpointPath only suitable for runc runtime now | ||||||
| func getCheckpointPath(runtime string, option *ptypes.Any) (string, error) { | func getCheckpointPath(runtime string, option *ptypes.Any) (string, error) { | ||||||
| 	if option == nil { | 	if option == nil { | ||||||
| @@ -760,29 +707,15 @@ func getCheckpointPath(runtime string, option *ptypes.Any) (string, error) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var checkpointPath string | 	var checkpointPath string | ||||||
| 	switch { | 	v, err := typeurl.UnmarshalAny(option) | ||||||
| 	case checkRuntime(runtime, "io.containerd.runc"): | 	if err != nil { | ||||||
| 		v, err := typeurl.UnmarshalAny(option) | 		return "", err | ||||||
| 		if err != nil { |  | ||||||
| 			return "", err |  | ||||||
| 		} |  | ||||||
| 		opts, ok := v.(*options.CheckpointOptions) |  | ||||||
| 		if !ok { |  | ||||||
| 			return "", fmt.Errorf("invalid task checkpoint option for %s", runtime) |  | ||||||
| 		} |  | ||||||
| 		checkpointPath = opts.ImagePath |  | ||||||
|  |  | ||||||
| 	case runtime == plugin.RuntimeLinuxV1: |  | ||||||
| 		v, err := typeurl.UnmarshalAny(option) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return "", err |  | ||||||
| 		} |  | ||||||
| 		opts, ok := v.(*runctypes.CheckpointOptions) |  | ||||||
| 		if !ok { |  | ||||||
| 			return "", fmt.Errorf("invalid task checkpoint option for %s", runtime) |  | ||||||
| 		} |  | ||||||
| 		checkpointPath = opts.ImagePath |  | ||||||
| 	} | 	} | ||||||
|  | 	opts, ok := v.(*options.CheckpointOptions) | ||||||
|  | 	if !ok { | ||||||
|  | 		return "", fmt.Errorf("invalid task checkpoint option for %s", runtime) | ||||||
|  | 	} | ||||||
|  | 	checkpointPath = opts.ImagePath | ||||||
|  |  | ||||||
| 	return checkpointPath, nil | 	return checkpointPath, nil | ||||||
| } | } | ||||||
| @@ -794,45 +727,15 @@ func getRestorePath(runtime string, option *ptypes.Any) (string, error) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var restorePath string | 	var restorePath string | ||||||
| 	switch { | 	v, err := typeurl.UnmarshalAny(option) | ||||||
| 	case checkRuntime(runtime, "io.containerd.runc"): | 	if err != nil { | ||||||
| 		v, err := typeurl.UnmarshalAny(option) | 		return "", err | ||||||
| 		if err != nil { |  | ||||||
| 			return "", err |  | ||||||
| 		} |  | ||||||
| 		opts, ok := v.(*options.Options) |  | ||||||
| 		if !ok { |  | ||||||
| 			return "", fmt.Errorf("invalid task create option for %s", runtime) |  | ||||||
| 		} |  | ||||||
| 		restorePath = opts.CriuImagePath |  | ||||||
| 	case runtime == plugin.RuntimeLinuxV1: |  | ||||||
| 		v, err := typeurl.UnmarshalAny(option) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return "", err |  | ||||||
| 		} |  | ||||||
| 		opts, ok := v.(*runctypes.CreateOptions) |  | ||||||
| 		if !ok { |  | ||||||
| 			return "", fmt.Errorf("invalid task create option for %s", runtime) |  | ||||||
| 		} |  | ||||||
| 		restorePath = opts.CriuImagePath |  | ||||||
| 	} | 	} | ||||||
|  | 	opts, ok := v.(*options.Options) | ||||||
|  | 	if !ok { | ||||||
|  | 		return "", fmt.Errorf("invalid task create option for %s", runtime) | ||||||
|  | 	} | ||||||
|  | 	restorePath = opts.CriuImagePath | ||||||
|  |  | ||||||
| 	return restorePath, nil | 	return restorePath, 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 |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -20,7 +20,6 @@ package tasks | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/containerd/containerd/plugin" | 	"github.com/containerd/containerd/plugin" | ||||||
| 	"github.com/containerd/containerd/runtime" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var tasksServiceRequires = []plugin.Type{ | var tasksServiceRequires = []plugin.Type{ | ||||||
| @@ -28,8 +27,3 @@ var tasksServiceRequires = []plugin.Type{ | |||||||
| 	plugin.MetadataPlugin, | 	plugin.MetadataPlugin, | ||||||
| 	plugin.TaskMonitorPlugin, | 	plugin.TaskMonitorPlugin, | ||||||
| } | } | ||||||
|  |  | ||||||
| // loadV1Runtimes on darwin returns an empty map. There are no v1 runtimes |  | ||||||
| func loadV1Runtimes(ic *plugin.InitContext) (map[string]runtime.PlatformRuntime, error) { |  | ||||||
| 	return make(map[string]runtime.PlatformRuntime), nil |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -18,7 +18,6 @@ package tasks | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/containerd/containerd/plugin" | 	"github.com/containerd/containerd/plugin" | ||||||
| 	"github.com/containerd/containerd/runtime" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var tasksServiceRequires = []plugin.Type{ | var tasksServiceRequires = []plugin.Type{ | ||||||
| @@ -27,8 +26,3 @@ var tasksServiceRequires = []plugin.Type{ | |||||||
| 	plugin.MetadataPlugin, | 	plugin.MetadataPlugin, | ||||||
| 	plugin.TaskMonitorPlugin, | 	plugin.TaskMonitorPlugin, | ||||||
| } | } | ||||||
|  |  | ||||||
| // loadV1Runtimes on FreeBSD returns an empty map. There are no v1 runtimes |  | ||||||
| func loadV1Runtimes(ic *plugin.InitContext) (map[string]runtime.PlatformRuntime, error) { |  | ||||||
| 	return make(map[string]runtime.PlatformRuntime), nil |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -19,11 +19,7 @@ | |||||||
| package tasks | package tasks | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"errors" |  | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/log" |  | ||||||
| 	"github.com/containerd/containerd/plugin" | 	"github.com/containerd/containerd/plugin" | ||||||
| 	"github.com/containerd/containerd/runtime" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var tasksServiceRequires = []plugin.Type{ | var tasksServiceRequires = []plugin.Type{ | ||||||
| @@ -33,26 +29,3 @@ var tasksServiceRequires = []plugin.Type{ | |||||||
| 	plugin.MetadataPlugin, | 	plugin.MetadataPlugin, | ||||||
| 	plugin.TaskMonitorPlugin, | 	plugin.TaskMonitorPlugin, | ||||||
| } | } | ||||||
|  |  | ||||||
| func loadV1Runtimes(ic *plugin.InitContext) (map[string]runtime.PlatformRuntime, error) { |  | ||||||
| 	rt, err := ic.GetByType(plugin.RuntimePlugin) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	runtimes := make(map[string]runtime.PlatformRuntime) |  | ||||||
| 	for _, rr := range rt { |  | ||||||
| 		ri, err := rr.Instance() |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.G(ic.Context).WithError(err).Warn("could not load runtime instance due to initialization error") |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		r := ri.(runtime.PlatformRuntime) |  | ||||||
| 		runtimes[r.ID()] = r |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(runtimes) == 0 { |  | ||||||
| 		return nil, errors.New("no runtimes available to create task service") |  | ||||||
| 	} |  | ||||||
| 	return runtimes, nil |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -18,7 +18,6 @@ package tasks | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/containerd/containerd/plugin" | 	"github.com/containerd/containerd/plugin" | ||||||
| 	"github.com/containerd/containerd/runtime" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var tasksServiceRequires = []plugin.Type{ | var tasksServiceRequires = []plugin.Type{ | ||||||
| @@ -27,8 +26,3 @@ var tasksServiceRequires = []plugin.Type{ | |||||||
| 	plugin.MetadataPlugin, | 	plugin.MetadataPlugin, | ||||||
| 	plugin.TaskMonitorPlugin, | 	plugin.TaskMonitorPlugin, | ||||||
| } | } | ||||||
|  |  | ||||||
| // loadV1Runtimes on Windows V2 returns an empty map. There are no v1 runtimes |  | ||||||
| func loadV1Runtimes(ic *plugin.InitContext) (map[string]runtime.PlatformRuntime, error) { |  | ||||||
| 	return make(map[string]runtime.PlatformRuntime), nil |  | ||||||
| } |  | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								task.go
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								task.go
									
									
									
									
									
								
							| @@ -41,7 +41,6 @@ import ( | |||||||
| 	"github.com/containerd/containerd/protobuf" | 	"github.com/containerd/containerd/protobuf" | ||||||
| 	google_protobuf "github.com/containerd/containerd/protobuf/types" | 	google_protobuf "github.com/containerd/containerd/protobuf/types" | ||||||
| 	"github.com/containerd/containerd/rootfs" | 	"github.com/containerd/containerd/rootfs" | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v2/runc/options" | 	"github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
| 	"github.com/containerd/typeurl/v2" | 	"github.com/containerd/typeurl/v2" | ||||||
| 	digest "github.com/opencontainers/go-digest" | 	digest "github.com/opencontainers/go-digest" | ||||||
| @@ -691,15 +690,10 @@ func isCheckpointPathExist(runtime string, v interface{}) bool { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	switch runtime { | 	switch runtime { | ||||||
| 	case plugin.RuntimeRuncV1, plugin.RuntimeRuncV2: | 	case plugin.RuntimeRuncV2: | ||||||
| 		if opts, ok := v.(*options.CheckpointOptions); ok && opts.ImagePath != "" { | 		if opts, ok := v.(*options.CheckpointOptions); ok && opts.ImagePath != "" { | ||||||
| 			return true | 			return true | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 	case plugin.RuntimeLinuxV1: |  | ||||||
| 		if opts, ok := v.(*runctypes.CheckpointOptions); ok && opts.ImagePath != "" { |  | ||||||
| 			return true |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return false | 	return false | ||||||
|   | |||||||
							
								
								
									
										51
									
								
								task_opts.go
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								task_opts.go
									
									
									
									
									
								
							| @@ -28,7 +28,6 @@ import ( | |||||||
| 	"github.com/containerd/containerd/errdefs" | 	"github.com/containerd/containerd/errdefs" | ||||||
| 	"github.com/containerd/containerd/images" | 	"github.com/containerd/containerd/images" | ||||||
| 	"github.com/containerd/containerd/mount" | 	"github.com/containerd/containerd/mount" | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v2/runc/options" | 	"github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
| 	imagespec "github.com/opencontainers/image-spec/specs-go/v1" | 	imagespec "github.com/opencontainers/image-spec/specs-go/v1" | ||||||
| 	"github.com/opencontainers/runtime-spec/specs-go" | 	"github.com/opencontainers/runtime-spec/specs-go" | ||||||
| @@ -104,25 +103,14 @@ func WithCheckpointName(name string) CheckpointTaskOpts { | |||||||
| // WithCheckpointImagePath sets image path for checkpoint option | // WithCheckpointImagePath sets image path for checkpoint option | ||||||
| func WithCheckpointImagePath(path string) CheckpointTaskOpts { | func WithCheckpointImagePath(path string) CheckpointTaskOpts { | ||||||
| 	return func(r *CheckpointTaskInfo) error { | 	return func(r *CheckpointTaskInfo) error { | ||||||
| 		if CheckRuntime(r.Runtime(), "io.containerd.runc") { | 		if r.Options == nil { | ||||||
| 			if r.Options == nil { | 			r.Options = &options.CheckpointOptions{} | ||||||
| 				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 |  | ||||||
| 		} | 		} | ||||||
|  | 		opts, ok := r.Options.(*options.CheckpointOptions) | ||||||
|  | 		if !ok { | ||||||
|  | 			return errors.New("invalid v2 shim checkpoint options format") | ||||||
|  | 		} | ||||||
|  | 		opts.ImagePath = path | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -130,25 +118,14 @@ func WithCheckpointImagePath(path string) CheckpointTaskOpts { | |||||||
| // WithRestoreImagePath sets image path for create option | // WithRestoreImagePath sets image path for create option | ||||||
| func WithRestoreImagePath(path string) NewTaskOpts { | func WithRestoreImagePath(path string) NewTaskOpts { | ||||||
| 	return func(ctx context.Context, c *Client, ti *TaskInfo) error { | 	return func(ctx context.Context, c *Client, ti *TaskInfo) error { | ||||||
| 		if CheckRuntime(ti.Runtime(), "io.containerd.runc") { | 		if ti.Options == nil { | ||||||
| 			if ti.Options == nil { | 			ti.Options = &options.Options{} | ||||||
| 				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 |  | ||||||
| 		} | 		} | ||||||
|  | 		opts, ok := ti.Options.(*options.Options) | ||||||
|  | 		if !ok { | ||||||
|  | 			return errors.New("invalid v2 shim create options format") | ||||||
|  | 		} | ||||||
|  | 		opts.CriuImagePath = path | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,84 +22,47 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"errors" | 	"errors" | ||||||
|  |  | ||||||
| 	"github.com/containerd/containerd/runtime/linux/runctypes" |  | ||||||
| 	"github.com/containerd/containerd/runtime/v2/runc/options" | 	"github.com/containerd/containerd/runtime/v2/runc/options" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // WithNoNewKeyring causes tasks not to be created with a new keyring for secret storage. | // 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 | // There is an upper limit on the number of keyrings in a linux system | ||||||
| func WithNoNewKeyring(ctx context.Context, c *Client, ti *TaskInfo) error { | func WithNoNewKeyring(ctx context.Context, c *Client, ti *TaskInfo) error { | ||||||
| 	if CheckRuntime(ti.Runtime(), "io.containerd.runc") { | 	if ti.Options == nil { | ||||||
| 		if ti.Options == nil { | 		ti.Options = &options.Options{} | ||||||
| 			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.(*options.Options) | ||||||
|  | 	if !ok { | ||||||
|  | 		return errors.New("invalid v2 shim create options format") | ||||||
|  | 	} | ||||||
|  | 	opts.NoNewKeyring = true | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // WithNoPivotRoot instructs the runtime not to you pivot_root | // WithNoPivotRoot instructs the runtime not to you pivot_root | ||||||
| func WithNoPivotRoot(_ context.Context, _ *Client, ti *TaskInfo) error { | func WithNoPivotRoot(_ context.Context, _ *Client, ti *TaskInfo) error { | ||||||
| 	if CheckRuntime(ti.Runtime(), "io.containerd.runc") { | 	if ti.Options == nil { | ||||||
| 		if ti.Options == nil { | 		ti.Options = &options.Options{} | ||||||
| 			ti.Options = &options.Options{} |  | ||||||
| 		} |  | ||||||
| 		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 := ti.Options.(*options.Options) | ||||||
|  | 	if !ok { | ||||||
|  | 		return errors.New("invalid v2 shim create options format") | ||||||
|  | 	} | ||||||
|  | 	opts.NoPivotRoot = true | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // WithShimCgroup sets the existing cgroup for the shim | // WithShimCgroup sets the existing cgroup for the shim | ||||||
| func WithShimCgroup(path string) NewTaskOpts { | func WithShimCgroup(path string) NewTaskOpts { | ||||||
| 	return func(ctx context.Context, c *Client, ti *TaskInfo) error { | 	return func(ctx context.Context, c *Client, ti *TaskInfo) error { | ||||||
| 		if CheckRuntime(ti.Runtime(), "io.containerd.runc") { | 		if ti.Options == nil { | ||||||
| 			if ti.Options == nil { | 			ti.Options = &options.Options{} | ||||||
| 				ti.Options = &options.Options{} |  | ||||||
| 			} |  | ||||||
| 			opts, ok := ti.Options.(*options.Options) |  | ||||||
| 			if !ok { |  | ||||||
| 				return errors.New("invalid v2 shim create options format") |  | ||||||
| 			} |  | ||||||
| 			opts.ShimCgroup = path |  | ||||||
| 		} 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.ShimCgroup = path |  | ||||||
| 		} | 		} | ||||||
|  | 		opts, ok := ti.Options.(*options.Options) | ||||||
|  | 		if !ok { | ||||||
|  | 			return errors.New("invalid v2 shim create options format") | ||||||
|  | 		} | ||||||
|  | 		opts.ShimCgroup = path | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -107,25 +70,14 @@ func WithShimCgroup(path string) NewTaskOpts { | |||||||
| // WithUIDOwner allows console I/O to work with the remapped UID in user namespace | // WithUIDOwner allows console I/O to work with the remapped UID in user namespace | ||||||
| func WithUIDOwner(uid uint32) NewTaskOpts { | func WithUIDOwner(uid uint32) NewTaskOpts { | ||||||
| 	return func(ctx context.Context, c *Client, ti *TaskInfo) error { | 	return func(ctx context.Context, c *Client, ti *TaskInfo) error { | ||||||
| 		if CheckRuntime(ti.Runtime(), "io.containerd.runc") { | 		if ti.Options == nil { | ||||||
| 			if ti.Options == nil { | 			ti.Options = &options.Options{} | ||||||
| 				ti.Options = &options.Options{} |  | ||||||
| 			} |  | ||||||
| 			opts, ok := ti.Options.(*options.Options) |  | ||||||
| 			if !ok { |  | ||||||
| 				return errors.New("invalid v2 shim create options format") |  | ||||||
| 			} |  | ||||||
| 			opts.IoUid = uid |  | ||||||
| 		} 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.IoUid = uid |  | ||||||
| 		} | 		} | ||||||
|  | 		opts, ok := ti.Options.(*options.Options) | ||||||
|  | 		if !ok { | ||||||
|  | 			return errors.New("invalid v2 shim create options format") | ||||||
|  | 		} | ||||||
|  | 		opts.IoUid = uid | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -133,25 +85,14 @@ func WithUIDOwner(uid uint32) NewTaskOpts { | |||||||
| // WithGIDOwner allows console I/O to work with the remapped GID in user namespace | // WithGIDOwner allows console I/O to work with the remapped GID in user namespace | ||||||
| func WithGIDOwner(gid uint32) NewTaskOpts { | func WithGIDOwner(gid uint32) NewTaskOpts { | ||||||
| 	return func(ctx context.Context, c *Client, ti *TaskInfo) error { | 	return func(ctx context.Context, c *Client, ti *TaskInfo) error { | ||||||
| 		if CheckRuntime(ti.Runtime(), "io.containerd.runc") { | 		if ti.Options == nil { | ||||||
| 			if ti.Options == nil { | 			ti.Options = &options.Options{} | ||||||
| 				ti.Options = &options.Options{} |  | ||||||
| 			} |  | ||||||
| 			opts, ok := ti.Options.(*options.Options) |  | ||||||
| 			if !ok { |  | ||||||
| 				return errors.New("invalid v2 shim create options format") |  | ||||||
| 			} |  | ||||||
| 			opts.IoGid = gid |  | ||||||
| 		} 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.IoGid = gid |  | ||||||
| 		} | 		} | ||||||
|  | 		opts, ok := ti.Options.(*options.Options) | ||||||
|  | 		if !ok { | ||||||
|  | 			return errors.New("invalid v2 shim create options format") | ||||||
|  | 		} | ||||||
|  | 		opts.IoGid = gid | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Akihiro Suda
					Akihiro Suda