summaryrefslogtreecommitdiffhomepage
path: root/pkg/shim
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/shim')
-rw-r--r--pkg/shim/BUILD (renamed from pkg/shim/v2/BUILD)14
-rw-r--r--pkg/shim/api.go (renamed from pkg/shim/v2/api.go)3
-rw-r--r--pkg/shim/epoll.go (renamed from pkg/shim/v2/epoll.go)2
-rw-r--r--pkg/shim/options.go50
-rw-r--r--pkg/shim/proc/BUILD (renamed from pkg/shim/v1/proc/BUILD)2
-rw-r--r--pkg/shim/proc/deleted_state.go (renamed from pkg/shim/v1/proc/deleted_state.go)0
-rw-r--r--pkg/shim/proc/exec.go (renamed from pkg/shim/v1/proc/exec.go)0
-rw-r--r--pkg/shim/proc/exec_state.go (renamed from pkg/shim/v1/proc/exec_state.go)0
-rw-r--r--pkg/shim/proc/init.go (renamed from pkg/shim/v1/proc/init.go)8
-rw-r--r--pkg/shim/proc/init_state.go (renamed from pkg/shim/v1/proc/init_state.go)4
-rw-r--r--pkg/shim/proc/io.go (renamed from pkg/shim/v1/proc/io.go)0
-rw-r--r--pkg/shim/proc/proc.go (renamed from pkg/shim/v1/proc/process.go)2
-rw-r--r--pkg/shim/proc/types.go (renamed from pkg/shim/v1/proc/types.go)1
-rw-r--r--pkg/shim/proc/utils.go (renamed from pkg/shim/v1/proc/utils.go)18
-rw-r--r--pkg/shim/runsc/runsc.go30
-rw-r--r--pkg/shim/runsc/utils.go15
-rw-r--r--pkg/shim/runtimeoptions/BUILD (renamed from pkg/shim/v2/runtimeoptions/BUILD)2
-rw-r--r--pkg/shim/runtimeoptions/runtimeoptions.go (renamed from pkg/shim/v2/runtimeoptions/runtimeoptions.go)0
-rw-r--r--pkg/shim/runtimeoptions/runtimeoptions.proto (renamed from pkg/shim/v2/runtimeoptions/runtimeoptions.proto)0
-rw-r--r--pkg/shim/runtimeoptions/runtimeoptions_cri.go (renamed from pkg/shim/v2/runtimeoptions/runtimeoptions_cri.go)0
-rw-r--r--pkg/shim/runtimeoptions/runtimeoptions_test.go (renamed from pkg/shim/v2/runtimeoptions/runtimeoptions_test.go)0
-rw-r--r--pkg/shim/service.go (renamed from pkg/shim/v2/service.go)437
-rw-r--r--pkg/shim/service_linux.go (renamed from pkg/shim/v2/service_linux.go)2
-rw-r--r--pkg/shim/state.go48
-rw-r--r--pkg/shim/utils/BUILD (renamed from pkg/shim/v1/utils/BUILD)0
-rw-r--r--pkg/shim/utils/annotations.go (renamed from pkg/shim/v1/utils/annotations.go)0
-rw-r--r--pkg/shim/utils/utils.go (renamed from pkg/shim/v1/utils/utils.go)1
-rw-r--r--pkg/shim/utils/volumes.go (renamed from pkg/shim/v1/utils/volumes.go)0
-rw-r--r--pkg/shim/utils/volumes_test.go (renamed from pkg/shim/v1/utils/volumes_test.go)0
-rw-r--r--pkg/shim/v1/shim/BUILD40
-rw-r--r--pkg/shim/v1/shim/api.go28
-rw-r--r--pkg/shim/v1/shim/platform.go106
-rw-r--r--pkg/shim/v1/shim/service.go573
-rw-r--r--pkg/shim/v2/options/BUILD11
-rw-r--r--pkg/shim/v2/options/options.go33
35 files changed, 443 insertions, 987 deletions
diff --git a/pkg/shim/v2/BUILD b/pkg/shim/BUILD
index 7e0a114a0..4f7c02f5d 100644
--- a/pkg/shim/v2/BUILD
+++ b/pkg/shim/BUILD
@@ -3,23 +3,26 @@ load("//tools:defs.bzl", "go_library")
package(licenses = ["notice"])
go_library(
- name = "v2",
+ name = "shim",
srcs = [
"api.go",
"epoll.go",
+ "options.go",
"service.go",
"service_linux.go",
+ "state.go",
],
visibility = ["//shim:__subpackages__"],
deps = [
+ "//pkg/cleanup",
+ "//pkg/shim/proc",
"//pkg/shim/runsc",
- "//pkg/shim/v1/proc",
- "//pkg/shim/v1/utils",
- "//pkg/shim/v2/options",
- "//pkg/shim/v2/runtimeoptions",
+ "//pkg/shim/runtimeoptions",
+ "//pkg/shim/utils",
"//runsc/specutils",
"@com_github_burntsushi_toml//:go_default_library",
"@com_github_containerd_cgroups//:go_default_library",
+ "@com_github_containerd_cgroups//stats/v1:go_default_library",
"@com_github_containerd_console//:go_default_library",
"@com_github_containerd_containerd//api/events:go_default_library",
"@com_github_containerd_containerd//api/types/task:go_default_library",
@@ -38,6 +41,7 @@ go_library(
"@com_github_containerd_fifo//:go_default_library",
"@com_github_containerd_typeurl//:go_default_library",
"@com_github_gogo_protobuf//types:go_default_library",
+ "@com_github_sirupsen_logrus//:go_default_library",
"@org_golang_x_sys//unix:go_default_library",
],
)
diff --git a/pkg/shim/v2/api.go b/pkg/shim/api.go
index dbe5c59f6..6d1741f0c 100644
--- a/pkg/shim/v2/api.go
+++ b/pkg/shim/api.go
@@ -13,10 +13,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package v2
+package shim
import (
"github.com/containerd/containerd/api/events"
)
+// TaskOOM is an alias for events.TaskOOM.
type TaskOOM = events.TaskOOM
diff --git a/pkg/shim/v2/epoll.go b/pkg/shim/epoll.go
index 41232cca8..737d2b781 100644
--- a/pkg/shim/v2/epoll.go
+++ b/pkg/shim/epoll.go
@@ -15,7 +15,7 @@
// +build linux
-package v2
+package shim
import (
"context"
diff --git a/pkg/shim/options.go b/pkg/shim/options.go
new file mode 100644
index 000000000..e40a1a07d
--- /dev/null
+++ b/pkg/shim/options.go
@@ -0,0 +1,50 @@
+// Copyright 2018 The gVisor 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
+//
+// https://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
+
+const optionsType = "io.containerd.runsc.v1.options"
+
+// options is runtime options for io.containerd.runsc.v1.
+type options struct {
+ // ShimCgroup is the cgroup the shim should be in.
+ ShimCgroup string `toml:"shim_cgroup" json:"shimCgroup"`
+
+ // IoUID is the I/O's pipes uid.
+ IoUID uint32 `toml:"io_uid" json:"ioUid"`
+
+ // IoGID is the I/O's pipes gid.
+ IoGID uint32 `toml:"io_gid" json:"ioGid"`
+
+ // BinaryName is the binary name of the runsc binary.
+ BinaryName string `toml:"binary_name" json:"binaryName"`
+
+ // Root is the runsc root directory.
+ Root string `toml:"root" json:"root"`
+
+ // LogLevel sets the logging level. Some of the possible values are: debug,
+ // info, warning.
+ //
+ // This configuration only applies when the shim is running as a service.
+ LogLevel string `toml:"log_level" json:"logLevel"`
+
+ // LogPath is the path to log directory. %ID% tags inside the string are
+ // replaced with the container ID.
+ //
+ // This configuration only applies when the shim is running as a service.
+ LogPath string `toml:"log_path" json:"logPath"`
+
+ // RunscConfig is a key/value map of all runsc flags.
+ RunscConfig map[string]string `toml:"runsc_config" json:"runscConfig"`
+}
diff --git a/pkg/shim/v1/proc/BUILD b/pkg/shim/proc/BUILD
index 4377306af..544bdc170 100644
--- a/pkg/shim/v1/proc/BUILD
+++ b/pkg/shim/proc/BUILD
@@ -11,7 +11,7 @@ go_library(
"init.go",
"init_state.go",
"io.go",
- "process.go",
+ "proc.go",
"types.go",
"utils.go",
],
diff --git a/pkg/shim/v1/proc/deleted_state.go b/pkg/shim/proc/deleted_state.go
index d9b970c4d..d9b970c4d 100644
--- a/pkg/shim/v1/proc/deleted_state.go
+++ b/pkg/shim/proc/deleted_state.go
diff --git a/pkg/shim/v1/proc/exec.go b/pkg/shim/proc/exec.go
index 1d1d90488..1d1d90488 100644
--- a/pkg/shim/v1/proc/exec.go
+++ b/pkg/shim/proc/exec.go
diff --git a/pkg/shim/v1/proc/exec_state.go b/pkg/shim/proc/exec_state.go
index 4dcda8b44..4dcda8b44 100644
--- a/pkg/shim/v1/proc/exec_state.go
+++ b/pkg/shim/proc/exec_state.go
diff --git a/pkg/shim/v1/proc/init.go b/pkg/shim/proc/init.go
index dab3123d6..cacaade88 100644
--- a/pkg/shim/v1/proc/init.go
+++ b/pkg/shim/proc/init.go
@@ -39,9 +39,6 @@ import (
"gvisor.dev/gvisor/pkg/shim/runsc"
)
-// InitPidFile name of the file that contains the init pid.
-const InitPidFile = "init.pid"
-
// Init represents an initial process for a container.
type Init struct {
wg sync.WaitGroup
@@ -122,7 +119,8 @@ func (p *Init) Create(ctx context.Context, r *CreateConfig) (err error) {
return fmt.Errorf("failed to create OCI runtime io pipes: %w", err)
}
}
- pidFile := filepath.Join(p.Bundle, InitPidFile)
+ // pidFile is the file that will contain the sandbox pid.
+ pidFile := filepath.Join(p.Bundle, "init.pid")
opts := &runsc.CreateOpts{
PidFile: pidFile,
}
@@ -397,7 +395,7 @@ func (p *Init) Exec(ctx context.Context, path string, r *ExecConfig) (process.Pr
}
// exec returns a new exec'd process.
-func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (process.Process, error) {
+func (p *Init) exec(path string, r *ExecConfig) (process.Process, error) {
// process exec request
var spec specs.Process
if err := json.Unmarshal(r.Spec.Value, &spec); err != nil {
diff --git a/pkg/shim/v1/proc/init_state.go b/pkg/shim/proc/init_state.go
index 9233ecc85..0065fc385 100644
--- a/pkg/shim/v1/proc/init_state.go
+++ b/pkg/shim/proc/init_state.go
@@ -95,7 +95,7 @@ func (s *createdState) SetExited(status int) {
}
func (s *createdState) Exec(ctx context.Context, path string, r *ExecConfig) (process.Process, error) {
- return s.p.exec(ctx, path, r)
+ return s.p.exec(path, r)
}
type runningState struct {
@@ -137,7 +137,7 @@ func (s *runningState) SetExited(status int) {
}
func (s *runningState) Exec(ctx context.Context, path string, r *ExecConfig) (process.Process, error) {
- return s.p.exec(ctx, path, r)
+ return s.p.exec(path, r)
}
type stoppedState struct {
diff --git a/pkg/shim/v1/proc/io.go b/pkg/shim/proc/io.go
index 34d825fb7..34d825fb7 100644
--- a/pkg/shim/v1/proc/io.go
+++ b/pkg/shim/proc/io.go
diff --git a/pkg/shim/v1/proc/process.go b/pkg/shim/proc/proc.go
index d462c3eef..edba3fca5 100644
--- a/pkg/shim/v1/proc/process.go
+++ b/pkg/shim/proc/proc.go
@@ -13,6 +13,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package proc is responsible to manage the communication between the shim and
+// the sandbox process running the container.
package proc
import (
diff --git a/pkg/shim/v1/proc/types.go b/pkg/shim/proc/types.go
index 2b0df4663..fc182cf5e 100644
--- a/pkg/shim/v1/proc/types.go
+++ b/pkg/shim/proc/types.go
@@ -40,7 +40,6 @@ type CreateConfig struct {
Stdin string
Stdout string
Stderr string
- Options *types.Any
}
// ExecConfig holds exec creation configuration.
diff --git a/pkg/shim/v1/proc/utils.go b/pkg/shim/proc/utils.go
index 716de2f59..7c2c409af 100644
--- a/pkg/shim/v1/proc/utils.go
+++ b/pkg/shim/proc/utils.go
@@ -67,24 +67,6 @@ func getLastRuntimeError(r *runsc.Runsc) (string, error) {
return errMsg, nil
}
-func copyFile(to, from string) error {
- ff, err := os.Open(from)
- if err != nil {
- return err
- }
- defer ff.Close()
- tt, err := os.Create(to)
- if err != nil {
- return err
- }
- defer tt.Close()
-
- p := bufPool.Get().(*[]byte)
- defer bufPool.Put(p)
- _, err = io.CopyBuffer(tt, ff, *p)
- return err
-}
-
func hasNoIO(r *CreateConfig) bool {
return r.Stdin == "" && r.Stdout == "" && r.Stderr == ""
}
diff --git a/pkg/shim/runsc/runsc.go b/pkg/shim/runsc/runsc.go
index e7c9640ba..aedaf5ee5 100644
--- a/pkg/shim/runsc/runsc.go
+++ b/pkg/shim/runsc/runsc.go
@@ -13,6 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package runsc provides an API to interact with runsc command line.
package runsc
import (
@@ -33,12 +34,32 @@ import (
specs "github.com/opencontainers/runtime-spec/specs-go"
)
-// Monitor is the default process monitor to be used by runsc.
-var Monitor runc.ProcessMonitor = runc.Monitor
-
// DefaultCommand is the default command for Runsc.
const DefaultCommand = "runsc"
+// Monitor is the default process monitor to be used by runsc.
+var Monitor runc.ProcessMonitor = &LogMonitor{Next: runc.Monitor}
+
+// LogMonitor implements the runc.ProcessMonitor interface, logging the command
+// that is getting executed, and then forwarding the call to another
+// implementation.
+type LogMonitor struct {
+ Next runc.ProcessMonitor
+}
+
+// Start implements runc.ProcessMonitor.
+func (l *LogMonitor) Start(cmd *exec.Cmd) (chan runc.Exit, error) {
+ log.L.Debugf("Executing: %s", cmd.Args)
+ return l.Next.Start(cmd)
+}
+
+// Wait implements runc.ProcessMonitor.
+func (l *LogMonitor) Wait(cmd *exec.Cmd, ch chan runc.Exit) (int, error) {
+ status, err := l.Next.Wait(cmd, ch)
+ log.L.Debugf("Command exit code: %d, err: %v", status, err)
+ return status, err
+}
+
// Runsc is the client to the runsc cli.
type Runsc struct {
Command string
@@ -370,9 +391,10 @@ func (r *Runsc) Stats(context context.Context, id string) (*runc.Stats, error) {
}()
var e runc.Event
if err := json.NewDecoder(rd).Decode(&e); err != nil {
+ log.L.Debugf("Parsing events error: %v", err)
return nil, err
}
- log.L.Debugf("Stats returned: %+v", e.Stats)
+ log.L.Debugf("Stats returned, type: %s, stats: %+v", e.Type, e.Stats)
if e.Type != "stats" {
return nil, fmt.Errorf(`unexpected event type %q, wanted "stats"`, e.Type)
}
diff --git a/pkg/shim/runsc/utils.go b/pkg/shim/runsc/utils.go
index c514b3bc7..55f17d29e 100644
--- a/pkg/shim/runsc/utils.go
+++ b/pkg/shim/runsc/utils.go
@@ -36,9 +36,20 @@ func putBuf(b *bytes.Buffer) {
bytesBufferPool.Put(b)
}
-// FormatLogPath parses runsc config, and fill in %ID% in the log path.
-func FormatLogPath(id string, config map[string]string) {
+// FormatRunscLogPath parses runsc config, and fill in %ID% in the log path.
+func FormatRunscLogPath(id string, config map[string]string) {
if path, ok := config["debug-log"]; ok {
config["debug-log"] = strings.Replace(path, "%ID%", id, -1)
}
}
+
+// FormatShimLogPath creates the file path to the log file. It replaces %ID%
+// in the path with the provided "id". It also uses a default log name if the
+// path end with '/'.
+func FormatShimLogPath(path string, id string) string {
+ if strings.HasSuffix(path, "/") {
+ // Default format: <path>/runsc-shim-<ID>.log
+ path += "runsc-shim-%ID%.log"
+ }
+ return strings.Replace(path, "%ID%", id, -1)
+}
diff --git a/pkg/shim/v2/runtimeoptions/BUILD b/pkg/shim/runtimeoptions/BUILD
index abb8c3be3..029be7c09 100644
--- a/pkg/shim/v2/runtimeoptions/BUILD
+++ b/pkg/shim/runtimeoptions/BUILD
@@ -15,7 +15,7 @@ go_library(
"runtimeoptions.go",
"runtimeoptions_cri.go",
],
- visibility = ["//pkg/shim/v2:__pkg__"],
+ visibility = ["//pkg/shim:__pkg__"],
deps = ["@com_github_gogo_protobuf//proto:go_default_library"],
)
diff --git a/pkg/shim/v2/runtimeoptions/runtimeoptions.go b/pkg/shim/runtimeoptions/runtimeoptions.go
index 072dd87f0..072dd87f0 100644
--- a/pkg/shim/v2/runtimeoptions/runtimeoptions.go
+++ b/pkg/shim/runtimeoptions/runtimeoptions.go
diff --git a/pkg/shim/v2/runtimeoptions/runtimeoptions.proto b/pkg/shim/runtimeoptions/runtimeoptions.proto
index 057032e34..057032e34 100644
--- a/pkg/shim/v2/runtimeoptions/runtimeoptions.proto
+++ b/pkg/shim/runtimeoptions/runtimeoptions.proto
diff --git a/pkg/shim/v2/runtimeoptions/runtimeoptions_cri.go b/pkg/shim/runtimeoptions/runtimeoptions_cri.go
index e6102b4cf..e6102b4cf 100644
--- a/pkg/shim/v2/runtimeoptions/runtimeoptions_cri.go
+++ b/pkg/shim/runtimeoptions/runtimeoptions_cri.go
diff --git a/pkg/shim/v2/runtimeoptions/runtimeoptions_test.go b/pkg/shim/runtimeoptions/runtimeoptions_test.go
index c59a2400e..c59a2400e 100644
--- a/pkg/shim/v2/runtimeoptions/runtimeoptions_test.go
+++ b/pkg/shim/runtimeoptions/runtimeoptions_test.go
diff --git a/pkg/shim/v2/service.go b/pkg/shim/service.go
index 1534152fc..9aba26ac7 100644
--- a/pkg/shim/v2/service.go
+++ b/pkg/shim/service.go
@@ -12,12 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package v2
+// Package shim implements Containerd Shim v2 interface.
+package shim
import (
"context"
"fmt"
- "io/ioutil"
+ "io"
"os"
"os/exec"
"path/filepath"
@@ -27,6 +28,7 @@ import (
"github.com/BurntSushi/toml"
"github.com/containerd/cgroups"
+ cgroupsstats "github.com/containerd/cgroups/stats/v1"
"github.com/containerd/console"
"github.com/containerd/containerd/api/events"
"github.com/containerd/containerd/api/types/task"
@@ -43,13 +45,14 @@ import (
"github.com/containerd/containerd/sys/reaper"
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/types"
+ "github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
+ "gvisor.dev/gvisor/pkg/cleanup"
+ "gvisor.dev/gvisor/pkg/shim/proc"
"gvisor.dev/gvisor/pkg/shim/runsc"
- "gvisor.dev/gvisor/pkg/shim/v1/proc"
- "gvisor.dev/gvisor/pkg/shim/v1/utils"
- "gvisor.dev/gvisor/pkg/shim/v2/options"
- "gvisor.dev/gvisor/pkg/shim/v2/runtimeoptions"
+ "gvisor.dev/gvisor/pkg/shim/runtimeoptions"
+ "gvisor.dev/gvisor/pkg/shim/utils"
"gvisor.dev/gvisor/runsc/specutils"
)
@@ -65,55 +68,108 @@ var (
var _ = (taskAPI.TaskService)(&service{})
-// configFile is the default config file name. For containerd 1.2,
-// we assume that a config.toml should exist in the runtime root.
-const configFile = "config.toml"
+const (
+ // configFile is the default config file name. For containerd 1.2,
+ // we assume that a config.toml should exist in the runtime root.
+ configFile = "config.toml"
+
+ // shimAddressPath is the relative path to a file that contains the address
+ // to the shim UDS. See service.shimAddress.
+ shimAddressPath = "address"
+)
// New returns a new shim service that can be used via GRPC.
func New(ctx context.Context, id string, publisher shim.Publisher, cancel func()) (shim.Shim, error) {
+ log.L.Debugf("service.New, id: %s", id)
+
+ var opts shim.Opts
+ if ctxOpts := ctx.Value(shim.OptsKey{}); ctxOpts != nil {
+ opts = ctxOpts.(shim.Opts)
+ }
+
ep, err := newOOMEpoller(publisher)
if err != nil {
return nil, err
}
go ep.run(ctx)
s := &service{
- id: id,
- context: ctx,
- processes: make(map[string]process.Process),
- events: make(chan interface{}, 128),
- ec: proc.ExitCh,
- oomPoller: ep,
- cancel: cancel,
- }
- go s.processExits()
- runsc.Monitor = reaper.Default
+ id: id,
+ processes: make(map[string]process.Process),
+ events: make(chan interface{}, 128),
+ ec: proc.ExitCh,
+ oomPoller: ep,
+ cancel: cancel,
+ genericOptions: opts,
+ }
+ go s.processExits(ctx)
+ runsc.Monitor = &runsc.LogMonitor{Next: reaper.Default}
if err := s.initPlatform(); err != nil {
cancel()
return nil, fmt.Errorf("failed to initialized platform behavior: %w", err)
}
- go s.forward(publisher)
+ go s.forward(ctx, publisher)
+
+ if address, err := shim.ReadAddress(shimAddressPath); err == nil {
+ s.shimAddress = address
+ }
+
return s, nil
}
-// service is the shim implementation of a remote shim over GRPC.
+// service is the shim implementation of a remote shim over GRPC. It runs in 2
+// different modes:
+// 1. Service: process runs for the life time of the container and receives
+// calls described in shimapi.TaskService interface.
+// 2. Tool: process is short lived and runs only to perform the requested
+// operations and then exits. It implements the direct functions in
+// shim.Shim interface.
+//
+// When the service is running, it saves a json file with state information so
+// that commands sent to the tool can load the state and perform the operation.
type service struct {
mu sync.Mutex
- context context.Context
- task process.Process
+ // id is the container ID.
+ id string
+
+ // bundle is a path provided by the caller on container creation. Store
+ // because it's needed in commands that don't receive bundle in the request.
+ bundle string
+
+ // task is the main process that is running the container.
+ task *proc.Init
+
+ // processes maps ExecId to processes running through exec.
processes map[string]process.Process
- events chan interface{}
- platform stdio.Platform
- opts options.Options
- ec chan proc.Exit
+
+ events chan interface{}
+
+ // platform handles operations related to the console.
+ platform stdio.Platform
+
+ // genericOptions are options that come from the shim interface and are common
+ // to all shims.
+ genericOptions shim.Opts
+
+ // opts are configuration options specific for this shim.
+ opts options
+
+ // ex gets notified whenever the container init process or an exec'd process
+ // exits from inside the sandbox.
+ ec chan proc.Exit
+
+ // oomPoller monitors the sandbox's cgroup for OOM notifications.
oomPoller *epoller
- id string
- bundle string
+ // cancel is a function that needs to be called before the shim stops. The
+ // function is provided by the caller to New().
cancel func()
+
+ // shimAddress is the location of the UDS used to communicate to containerd.
+ shimAddress string
}
-func newCommand(ctx context.Context, containerdBinary, containerdAddress string) (*exec.Cmd, error) {
+func (s *service) newCommand(ctx context.Context, containerdBinary, containerdAddress string) (*exec.Cmd, error) {
ns, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return nil, err
@@ -131,6 +187,9 @@ func newCommand(ctx context.Context, containerdBinary, containerdAddress string)
"-address", containerdAddress,
"-publish-binary", containerdBinary,
}
+ if s.genericOptions.Debug {
+ args = append(args, "-debug")
+ }
cmd := exec.Command(self, args...)
cmd.Dir = cwd
cmd.Env = append(os.Environ(), "GOMAXPROCS=2")
@@ -141,50 +200,78 @@ func newCommand(ctx context.Context, containerdBinary, containerdAddress string)
}
func (s *service) StartShim(ctx context.Context, id, containerdBinary, containerdAddress, containerdTTRPCAddress string) (string, error) {
- cmd, err := newCommand(ctx, containerdBinary, containerdAddress)
+ log.L.Debugf("StartShim, id: %s, binary: %q, address: %q", id, containerdBinary, containerdAddress)
+
+ cmd, err := s.newCommand(ctx, containerdBinary, containerdAddress)
if err != nil {
return "", err
}
- address, err := shim.SocketAddress(ctx, id)
+ address, err := shim.SocketAddress(ctx, containerdAddress, id)
if err != nil {
return "", err
}
socket, err := shim.NewSocket(address)
if err != nil {
- return "", err
+ // The only time where this would happen is if there is a bug and the socket
+ // was not cleaned up in the cleanup method of the shim or we are using the
+ // grouping functionality where the new process should be run with the same
+ // shim as an existing container.
+ if !shim.SocketEaddrinuse(err) {
+ return "", fmt.Errorf("create new shim socket: %w", err)
+ }
+ if shim.CanConnect(address) {
+ if err := shim.WriteAddress(shimAddressPath, address); err != nil {
+ return "", fmt.Errorf("write existing socket for shim: %w", err)
+ }
+ return address, nil
+ }
+ if err := shim.RemoveSocket(address); err != nil {
+ return "", fmt.Errorf("remove pre-existing socket: %w", err)
+ }
+ if socket, err = shim.NewSocket(address); err != nil {
+ return "", fmt.Errorf("try create new shim socket 2x: %w", err)
+ }
}
- defer socket.Close()
+ cu := cleanup.Make(func() {
+ socket.Close()
+ _ = shim.RemoveSocket(address)
+ })
+ defer cu.Clean()
+
f, err := socket.File()
if err != nil {
return "", err
}
- defer f.Close()
cmd.ExtraFiles = append(cmd.ExtraFiles, f)
+ log.L.Debugf("Executing: %q %s", cmd.Path, cmd.Args)
if err := cmd.Start(); err != nil {
+ f.Close()
return "", err
}
- defer func() {
- if err != nil {
- cmd.Process.Kill()
- }
- }()
+ cu.Add(func() { 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 err := shim.WriteAddress("address", address); err != nil {
+ if err := shim.WriteAddress(shimAddressPath, address); err != nil {
return "", err
}
if err := shim.SetScore(cmd.Process.Pid); err != nil {
return "", fmt.Errorf("failed to set OOM Score on shim: %w", err)
}
+ cu.Release()
return address, nil
}
+// Cleanup is called from another process (need to reload state) to stop the
+// container and undo all operations done in Create().
func (s *service) Cleanup(ctx context.Context) (*taskAPI.DeleteResponse, error) {
+ log.L.Debugf("Cleanup")
+
path, err := os.Getwd()
if err != nil {
return nil, err
@@ -193,18 +280,19 @@ func (s *service) Cleanup(ctx context.Context) (*taskAPI.DeleteResponse, error)
if err != nil {
return nil, err
}
- runtime, err := s.readRuntime(path)
- if err != nil {
+ var st state
+ if err := st.load(path); err != nil {
return nil, err
}
- r := proc.NewRunsc(s.opts.Root, path, ns, runtime, nil)
+ r := proc.NewRunsc(s.opts.Root, path, ns, st.Options.BinaryName, nil)
+
if err := r.Delete(ctx, s.id, &runsc.DeleteOpts{
Force: true,
}); err != nil {
- log.L.Printf("failed to remove runc container: %v", err)
+ log.L.Infof("failed to remove runc container: %v", err)
}
- if err := mount.UnmountAll(filepath.Join(path, "rootfs"), 0); err != nil {
- log.L.Printf("failed to cleanup rootfs mount: %v", err)
+ if err := mount.UnmountAll(st.Rootfs, 0); err != nil {
+ log.L.Infof("failed to cleanup rootfs mount: %v", err)
}
return &taskAPI.DeleteResponse{
ExitedAt: time.Now(),
@@ -212,31 +300,24 @@ func (s *service) Cleanup(ctx context.Context) (*taskAPI.DeleteResponse, error)
}, nil
}
-func (s *service) readRuntime(path string) (string, error) {
- data, err := ioutil.ReadFile(filepath.Join(path, "runtime"))
- if err != nil {
- return "", err
- }
- return string(data), nil
-}
-
-func (s *service) writeRuntime(path, runtime string) error {
- return ioutil.WriteFile(filepath.Join(path, "runtime"), []byte(runtime), 0600)
-}
-
// Create creates 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) {
+func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (*taskAPI.CreateTaskResponse, error) {
+ log.L.Debugf("Create, id: %s, bundle: %q", r.ID, r.Bundle)
+
s.mu.Lock()
defer s.mu.Unlock()
+ // Save the main task id and bundle to the shim for additional requests.
+ s.id = r.ID
+ s.bundle = r.Bundle
+
ns, err := namespaces.NamespaceRequired(ctx)
if err != nil {
return nil, fmt.Errorf("create namespace: %w", err)
}
// Read from root for now.
- var opts options.Options
if r.Options != nil {
v, err := typeurl.UnmarshalAny(r.Options)
if err != nil {
@@ -245,16 +326,16 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *
var path string
switch o := v.(type) {
case *runctypes.CreateOptions: // containerd 1.2.x
- opts.IoUid = o.IoUid
- opts.IoGid = o.IoGid
- opts.ShimCgroup = o.ShimCgroup
+ s.opts.IoUID = o.IoUid
+ s.opts.IoGID = o.IoGid
+ s.opts.ShimCgroup = o.ShimCgroup
case *runctypes.RuncOptions: // containerd 1.2.x
root := proc.RunscRoot
if o.RuntimeRoot != "" {
root = o.RuntimeRoot
}
- opts.BinaryName = o.Runtime
+ s.opts.BinaryName = o.Runtime
path = filepath.Join(root, configFile)
if _, err := os.Stat(path); err != nil {
@@ -268,7 +349,7 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *
if o.ConfigPath == "" {
break
}
- if o.TypeUrl != options.OptionType {
+ if o.TypeUrl != optionsType {
return nil, fmt.Errorf("unsupported option type %q", o.TypeUrl)
}
path = o.ConfigPath
@@ -276,12 +357,61 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *
return nil, fmt.Errorf("unsupported option type %q", r.Options.TypeUrl)
}
if path != "" {
- if _, err = toml.DecodeFile(path, &opts); err != nil {
+ if _, err = toml.DecodeFile(path, &s.opts); err != nil {
return nil, fmt.Errorf("decode config file %q: %w", path, err)
}
}
}
+ if len(s.opts.LogLevel) != 0 {
+ lvl, err := logrus.ParseLevel(s.opts.LogLevel)
+ if err != nil {
+ return nil, err
+ }
+ logrus.SetLevel(lvl)
+ }
+ if len(s.opts.LogPath) != 0 {
+ logPath := runsc.FormatShimLogPath(s.opts.LogPath, s.id)
+ if err := os.MkdirAll(filepath.Dir(logPath), 0777); err != nil {
+ return nil, fmt.Errorf("failed to create log dir: %w", err)
+ }
+ logFile, err := os.Create(logPath)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create log file: %w", err)
+ }
+ log.L.Debugf("Starting mirror log at %q", logPath)
+ std := logrus.StandardLogger()
+ std.SetOutput(io.MultiWriter(std.Out, logFile))
+
+ log.L.Debugf("Create shim")
+ log.L.Debugf("***************************")
+ log.L.Debugf("Args: %s", os.Args)
+ log.L.Debugf("PID: %d", os.Getpid())
+ log.L.Debugf("ID: %s", s.id)
+ log.L.Debugf("Options: %+v", s.opts)
+ log.L.Debugf("Bundle: %s", r.Bundle)
+ log.L.Debugf("Terminal: %t", r.Terminal)
+ log.L.Debugf("stdin: %s", r.Stdin)
+ log.L.Debugf("stdout: %s", r.Stdout)
+ log.L.Debugf("stderr: %s", r.Stderr)
+ log.L.Debugf("***************************")
+ }
+
+ // Save state before any action is taken to ensure Cleanup() will have all
+ // the information it needs to undo the operations.
+ st := state{
+ Rootfs: filepath.Join(r.Bundle, "rootfs"),
+ Options: s.opts,
+ }
+ if err := st.save(r.Bundle); err != nil {
+ return nil, err
+ }
+
+ if err := os.Mkdir(st.Rootfs, 0711); err != nil && !os.IsExist(err) {
+ return nil, err
+ }
+
+ // Convert from types.Mount to proc.Mount.
var mounts []proc.Mount
for _, m := range r.Rootfs {
mounts = append(mounts, proc.Mount{
@@ -292,62 +422,41 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *
})
}
- rootfs := filepath.Join(r.Bundle, "rootfs")
- if err := os.Mkdir(rootfs, 0711); err != nil && !os.IsExist(err) {
- return nil, err
+ // Cleans up all mounts in case of failure.
+ cu := cleanup.Make(func() {
+ if err := mount.UnmountAll(st.Rootfs, 0); err != nil {
+ log.L.Infof("failed to cleanup rootfs mount: %v", err)
+ }
+ })
+ defer cu.Clean()
+ for _, rm := range mounts {
+ m := &mount.Mount{
+ Type: rm.Type,
+ Source: rm.Source,
+ Options: rm.Options,
+ }
+ if err := m.Mount(st.Rootfs); err != nil {
+ return nil, fmt.Errorf("failed to mount rootfs component %v: %w", m, err)
+ }
}
config := &proc.CreateConfig{
ID: r.ID,
Bundle: r.Bundle,
- Runtime: opts.BinaryName,
+ Runtime: s.opts.BinaryName,
Rootfs: mounts,
Terminal: r.Terminal,
Stdin: r.Stdin,
Stdout: r.Stdout,
Stderr: r.Stderr,
- Options: r.Options,
- }
- if err := s.writeRuntime(r.Bundle, opts.BinaryName); err != nil {
- return nil, err
}
- defer func() {
- if err != nil {
- if err := mount.UnmountAll(rootfs, 0); err != nil {
- log.L.Printf("failed to cleanup rootfs mount: %v", err)
- }
- }
- }()
- for _, rm := range mounts {
- m := &mount.Mount{
- Type: rm.Type,
- Source: rm.Source,
- Options: rm.Options,
- }
- if err := m.Mount(rootfs); err != nil {
- return nil, fmt.Errorf("failed to mount rootfs component %v: %w", m, err)
- }
- }
- process, err := newInit(
- ctx,
- r.Bundle,
- filepath.Join(r.Bundle, "work"),
- ns,
- s.platform,
- config,
- &opts,
- rootfs,
- )
+ process, err := newInit(r.Bundle, filepath.Join(r.Bundle, "work"), ns, s.platform, config, &s.opts, st.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
// Set up OOM notification on the sandbox's cgroup. This is done on
// sandbox create since the sandbox process will be created here.
@@ -361,16 +470,19 @@ func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *
return nil, fmt.Errorf("add cg to OOM monitor: %w", err)
}
}
+
+ // Success
+ cu.Release()
s.task = process
- s.opts = opts
return &taskAPI.CreateTaskResponse{
Pid: uint32(process.Pid()),
}, nil
-
}
// Start starts a process.
func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.StartResponse, error) {
+ log.L.Debugf("Start, id: %s, execID: %s", r.ID, r.ExecID)
+
p, err := s.getProcess(r.ExecID)
if err != nil {
return nil, err
@@ -387,6 +499,8 @@ func (s *service) Start(ctx context.Context, r *taskAPI.StartRequest) (*taskAPI.
// Delete deletes the initial process and container.
func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAPI.DeleteResponse, error) {
+ log.L.Debugf("Delete, id: %s, execID: %s", r.ID, r.ExecID)
+
p, err := s.getProcess(r.ExecID)
if err != nil {
return nil, err
@@ -397,13 +511,11 @@ func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAP
if err := p.Delete(ctx); err != nil {
return nil, err
}
- isTask := r.ExecID == ""
- if !isTask {
+ if len(r.ExecID) != 0 {
s.mu.Lock()
delete(s.processes, r.ExecID)
s.mu.Unlock()
- }
- if isTask && s.platform != nil {
+ } else if s.platform != nil {
s.platform.Close()
}
return &taskAPI.DeleteResponse{
@@ -415,17 +527,18 @@ func (s *service) Delete(ctx context.Context, r *taskAPI.DeleteRequest) (*taskAP
// Exec spawns an additional process inside the container.
func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*types.Empty, error) {
+ log.L.Debugf("Exec, id: %s, execID: %s", r.ID, r.ExecID)
+
s.mu.Lock()
p := s.processes[r.ExecID]
s.mu.Unlock()
if p != nil {
return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ExecID)
}
- p = s.task
- if p == nil {
+ if s.task == nil {
return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
}
- process, err := p.(*proc.Init).Exec(ctx, s.bundle, &proc.ExecConfig{
+ process, err := s.task.Exec(ctx, s.bundle, &proc.ExecConfig{
ID: r.ExecID,
Terminal: r.Terminal,
Stdin: r.Stdin,
@@ -444,6 +557,8 @@ func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*typ
// ResizePty resizes the terminal of a process.
func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*types.Empty, error) {
+ log.L.Debugf("ResizePty, id: %s, execID: %s, dimension: %dx%d", r.ID, r.ExecID, r.Height, r.Width)
+
p, err := s.getProcess(r.ExecID)
if err != nil {
return nil, err
@@ -460,6 +575,8 @@ func (s *service) ResizePty(ctx context.Context, r *taskAPI.ResizePtyRequest) (*
// State returns runtime state information for a process.
func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI.StateResponse, error) {
+ log.L.Debugf("State, id: %s, execID: %s", r.ID, r.ExecID)
+
p, err := s.getProcess(r.ExecID)
if err != nil {
return nil, err
@@ -494,16 +611,20 @@ func (s *service) State(ctx context.Context, r *taskAPI.StateRequest) (*taskAPI.
// Pause the container.
func (s *service) Pause(ctx context.Context, r *taskAPI.PauseRequest) (*types.Empty, error) {
+ log.L.Debugf("Pause, id: %s", r.ID)
return empty, errdefs.ToGRPC(errdefs.ErrNotImplemented)
}
// Resume the container.
func (s *service) Resume(ctx context.Context, r *taskAPI.ResumeRequest) (*types.Empty, error) {
+ log.L.Debugf("Resume, id: %s", r.ID)
return empty, errdefs.ToGRPC(errdefs.ErrNotImplemented)
}
// Kill a process with the provided signal.
func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*types.Empty, error) {
+ log.L.Debugf("Kill, id: %s, execID: %s, signal: %d, all: %t", r.ID, r.ExecID, r.Signal, r.All)
+
p, err := s.getProcess(r.ExecID)
if err != nil {
return nil, err
@@ -519,6 +640,8 @@ func (s *service) Kill(ctx context.Context, r *taskAPI.KillRequest) (*types.Empt
// Pids returns all pids inside the container.
func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.PidsResponse, error) {
+ log.L.Debugf("Pids, id: %s", r.ID)
+
pids, err := s.getContainerPids(ctx, r.ID)
if err != nil {
return nil, errdefs.ToGRPC(err)
@@ -550,6 +673,8 @@ func (s *service) Pids(ctx context.Context, r *taskAPI.PidsRequest) (*taskAPI.Pi
// CloseIO closes the I/O context of a process.
func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*types.Empty, error) {
+ log.L.Debugf("CloseIO, id: %s, execID: %s, stdin: %t", r.ID, r.ExecID, r.Stdin)
+
p, err := s.getProcess(r.ExecID)
if err != nil {
return nil, err
@@ -564,11 +689,14 @@ func (s *service) CloseIO(ctx context.Context, r *taskAPI.CloseIORequest) (*type
// Checkpoint checkpoints the container.
func (s *service) Checkpoint(ctx context.Context, r *taskAPI.CheckpointTaskRequest) (*types.Empty, error) {
+ log.L.Debugf("Checkpoint, id: %s", r.ID)
return empty, errdefs.ToGRPC(errdefs.ErrNotImplemented)
}
// Connect returns shim information such as the shim's pid.
func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*taskAPI.ConnectResponse, error) {
+ log.L.Debugf("Connect, id: %s", r.ID)
+
var pid int
if s.task != nil {
pid = s.task.Pid()
@@ -580,27 +708,24 @@ func (s *service) Connect(ctx context.Context, r *taskAPI.ConnectRequest) (*task
}
func (s *service) Shutdown(ctx context.Context, r *taskAPI.ShutdownRequest) (*types.Empty, error) {
+ log.L.Debugf("Shutdown, id: %s", r.ID)
s.cancel()
+ if s.shimAddress != "" {
+ _ = shim.RemoveSocket(s.shimAddress)
+ }
os.Exit(0)
- return empty, nil
+ panic("Should not get here")
}
func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) {
- path, err := os.Getwd()
- if err != nil {
- return nil, err
- }
- ns, err := namespaces.NamespaceRequired(ctx)
- if err != nil {
- return nil, err
- }
- runtime, err := s.readRuntime(path)
- if err != nil {
- return nil, err
+ log.L.Debugf("Stats, id: %s", r.ID)
+ if s.task == nil {
+ log.L.Debugf("Stats error, id: %s: container not created", r.ID)
+ return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
}
- rs := proc.NewRunsc(s.opts.Root, path, ns, runtime, nil)
- stats, err := rs.Stats(ctx, s.id)
+ stats, err := s.task.Runtime().Stats(ctx, s.id)
if err != nil {
+ log.L.Debugf("Stats error, id: %s: %v", r.ID, err)
return nil, err
}
@@ -611,55 +736,58 @@ func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.
// as runc.
//
// [0]: https://github.com/google/gvisor/blob/277a0d5a1fbe8272d4729c01ee4c6e374d047ebc/runsc/boot/events.go#L61-L81
- data, err := typeurl.MarshalAny(&cgroups.Metrics{
- CPU: &cgroups.CPUStat{
- Usage: &cgroups.CPUUsage{
+ metrics := &cgroupsstats.Metrics{
+ CPU: &cgroupsstats.CPUStat{
+ Usage: &cgroupsstats.CPUUsage{
Total: stats.Cpu.Usage.Total,
Kernel: stats.Cpu.Usage.Kernel,
User: stats.Cpu.Usage.User,
PerCPU: stats.Cpu.Usage.Percpu,
},
- Throttling: &cgroups.Throttle{
+ Throttling: &cgroupsstats.Throttle{
Periods: stats.Cpu.Throttling.Periods,
ThrottledPeriods: stats.Cpu.Throttling.ThrottledPeriods,
ThrottledTime: stats.Cpu.Throttling.ThrottledTime,
},
},
- Memory: &cgroups.MemoryStat{
+ Memory: &cgroupsstats.MemoryStat{
Cache: stats.Memory.Cache,
- Usage: &cgroups.MemoryEntry{
+ Usage: &cgroupsstats.MemoryEntry{
Limit: stats.Memory.Usage.Limit,
Usage: stats.Memory.Usage.Usage,
Max: stats.Memory.Usage.Max,
Failcnt: stats.Memory.Usage.Failcnt,
},
- Swap: &cgroups.MemoryEntry{
+ Swap: &cgroupsstats.MemoryEntry{
Limit: stats.Memory.Swap.Limit,
Usage: stats.Memory.Swap.Usage,
Max: stats.Memory.Swap.Max,
Failcnt: stats.Memory.Swap.Failcnt,
},
- Kernel: &cgroups.MemoryEntry{
+ Kernel: &cgroupsstats.MemoryEntry{
Limit: stats.Memory.Kernel.Limit,
Usage: stats.Memory.Kernel.Usage,
Max: stats.Memory.Kernel.Max,
Failcnt: stats.Memory.Kernel.Failcnt,
},
- KernelTCP: &cgroups.MemoryEntry{
+ KernelTCP: &cgroupsstats.MemoryEntry{
Limit: stats.Memory.KernelTCP.Limit,
Usage: stats.Memory.KernelTCP.Usage,
Max: stats.Memory.KernelTCP.Max,
Failcnt: stats.Memory.KernelTCP.Failcnt,
},
},
- Pids: &cgroups.PidsStat{
+ Pids: &cgroupsstats.PidsStat{
Current: stats.Pids.Current,
Limit: stats.Pids.Limit,
},
- })
+ }
+ data, err := typeurl.MarshalAny(metrics)
if err != nil {
+ log.L.Debugf("Stats error, id: %s: %v", r.ID, err)
return nil, err
}
+ log.L.Debugf("Stats success, id: %s: %+v", r.ID, data)
return &taskAPI.StatsResponse{
Stats: data,
}, nil
@@ -672,6 +800,8 @@ func (s *service) Update(ctx context.Context, r *taskAPI.UpdateTaskRequest) (*ty
// Wait waits for a process to exit.
func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.WaitResponse, error) {
+ log.L.Debugf("Wait, id: %s, execID: %s", r.ID, r.ExecID)
+
p, err := s.getProcess(r.ExecID)
if err != nil {
return nil, err
@@ -687,21 +817,22 @@ func (s *service) Wait(ctx context.Context, r *taskAPI.WaitRequest) (*taskAPI.Wa
}, nil
}
-func (s *service) processExits() {
+func (s *service) processExits(ctx context.Context) {
for e := range s.ec {
- s.checkProcesses(e)
+ s.checkProcesses(ctx, e)
}
}
-func (s *service) checkProcesses(e proc.Exit) {
+func (s *service) checkProcesses(ctx context.Context, e proc.Exit) {
// TODO(random-liu): Add `shouldKillAll` logic if container pid
// namespace is supported.
for _, p := range s.allProcesses() {
if p.ID() == e.ID {
if ip, ok := p.(*proc.Init); ok {
// Ensure all children are killed.
- if err := ip.KillAll(s.context); err != nil {
- log.G(s.context).WithError(err).WithField("id", ip.ID()).
+ log.L.Debugf("Container init process exited, killing all container processes")
+ if err := ip.KillAll(ctx); err != nil {
+ log.G(ctx).WithError(err).WithField("id", ip.ID()).
Error("failed to kill init's children")
}
}
@@ -737,7 +868,7 @@ func (s *service) getContainerPids(ctx context.Context, id string) ([]uint32, er
if p == nil {
return nil, fmt.Errorf("container must be created: %w", errdefs.ErrFailedPrecondition)
}
- ps, err := p.(*proc.Init).Runtime().Ps(ctx, id)
+ ps, err := p.Runtime().Ps(ctx, id)
if err != nil {
return nil, err
}
@@ -748,11 +879,9 @@ func (s *service) getContainerPids(ctx context.Context, id string) ([]uint32, er
return pids, nil
}
-func (s *service) forward(publisher shim.Publisher) {
+func (s *service) forward(ctx context.Context, publisher shim.Publisher) {
for e := range s.events {
- ctx, cancel := context.WithTimeout(s.context, 5*time.Second)
err := publisher.Publish(ctx, getTopic(e), e)
- cancel()
if err != nil {
// Should not happen.
panic(fmt.Errorf("post event: %w", err))
@@ -790,12 +919,12 @@ func getTopic(e interface{}) string {
case *events.TaskExecStarted:
return runtime.TaskExecStartedEventTopic
default:
- log.L.Printf("no topic for type %#v", e)
+ log.L.Infof("no topic for type %#v", e)
}
return runtime.TaskUnknownTopic
}
-func newInit(ctx context.Context, path, workDir, namespace string, platform stdio.Platform, r *proc.CreateConfig, options *options.Options, rootfs string) (*proc.Init, error) {
+func newInit(path, workDir, namespace string, platform stdio.Platform, r *proc.CreateConfig, options *options, rootfs string) (*proc.Init, error) {
spec, err := utils.ReadSpec(r.Bundle)
if err != nil {
return nil, fmt.Errorf("read oci spec: %w", err)
@@ -803,7 +932,7 @@ func newInit(ctx context.Context, path, workDir, namespace string, platform stdi
if err := utils.UpdateVolumeAnnotations(r.Bundle, spec); err != nil {
return nil, fmt.Errorf("update volume annotations: %w", err)
}
- runsc.FormatLogPath(r.ID, options.RunscConfig)
+ runsc.FormatRunscLogPath(r.ID, options.RunscConfig)
runtime := proc.NewRunsc(options.Root, path, namespace, options.BinaryName, options.RunscConfig)
p := proc.New(r.ID, runtime, stdio.Stdio{
Stdin: r.Stdin,
@@ -815,8 +944,8 @@ func newInit(ctx context.Context, path, workDir, namespace string, platform stdi
p.Platform = platform
p.Rootfs = rootfs
p.WorkDir = workDir
- p.IoUID = int(options.IoUid)
- p.IoGID = int(options.IoGid)
+ p.IoUID = int(options.IoUID)
+ p.IoGID = int(options.IoGID)
p.Sandbox = specutils.SpecContainerType(spec) == specutils.ContainerTypeSandbox
p.UserLog = utils.UserLogPath(spec)
p.Monitor = reaper.Default
diff --git a/pkg/shim/v2/service_linux.go b/pkg/shim/service_linux.go
index 1800ab90b..11622ed60 100644
--- a/pkg/shim/v2/service_linux.go
+++ b/pkg/shim/service_linux.go
@@ -15,7 +15,7 @@
// +build linux
-package v2
+package shim
import (
"context"
diff --git a/pkg/shim/state.go b/pkg/shim/state.go
new file mode 100644
index 000000000..5e9e92ec3
--- /dev/null
+++ b/pkg/shim/state.go
@@ -0,0 +1,48 @@
+// Copyright 2020 The gVisor 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
+//
+// https://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 (
+ "encoding/json"
+ "io/ioutil"
+ "path/filepath"
+)
+
+const filename = "state.json"
+
+// state holds information needed between shim invocations.
+type state struct {
+ // Rootfs is the full path to the location rootfs was mounted.
+ Rootfs string `json:"rootfs"`
+
+ // Options is the configuration loaded from config.toml.
+ Options options `json:"options"`
+}
+
+func (s state) load(path string) error {
+ data, err := ioutil.ReadFile(filepath.Join(path, filename))
+ if err != nil {
+ return err
+ }
+ return json.Unmarshal(data, &s)
+}
+
+func (s state) save(path string) error {
+ data, err := json.Marshal(&s)
+ if err != nil {
+ return err
+ }
+ return ioutil.WriteFile(filepath.Join(path, filename), data, 0644)
+}
diff --git a/pkg/shim/v1/utils/BUILD b/pkg/shim/utils/BUILD
index 54a0aabb7..54a0aabb7 100644
--- a/pkg/shim/v1/utils/BUILD
+++ b/pkg/shim/utils/BUILD
diff --git a/pkg/shim/v1/utils/annotations.go b/pkg/shim/utils/annotations.go
index 1e9d3f365..1e9d3f365 100644
--- a/pkg/shim/v1/utils/annotations.go
+++ b/pkg/shim/utils/annotations.go
diff --git a/pkg/shim/v1/utils/utils.go b/pkg/shim/utils/utils.go
index 07e346654..7b1cd983e 100644
--- a/pkg/shim/v1/utils/utils.go
+++ b/pkg/shim/utils/utils.go
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// Package utils container miscellaneous utility function used by the shim.
package utils
import (
diff --git a/pkg/shim/v1/utils/volumes.go b/pkg/shim/utils/volumes.go
index 52a428179..52a428179 100644
--- a/pkg/shim/v1/utils/volumes.go
+++ b/pkg/shim/utils/volumes.go
diff --git a/pkg/shim/v1/utils/volumes_test.go b/pkg/shim/utils/volumes_test.go
index 3e02c6151..3e02c6151 100644
--- a/pkg/shim/v1/utils/volumes_test.go
+++ b/pkg/shim/utils/volumes_test.go
diff --git a/pkg/shim/v1/shim/BUILD b/pkg/shim/v1/shim/BUILD
deleted file mode 100644
index 05c595bc9..000000000
--- a/pkg/shim/v1/shim/BUILD
+++ /dev/null
@@ -1,40 +0,0 @@
-load("//tools:defs.bzl", "go_library")
-
-package(licenses = ["notice"])
-
-go_library(
- name = "shim",
- srcs = [
- "api.go",
- "platform.go",
- "service.go",
- ],
- visibility = [
- "//pkg/shim:__subpackages__",
- "//shim:__subpackages__",
- ],
- deps = [
- "//pkg/shim/runsc",
- "//pkg/shim/v1/proc",
- "//pkg/shim/v1/utils",
- "@com_github_containerd_console//:go_default_library",
- "@com_github_containerd_containerd//api/events:go_default_library",
- "@com_github_containerd_containerd//api/types/task:go_default_library",
- "@com_github_containerd_containerd//errdefs:go_default_library",
- "@com_github_containerd_containerd//events:go_default_library",
- "@com_github_containerd_containerd//log:go_default_library",
- "@com_github_containerd_containerd//mount:go_default_library",
- "@com_github_containerd_containerd//namespaces:go_default_library",
- "@com_github_containerd_containerd//pkg/process:go_default_library",
- "@com_github_containerd_containerd//pkg/stdio:go_default_library",
- "@com_github_containerd_containerd//runtime:go_default_library",
- "@com_github_containerd_containerd//runtime/linux/runctypes:go_default_library",
- "@com_github_containerd_containerd//runtime/v1/shim/v1:go_default_library",
- "@com_github_containerd_containerd//sys/reaper:go_default_library",
- "@com_github_containerd_fifo//:go_default_library",
- "@com_github_containerd_typeurl//:go_default_library",
- "@com_github_gogo_protobuf//types:go_default_library",
- "@org_golang_google_grpc//codes:go_default_library",
- "@org_golang_google_grpc//status:go_default_library",
- ],
-)
diff --git a/pkg/shim/v1/shim/api.go b/pkg/shim/v1/shim/api.go
deleted file mode 100644
index 5dd8ff172..000000000
--- a/pkg/shim/v1/shim/api.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2018 The containerd Authors.
-// Copyright 2019 The gVisor 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
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package shim
-
-import (
- "github.com/containerd/containerd/api/events"
-)
-
-type TaskCreate = events.TaskCreate
-type TaskStart = events.TaskStart
-type TaskOOM = events.TaskOOM
-type TaskExit = events.TaskExit
-type TaskDelete = events.TaskDelete
-type TaskExecAdded = events.TaskExecAdded
-type TaskExecStarted = events.TaskExecStarted
diff --git a/pkg/shim/v1/shim/platform.go b/pkg/shim/v1/shim/platform.go
deleted file mode 100644
index f590f80ef..000000000
--- a/pkg/shim/v1/shim/platform.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2018 The containerd Authors.
-// Copyright 2019 The gVisor 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
-//
-// https://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"
- "sync"
- "syscall"
-
- "github.com/containerd/console"
- "github.com/containerd/fifo"
-)
-
-type linuxPlatform struct {
- epoller *console.Epoller
-}
-
-func (p *linuxPlatform) CopyConsole(ctx context.Context, console console.Console, stdin, stdout, stderr string, wg *sync.WaitGroup) (console.Console, error) {
- if p.epoller == nil {
- return nil, fmt.Errorf("uninitialized epoller")
- }
-
- epollConsole, err := p.epoller.Add(console)
- if err != nil {
- return nil, err
- }
-
- if stdin != "" {
- in, err := fifo.OpenFifo(ctx, stdin, syscall.O_RDONLY, 0)
- if err != nil {
- return nil, err
- }
- go func() {
- p := bufPool.Get().(*[]byte)
- defer bufPool.Put(p)
- io.CopyBuffer(epollConsole, in, *p)
- }()
- }
-
- 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)
- go func() {
- p := bufPool.Get().(*[]byte)
- defer bufPool.Put(p)
- io.CopyBuffer(outw, epollConsole, *p)
- epollConsole.Close()
- outr.Close()
- outw.Close()
- wg.Done()
- }()
- return epollConsole, nil
-}
-
-func (p *linuxPlatform) ShutdownConsole(ctx context.Context, cons console.Console) error {
- if p.epoller == nil {
- return fmt.Errorf("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
-}
diff --git a/pkg/shim/v1/shim/service.go b/pkg/shim/v1/shim/service.go
deleted file mode 100644
index 84a810cb2..000000000
--- a/pkg/shim/v1/shim/service.go
+++ /dev/null
@@ -1,573 +0,0 @@
-// Copyright 2018 The containerd Authors.
-// Copyright 2019 The gVisor 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
-//
-// https://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"
- "os"
- "path/filepath"
- "sync"
-
- "github.com/containerd/console"
- "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/runtime"
- "github.com/containerd/containerd/runtime/linux/runctypes"
- shim "github.com/containerd/containerd/runtime/v1/shim/v1"
- "github.com/containerd/containerd/sys/reaper"
- "github.com/containerd/typeurl"
- "github.com/gogo/protobuf/types"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/status"
-
- "gvisor.dev/gvisor/pkg/shim/runsc"
- "gvisor.dev/gvisor/pkg/shim/v1/proc"
- "gvisor.dev/gvisor/pkg/shim/v1/utils"
-)
-
-var (
- empty = &types.Empty{}
- bufPool = sync.Pool{
- New: func() interface{} {
- buffer := make([]byte, 32<<10)
- return &buffer
- },
- }
-)
-
-// Config contains shim specific configuration.
-type Config struct {
- Path string
- Namespace string
- WorkDir string
- RuntimeRoot string
- RunscConfig map[string]string
-}
-
-// 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)
- s := &Service{
- config: config,
- context: ctx,
- processes: make(map[string]process.Process),
- events: make(chan interface{}, 128),
- ec: proc.ExitCh,
- }
- 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 proc.Exit
-
- // Filled by Create()
- id string
- bundle string
-}
-
-// Create creates a new initial process and container with the underlying OCI runtime.
-func (s *Service) Create(ctx context.Context, r *shim.CreateTaskRequest) (_ *shim.CreateTaskResponse, err error) {
- s.mu.Lock()
- defer s.mu.Unlock()
-
- var mounts []proc.Mount
- for _, m := range r.Rootfs {
- mounts = append(mounts, proc.Mount{
- Type: m.Type,
- Source: m.Source,
- Target: m.Target,
- Options: m.Options,
- })
- }
-
- rootfs := filepath.Join(r.Bundle, "rootfs")
- if err := os.Mkdir(rootfs, 0711); err != nil && !os.IsExist(err) {
- return nil, err
- }
-
- config := &proc.CreateConfig{
- ID: r.ID,
- Bundle: r.Bundle,
- Runtime: r.Runtime,
- Rootfs: mounts,
- Terminal: r.Terminal,
- Stdin: r.Stdin,
- Stdout: r.Stdout,
- Stderr: r.Stderr,
- Options: r.Options,
- }
- defer func() {
- if err != nil {
- if err2 := mount.UnmountAll(rootfs, 0); err2 != nil {
- log.G(ctx).WithError(err2).Warn("Failed to cleanup rootfs mount")
- }
- }
- }()
- for _, rm := range mounts {
- m := &mount.Mount{
- Type: rm.Type,
- Source: rm.Source,
- Options: rm.Options,
- }
- if err := m.Mount(rootfs); err != nil {
- return nil, fmt.Errorf("failed to mount rootfs component %v: %w", m, err)
- }
- }
- process, err := newInit(
- ctx,
- s.config.Path,
- s.config.WorkDir,
- s.config.RuntimeRoot,
- s.config.Namespace,
- s.config.RunscConfig,
- s.platform,
- config,
- )
- 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 &shim.CreateTaskResponse{
- Pid: uint32(pid),
- }, nil
-}
-
-// Start starts a process.
-func (s *Service) Start(ctx context.Context, r *shim.StartRequest) (*shim.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 &shim.StartResponse{
- ID: p.ID(),
- Pid: uint32(p.Pid()),
- }, nil
-}
-
-// Delete deletes the initial process and container.
-func (s *Service) Delete(ctx context.Context, r *types.Empty) (*shim.DeleteResponse, error) {
- p, err := s.getInitProcess()
- if err != nil {
- return nil, err
- }
- if err := p.Delete(ctx); err != nil {
- return nil, err
- }
- s.mu.Lock()
- delete(s.processes, s.id)
- s.mu.Unlock()
- s.platform.Close()
- return &shim.DeleteResponse{
- ExitStatus: uint32(p.ExitStatus()),
- ExitedAt: p.ExitedAt(),
- Pid: uint32(p.Pid()),
- }, nil
-}
-
-// DeleteProcess deletes an exec'd process.
-func (s *Service) DeleteProcess(ctx context.Context, r *shim.DeleteProcessRequest) (*shim.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, err
- }
- s.mu.Lock()
- delete(s.processes, r.ID)
- s.mu.Unlock()
- return &shim.DeleteResponse{
- ExitStatus: uint32(p.ExitStatus()),
- ExitedAt: p.ExitedAt(),
- Pid: uint32(p.Pid()),
- }, nil
-}
-
-// Exec spawns an additional process inside the container.
-func (s *Service) Exec(ctx context.Context, r *shim.ExecProcessRequest) (*types.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.(*proc.Init).Exec(ctx, s.config.Path, &proc.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 resises the terminal of a process.
-func (s *Service) ResizePty(ctx context.Context, r *shim.ResizePtyRequest) (*types.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),
- }
- p, err := s.getExecProcess(r.ID)
- if err != nil {
- return nil, err
- }
- 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 *shim.StateRequest) (*shim.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.StatusUnknown
- switch st {
- case "created":
- status = task.StatusCreated
- case "running":
- status = task.StatusRunning
- case "stopped":
- status = task.StatusStopped
- }
- sio := p.Stdio()
- return &shim.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: p.ExitedAt(),
- }, nil
-}
-
-// Pause pauses the container.
-func (s *Service) Pause(ctx context.Context, r *types.Empty) (*types.Empty, error) {
- return empty, errdefs.ToGRPC(errdefs.ErrNotImplemented)
-}
-
-// Resume resumes the container.
-func (s *Service) Resume(ctx context.Context, r *types.Empty) (*types.Empty, error) {
- return empty, errdefs.ToGRPC(errdefs.ErrNotImplemented)
-}
-
-// Kill kills a process with the provided signal.
-func (s *Service) Kill(ctx context.Context, r *shim.KillRequest) (*types.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 *shim.ListPidsRequest) (*shim.ListPidsResponse, error) {
- 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 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 = a
- break
- }
- }
- processes = append(processes, &pInfo)
- }
- return &shim.ListPidsResponse{
- Processes: processes,
- }, nil
-}
-
-// CloseIO closes the I/O context of a process.
-func (s *Service) CloseIO(ctx context.Context, r *shim.CloseIORequest) (*types.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 checkpoints the container.
-func (s *Service) Checkpoint(ctx context.Context, r *shim.CheckpointTaskRequest) (*types.Empty, error) {
- return empty, errdefs.ToGRPC(errdefs.ErrNotImplemented)
-}
-
-// ShimInfo returns shim information such as the shim's pid.
-func (s *Service) ShimInfo(ctx context.Context, r *types.Empty) (*shim.ShimInfoResponse, error) {
- return &shim.ShimInfoResponse{
- ShimPid: uint32(os.Getpid()),
- }, nil
-}
-
-// Update updates a running container.
-func (s *Service) Update(ctx context.Context, r *shim.UpdateTaskRequest) (*types.Empty, error) {
- return empty, errdefs.ToGRPC(errdefs.ErrNotImplemented)
-}
-
-// Wait waits for a process to exit.
-func (s *Service) Wait(ctx context.Context, r *shim.WaitRequest) (*shim.WaitResponse, error) {
- p, err := s.getExecProcess(r.ID)
- if err != nil {
- return nil, err
- }
- p.Wait()
-
- return &shim.WaitResponse{
- ExitStatus: uint32(p.ExitStatus()),
- ExitedAt: p.ExitedAt(),
- }, nil
-}
-
-func (s *Service) processExits() {
- for e := range s.ec {
- s.checkProcesses(e)
- }
-}
-
-func (s *Service) allProcesses() []process.Process {
- s.mu.Lock()
- defer s.mu.Unlock()
-
- res := make([]process.Process, 0, len(s.processes))
- for _, p := range s.processes {
- res = append(res, p)
- }
- return res
-}
-
-func (s *Service) checkProcesses(e proc.Exit) {
- for _, p := range s.allProcesses() {
- if p.ID() == e.ID {
- if ip, ok := p.(*proc.Init); ok {
- // Ensure all children are killed.
- 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 <- &TaskExit{
- ContainerID: s.id,
- ID: p.ID(),
- Pid: uint32(p.Pid()),
- ExitStatus: uint32(e.Status),
- ExitedAt: p.ExitedAt(),
- }
- return
- }
- }
-}
-
-func (s *Service) getContainerPids(ctx context.Context, id string) ([]uint32, error) {
- p, err := s.getInitProcess()
- if err != nil {
- return nil, err
- }
-
- ps, err := p.(*proc.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 the init 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 the given 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 *TaskCreate:
- return runtime.TaskCreateEventTopic
- case *TaskStart:
- return runtime.TaskStartEventTopic
- case *TaskOOM:
- return runtime.TaskOOMEventTopic
- case *TaskExit:
- return runtime.TaskExitEventTopic
- case *TaskDelete:
- return runtime.TaskDeleteEventTopic
- case *TaskExecAdded:
- return runtime.TaskExecAddedEventTopic
- case *TaskExecStarted:
- return runtime.TaskExecStartedEventTopic
- default:
- log.L.Printf("no topic for type %#v", e)
- }
- return runtime.TaskUnknownTopic
-}
-
-func newInit(ctx context.Context, path, workDir, runtimeRoot, namespace string, config map[string]string, platform stdio.Platform, r *proc.CreateConfig) (*proc.Init, error) {
- var options runctypes.CreateOptions
- if r.Options != nil {
- v, err := typeurl.UnmarshalAny(r.Options)
- if err != nil {
- return nil, err
- }
- options = *v.(*runctypes.CreateOptions)
- }
-
- spec, err := utils.ReadSpec(r.Bundle)
- if err != nil {
- return nil, fmt.Errorf("read oci spec: %w", err)
- }
- if err := utils.UpdateVolumeAnnotations(r.Bundle, spec); err != nil {
- return nil, fmt.Errorf("update volume annotations: %w", err)
- }
-
- runsc.FormatLogPath(r.ID, config)
- rootfs := filepath.Join(path, "rootfs")
- runtime := proc.NewRunsc(runtimeRoot, path, namespace, r.Runtime, config)
- p := proc.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.Sandbox = utils.IsSandbox(spec)
- p.UserLog = utils.UserLogPath(spec)
- p.Monitor = reaper.Default
- return p, nil
-}
diff --git a/pkg/shim/v2/options/BUILD b/pkg/shim/v2/options/BUILD
deleted file mode 100644
index ca212e874..000000000
--- a/pkg/shim/v2/options/BUILD
+++ /dev/null
@@ -1,11 +0,0 @@
-load("//tools:defs.bzl", "go_library")
-
-package(licenses = ["notice"])
-
-go_library(
- name = "options",
- srcs = [
- "options.go",
- ],
- visibility = ["//:sandbox"],
-)
diff --git a/pkg/shim/v2/options/options.go b/pkg/shim/v2/options/options.go
deleted file mode 100644
index de09f2f79..000000000
--- a/pkg/shim/v2/options/options.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2018 The gVisor 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
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package options
-
-const OptionType = "io.containerd.runsc.v1.options"
-
-// Options is runtime options for io.containerd.runsc.v1.
-type Options struct {
- // ShimCgroup is the cgroup the shim should be in.
- ShimCgroup string `toml:"shim_cgroup"`
- // IoUid is the I/O's pipes uid.
- IoUid uint32 `toml:"io_uid"`
- // IoUid is the I/O's pipes gid.
- IoGid uint32 `toml:"io_gid"`
- // BinaryName is the binary name of the runsc binary.
- BinaryName string `toml:"binary_name"`
- // Root is the runsc root directory.
- Root string `toml:"root"`
- // RunscConfig is a key/value map of all runsc flags.
- RunscConfig map[string]string `toml:"runsc_config"`
-}