diff options
author | Fabricio Voznika <fvoznika@google.com> | 2021-01-12 17:50:33 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-01-12 17:54:10 -0800 |
commit | 8b0f0b4d11e0938eec8da411323b2ce35976ab56 (patch) | |
tree | aab8e37ca51133da5bfa4a055ea0dfa0bda514cf /pkg/shim/v2 | |
parent | be2b9d75d75e0e7371cd868589d57f4ddee44781 (diff) |
Delete shim v1
gvisor-containerd-shim is not compatible with containerd 1.1 or earlier.
Starting from containerd 1.2, shim v2 is the preferred interface.
PiperOrigin-RevId: 351485556
Diffstat (limited to 'pkg/shim/v2')
-rw-r--r-- | pkg/shim/v2/BUILD | 47 | ||||
-rw-r--r-- | pkg/shim/v2/api.go | 23 | ||||
-rw-r--r-- | pkg/shim/v2/epoll.go | 129 | ||||
-rw-r--r-- | pkg/shim/v2/options.go | 50 | ||||
-rw-r--r-- | pkg/shim/v2/runtimeoptions/BUILD | 32 | ||||
-rw-r--r-- | pkg/shim/v2/runtimeoptions/runtimeoptions.go | 17 | ||||
-rw-r--r-- | pkg/shim/v2/runtimeoptions/runtimeoptions.proto | 25 | ||||
-rw-r--r-- | pkg/shim/v2/runtimeoptions/runtimeoptions_cri.go | 383 | ||||
-rw-r--r-- | pkg/shim/v2/runtimeoptions/runtimeoptions_test.go | 57 | ||||
-rw-r--r-- | pkg/shim/v2/service.go | 953 | ||||
-rw-r--r-- | pkg/shim/v2/service_linux.go | 108 | ||||
-rw-r--r-- | pkg/shim/v2/state.go | 48 |
12 files changed, 0 insertions, 1872 deletions
diff --git a/pkg/shim/v2/BUILD b/pkg/shim/v2/BUILD deleted file mode 100644 index b0e8daa51..000000000 --- a/pkg/shim/v2/BUILD +++ /dev/null @@ -1,47 +0,0 @@ -load("//tools:defs.bzl", "go_library") - -package(licenses = ["notice"]) - -go_library( - name = "v2", - srcs = [ - "api.go", - "epoll.go", - "options.go", - "service.go", - "service_linux.go", - "state.go", - ], - visibility = ["//shim:__subpackages__"], - deps = [ - "//pkg/cleanup", - "//pkg/shim/runsc", - "//pkg/shim/v1/proc", - "//pkg/shim/v1/utils", - "//pkg/shim/v2/runtimeoptions", - "//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", - "@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/v2/shim:go_default_library", - "@com_github_containerd_containerd//runtime/v2/task: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", - "@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/v2/api.go deleted file mode 100644 index 5a60a04db..000000000 --- a/pkg/shim/v2/api.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2018 The containerd Authors. -// 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 v2 - -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/v2/epoll.go deleted file mode 100644 index 41232cca8..000000000 --- a/pkg/shim/v2/epoll.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2018 The containerd Authors. -// 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. - -// +build linux - -package v2 - -import ( - "context" - "fmt" - "sync" - - "github.com/containerd/cgroups" - "github.com/containerd/containerd/events" - "github.com/containerd/containerd/runtime" - "golang.org/x/sys/unix" -) - -func newOOMEpoller(publisher events.Publisher) (*epoller, error) { - fd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC) - if err != nil { - return nil, err - } - return &epoller{ - fd: fd, - publisher: publisher, - set: make(map[uintptr]*item), - }, nil -} - -type epoller struct { - mu sync.Mutex - - fd int - publisher events.Publisher - set map[uintptr]*item -} - -type item struct { - id string - cg cgroups.Cgroup -} - -func (e *epoller) Close() error { - return unix.Close(e.fd) -} - -func (e *epoller) run(ctx context.Context) { - var events [128]unix.EpollEvent - for { - select { - case <-ctx.Done(): - e.Close() - return - default: - n, err := unix.EpollWait(e.fd, events[:], -1) - if err != nil { - if err == unix.EINTR || err == unix.EAGAIN { - continue - } - // Should not happen. - panic(fmt.Errorf("cgroups: epoll wait: %w", err)) - } - for i := 0; i < n; i++ { - e.process(ctx, uintptr(events[i].Fd)) - } - } - } -} - -func (e *epoller) add(id string, cg cgroups.Cgroup) error { - e.mu.Lock() - defer e.mu.Unlock() - fd, err := cg.OOMEventFD() - if err != nil { - return err - } - e.set[fd] = &item{ - id: id, - cg: cg, - } - event := unix.EpollEvent{ - Fd: int32(fd), - Events: unix.EPOLLHUP | unix.EPOLLIN | unix.EPOLLERR, - } - return unix.EpollCtl(e.fd, unix.EPOLL_CTL_ADD, int(fd), &event) -} - -func (e *epoller) process(ctx context.Context, fd uintptr) { - flush(fd) - e.mu.Lock() - i, ok := e.set[fd] - if !ok { - e.mu.Unlock() - return - } - e.mu.Unlock() - if i.cg.State() == cgroups.Deleted { - e.mu.Lock() - delete(e.set, fd) - e.mu.Unlock() - unix.Close(int(fd)) - return - } - if err := e.publisher.Publish(ctx, runtime.TaskOOMEventTopic, &TaskOOM{ - ContainerID: i.id, - }); err != nil { - // Should not happen. - panic(fmt.Errorf("publish OOM event: %w", err)) - } -} - -func flush(fd uintptr) error { - var buf [8]byte - _, err := unix.Read(int(fd), buf[:]) - return err -} diff --git a/pkg/shim/v2/options.go b/pkg/shim/v2/options.go deleted file mode 100644 index 9db33fd1f..000000000 --- a/pkg/shim/v2/options.go +++ /dev/null @@ -1,50 +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 v2 - -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/v2/runtimeoptions/BUILD b/pkg/shim/v2/runtimeoptions/BUILD deleted file mode 100644 index abb8c3be3..000000000 --- a/pkg/shim/v2/runtimeoptions/BUILD +++ /dev/null @@ -1,32 +0,0 @@ -load("//tools:defs.bzl", "go_library", "go_test", "proto_library") - -package(licenses = ["notice"]) - -proto_library( - name = "api", - srcs = [ - "runtimeoptions.proto", - ], -) - -go_library( - name = "runtimeoptions", - srcs = [ - "runtimeoptions.go", - "runtimeoptions_cri.go", - ], - visibility = ["//pkg/shim/v2:__pkg__"], - deps = ["@com_github_gogo_protobuf//proto:go_default_library"], -) - -go_test( - name = "runtimeoptions_test", - size = "small", - srcs = ["runtimeoptions_test.go"], - library = ":runtimeoptions", - deps = [ - "@com_github_containerd_containerd//runtime/v1/shim/v1:go_default_library", - "@com_github_containerd_typeurl//:go_default_library", - "@com_github_gogo_protobuf//proto:go_default_library", - ], -) diff --git a/pkg/shim/v2/runtimeoptions/runtimeoptions.go b/pkg/shim/v2/runtimeoptions/runtimeoptions.go deleted file mode 100644 index 072dd87f0..000000000 --- a/pkg/shim/v2/runtimeoptions/runtimeoptions.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2018 The containerd Authors. -// 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 runtimeoptions contains the runtimeoptions proto. -package runtimeoptions diff --git a/pkg/shim/v2/runtimeoptions/runtimeoptions.proto b/pkg/shim/v2/runtimeoptions/runtimeoptions.proto deleted file mode 100644 index 057032e34..000000000 --- a/pkg/shim/v2/runtimeoptions/runtimeoptions.proto +++ /dev/null @@ -1,25 +0,0 @@ -// 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. - -syntax = "proto3"; - -package cri.runtimeoptions.v1; - -// This is a version of the runtimeoptions CRI API that is vendored. -// -// Importing the full CRI package is a nightmare. -message Options { - string type_url = 1; - string config_path = 2; -} diff --git a/pkg/shim/v2/runtimeoptions/runtimeoptions_cri.go b/pkg/shim/v2/runtimeoptions/runtimeoptions_cri.go deleted file mode 100644 index e6102b4cf..000000000 --- a/pkg/shim/v2/runtimeoptions/runtimeoptions_cri.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2018 The containerd Authors. -// 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 runtimeoptions - -import ( - "fmt" - "io" - "reflect" - "strings" - - proto "github.com/gogo/protobuf/proto" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package - -type Options struct { - // TypeUrl specifies the type of the content inside the config file. - TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"` - // ConfigPath specifies the filesystem location of the config file - // used by the runtime. - ConfigPath string `protobuf:"bytes,2,opt,name=config_path,json=configPath,proto3" json:"config_path,omitempty"` -} - -func (m *Options) Reset() { *m = Options{} } -func (*Options) ProtoMessage() {} -func (*Options) Descriptor() ([]byte, []int) { return fileDescriptorApi, []int{0} } - -func (m *Options) GetTypeUrl() string { - if m != nil { - return m.TypeUrl - } - return "" -} - -func (m *Options) GetConfigPath() string { - if m != nil { - return m.ConfigPath - } - return "" -} - -func init() { - proto.RegisterType((*Options)(nil), "cri.runtimeoptions.v1.Options") -} - -func (m *Options) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalTo(dAtA) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Options) MarshalTo(dAtA []byte) (int, error) { - var i int - _ = i - var l int - _ = l - if len(m.TypeUrl) > 0 { - dAtA[i] = 0xa - i++ - i = encodeVarintApi(dAtA, i, uint64(len(m.TypeUrl))) - i += copy(dAtA[i:], m.TypeUrl) - } - if len(m.ConfigPath) > 0 { - dAtA[i] = 0x12 - i++ - i = encodeVarintApi(dAtA, i, uint64(len(m.ConfigPath))) - i += copy(dAtA[i:], m.ConfigPath) - } - return i, nil -} - -func encodeVarintApi(dAtA []byte, offset int, v uint64) int { - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return offset + 1 -} - -func (m *Options) Size() (n int) { - var l int - _ = l - l = len(m.TypeUrl) - if l > 0 { - n += 1 + l + sovApi(uint64(l)) - } - l = len(m.ConfigPath) - if l > 0 { - n += 1 + l + sovApi(uint64(l)) - } - return n -} - -func sovApi(x uint64) (n int) { - for { - n++ - x >>= 7 - if x == 0 { - break - } - } - return n -} - -func sozApi(x uint64) (n int) { - return sovApi(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} - -func (this *Options) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&Options{`, - `TypeUrl:` + fmt.Sprintf("%v", this.TypeUrl) + `,`, - `ConfigPath:` + fmt.Sprintf("%v", this.ConfigPath) + `,`, - `}`, - }, "") - return s -} - -func valueToStringApi(v interface{}) string { - rv := reflect.ValueOf(v) - if rv.IsNil() { - return "nil" - } - pv := reflect.Indirect(rv).Interface() - return fmt.Sprintf("*%v", pv) -} - -func (m *Options) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowApi - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Options: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Options: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TypeUrl", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowApi - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthApi - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.TypeUrl = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ConfigPath", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowApi - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthApi - } - postIndex := iNdEx + intStringLen - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ConfigPath = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipApi(dAtA[iNdEx:]) - if err != nil { - return err - } - if skippy < 0 { - return ErrInvalidLengthApi - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} - -func skipApi(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowApi - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowApi - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - return iNdEx, nil - case 1: - iNdEx += 8 - return iNdEx, nil - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowApi - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - iNdEx += length - if length < 0 { - return 0, ErrInvalidLengthApi - } - return iNdEx, nil - case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowApi - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - innerWire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - innerWireType := int(innerWire & 0x7) - if innerWireType == 4 { - break - } - next, err := skipApi(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - } - return iNdEx, nil - case 4: - return iNdEx, nil - case 5: - iNdEx += 4 - return iNdEx, nil - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - } - panic("unreachable") -} - -var ( - ErrInvalidLengthApi = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowApi = fmt.Errorf("proto: integer overflow") -) - -func init() { proto.RegisterFile("api.proto", fileDescriptorApi) } - -var fileDescriptorApi = []byte{ - // 183 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4c, 0x2c, 0xc8, 0xd4, - 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x4d, 0x2e, 0xca, 0xd4, 0x2b, 0x2a, 0xcd, 0x2b, 0xc9, - 0xcc, 0x4d, 0xcd, 0x2f, 0x28, 0xc9, 0xcc, 0xcf, 0x2b, 0xd6, 0x2b, 0x33, 0x94, 0xd2, 0x4d, 0xcf, - 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0x4f, 0xcf, 0xd7, 0x07, 0xab, - 0x4e, 0x2a, 0x4d, 0x03, 0xf3, 0xc0, 0x1c, 0x30, 0x0b, 0x62, 0x8a, 0x92, 0x2b, 0x17, 0xbb, 0x3f, - 0x44, 0xb3, 0x90, 0x24, 0x17, 0x47, 0x49, 0x65, 0x41, 0x6a, 0x7c, 0x69, 0x51, 0x8e, 0x04, 0xa3, - 0x02, 0xa3, 0x06, 0x67, 0x10, 0x3b, 0x88, 0x1f, 0x5a, 0x94, 0x23, 0x24, 0xcf, 0xc5, 0x9d, 0x9c, - 0x9f, 0x97, 0x96, 0x99, 0x1e, 0x5f, 0x90, 0x58, 0x92, 0x21, 0xc1, 0x04, 0x96, 0xe5, 0x82, 0x08, - 0x05, 0x24, 0x96, 0x64, 0x38, 0xc9, 0x9c, 0x78, 0x28, 0xc7, 0x78, 0xe3, 0xa1, 0x1c, 0x43, 0xc3, - 0x23, 0x39, 0xc6, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, - 0xc2, 0x63, 0x39, 0x86, 0x24, 0x36, 0xb0, 0x5d, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x07, - 0x00, 0xf2, 0x18, 0xbe, 0x00, 0x00, 0x00, -} diff --git a/pkg/shim/v2/runtimeoptions/runtimeoptions_test.go b/pkg/shim/v2/runtimeoptions/runtimeoptions_test.go deleted file mode 100644 index c59a2400e..000000000 --- a/pkg/shim/v2/runtimeoptions/runtimeoptions_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// 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 runtimeoptions - -import ( - "bytes" - "testing" - - shim "github.com/containerd/containerd/runtime/v1/shim/v1" - "github.com/containerd/typeurl" - "github.com/gogo/protobuf/proto" -) - -func TestCreateTaskRequest(t *testing.T) { - // Serialize the top-level message. - const encodedText = `options: < - type_url: "cri.runtimeoptions.v1.Options" - value: "\n\010type_url\022\013config_path" ->` - got := &shim.CreateTaskRequest{} // Should have raw options. - if err := proto.UnmarshalText(encodedText, got); err != nil { - t.Fatalf("unable to unmarshal text: %v", err) - } - var textBuffer bytes.Buffer - if err := proto.MarshalText(&textBuffer, got); err != nil { - t.Errorf("unable to marshal text: %v", err) - } - t.Logf("got: %s", string(textBuffer.Bytes())) - - // Check the options. - wantOptions := &Options{} - wantOptions.TypeUrl = "type_url" - wantOptions.ConfigPath = "config_path" - gotMessage, err := typeurl.UnmarshalAny(got.Options) - if err != nil { - t.Fatalf("unable to unmarshal any: %v", err) - } - gotOptions, ok := gotMessage.(*Options) - if !ok { - t.Fatalf("got %v, want %v", gotMessage, wantOptions) - } - if !proto.Equal(gotOptions, wantOptions) { - t.Fatalf("got %v, want %v", gotOptions, wantOptions) - } -} diff --git a/pkg/shim/v2/service.go b/pkg/shim/v2/service.go deleted file mode 100644 index 6aaf5fab8..000000000 --- a/pkg/shim/v2/service.go +++ /dev/null @@ -1,953 +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 v2 implements Containerd Shim v2 interface. -package v2 - -import ( - "context" - "fmt" - "io" - "os" - "os/exec" - "path/filepath" - "sync" - "syscall" - "time" - - "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" - "github.com/containerd/containerd/errdefs" - "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" - "github.com/containerd/containerd/runtime/v2/shim" - taskAPI "github.com/containerd/containerd/runtime/v2/task" - "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/runsc" - "gvisor.dev/gvisor/pkg/shim/v1/proc" - "gvisor.dev/gvisor/pkg/shim/v1/utils" - "gvisor.dev/gvisor/pkg/shim/v2/runtimeoptions" - "gvisor.dev/gvisor/runsc/specutils" -) - -var ( - empty = &types.Empty{} - bufPool = sync.Pool{ - New: func() interface{} { - buffer := make([]byte, 32<<10) - return &buffer - }, - } -) - -var _ = (taskAPI.TaskService)(&service{}) - -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, - 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(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. 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 - - // 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 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 - - // 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 (s *service) newCommand(ctx context.Context, containerdBinary, containerdAddress 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, - "-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") - cmd.SysProcAttr = &syscall.SysProcAttr{ - Setpgid: true, - } - return cmd, nil -} - -func (s *service) StartShim(ctx context.Context, id, containerdBinary, containerdAddress, containerdTTRPCAddress string) (string, error) { - 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, containerdAddress, id) - if err != nil { - return "", err - } - socket, err := shim.NewSocket(address) - if err != nil { - // 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) - } - } - cu := cleanup.Make(func() { - socket.Close() - _ = shim.RemoveSocket(address) - }) - defer cu.Clean() - - f, err := socket.File() - if err != nil { - return "", err - } - - 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 - } - 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(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 - } - ns, err := namespaces.NamespaceRequired(ctx) - if err != nil { - return nil, err - } - var st state - if err := st.load(path); err != nil { - return nil, err - } - 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.Infof("failed to remove runc container: %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(), - ExitStatus: 128 + uint32(unix.SIGKILL), - }, nil -} - -// 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, 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. - if r.Options != nil { - v, err := typeurl.UnmarshalAny(r.Options) - if err != nil { - return nil, err - } - var path string - switch o := v.(type) { - case *runctypes.CreateOptions: // containerd 1.2.x - 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 - } - - s.opts.BinaryName = o.Runtime - - path = filepath.Join(root, configFile) - if _, err := os.Stat(path); err != nil { - if !os.IsNotExist(err) { - return nil, fmt.Errorf("stat config file %q: %w", path, err) - } - // A config file in runtime root is not required. - path = "" - } - case *runtimeoptions.Options: // containerd 1.3.x+ - if o.ConfigPath == "" { - break - } - if o.TypeUrl != optionsType { - return nil, fmt.Errorf("unsupported option type %q", o.TypeUrl) - } - path = o.ConfigPath - default: - return nil, fmt.Errorf("unsupported option type %q", r.Options.TypeUrl) - } - if path != "" { - 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{ - Type: m.Type, - Source: m.Source, - Target: m.Target, - Options: m.Options, - }) - } - - // 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: s.opts.BinaryName, - Rootfs: mounts, - Terminal: r.Terminal, - Stdin: r.Stdin, - Stdout: r.Stdout, - Stderr: r.Stderr, - } - 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) - } - - // Set up OOM notification on the sandbox's cgroup. This is done on - // sandbox create since the sandbox process will be created here. - pid := process.Pid() - if pid > 0 { - cg, err := cgroups.Load(cgroups.V1, cgroups.PidPath(pid)) - if err != nil { - return nil, fmt.Errorf("loading cgroup for %d: %w", pid, err) - } - if err := s.oomPoller.add(s.id, cg); err != nil { - return nil, fmt.Errorf("add cg to OOM monitor: %w", err) - } - } - - // Success - cu.Release() - s.task = process - 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 - } - if err := p.Start(ctx); err != nil { - return nil, err - } - // TODO: Set the cgroup and oom notifications on restore. - // https://github.com/google/gvisor-containerd-shim/issues/58 - return &taskAPI.StartResponse{ - Pid: uint32(p.Pid()), - }, nil -} - -// 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 - } - if p == nil { - return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") - } - if err := p.Delete(ctx); err != nil { - return nil, err - } - if len(r.ExecID) != 0 { - s.mu.Lock() - delete(s.processes, r.ExecID) - s.mu.Unlock() - } else if s.platform != nil { - s.platform.Close() - } - return &taskAPI.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 *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) - } - if s.task == nil { - return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") - } - process, err := s.task.Exec(ctx, s.bundle, &proc.ExecConfig{ - ID: r.ExecID, - 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.ExecID] = process - s.mu.Unlock() - return empty, nil -} - -// 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 - } - ws := console.WinSize{ - Width: uint16(r.Width), - Height: uint16(r.Height), - } - 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 *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 - } - 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 &taskAPI.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 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 - } - if p == nil { - return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") - } - if err := p.Kill(ctx, r.Signal, r.All); 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) { - log.L.Debugf("Pids, id: %s", r.ID) - - 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 &taskAPI.PidsResponse{ - Processes: processes, - }, nil -} - -// 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 - } - 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 *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() - } - return &taskAPI.ConnectResponse{ - ShimPid: uint32(os.Getpid()), - TaskPid: uint32(pid), - }, nil -} - -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) - panic("Should not get here") -} - -func (s *service) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { - 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") - } - 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 - } - - // gvisor currently (as of 2020-03-03) only returns the total memory - // usage and current PID value[0]. However, we copy the common fields here - // so that future updates will propagate correct information. We're - // using the cgroups.Metrics structure so we're returning the same type - // as runc. - // - // [0]: https://github.com/google/gvisor/blob/277a0d5a1fbe8272d4729c01ee4c6e374d047ebc/runsc/boot/events.go#L61-L81 - 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: &cgroupsstats.Throttle{ - Periods: stats.Cpu.Throttling.Periods, - ThrottledPeriods: stats.Cpu.Throttling.ThrottledPeriods, - ThrottledTime: stats.Cpu.Throttling.ThrottledTime, - }, - }, - Memory: &cgroupsstats.MemoryStat{ - Cache: stats.Memory.Cache, - Usage: &cgroupsstats.MemoryEntry{ - Limit: stats.Memory.Usage.Limit, - Usage: stats.Memory.Usage.Usage, - Max: stats.Memory.Usage.Max, - Failcnt: stats.Memory.Usage.Failcnt, - }, - Swap: &cgroupsstats.MemoryEntry{ - Limit: stats.Memory.Swap.Limit, - Usage: stats.Memory.Swap.Usage, - Max: stats.Memory.Swap.Max, - Failcnt: stats.Memory.Swap.Failcnt, - }, - Kernel: &cgroupsstats.MemoryEntry{ - Limit: stats.Memory.Kernel.Limit, - Usage: stats.Memory.Kernel.Usage, - Max: stats.Memory.Kernel.Max, - Failcnt: stats.Memory.Kernel.Failcnt, - }, - KernelTCP: &cgroupsstats.MemoryEntry{ - Limit: stats.Memory.KernelTCP.Limit, - Usage: stats.Memory.KernelTCP.Usage, - Max: stats.Memory.KernelTCP.Max, - Failcnt: stats.Memory.KernelTCP.Failcnt, - }, - }, - 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 -} - -// Update updates a running container. -func (s *service) Update(ctx context.Context, r *taskAPI.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 *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 - } - if p == nil { - return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created") - } - p.Wait() - - return &taskAPI.WaitResponse{ - ExitStatus: uint32(p.ExitStatus()), - ExitedAt: p.ExitedAt(), - }, nil -} - -func (s *service) processExits(ctx context.Context) { - for e := range s.ec { - s.checkProcesses(ctx, e) - } -} - -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. - 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") - } - } - p.SetExited(e.Status) - s.events <- &events.TaskExit{ - ContainerID: s.id, - ID: p.ID(), - Pid: uint32(p.Pid()), - ExitStatus: uint32(e.Status), - ExitedAt: p.ExitedAt(), - } - return - } - } -} - -func (s *service) allProcesses() (o []process.Process) { - s.mu.Lock() - defer s.mu.Unlock() - for _, p := range s.processes { - o = append(o, p) - } - if s.task != nil { - o = append(o, s.task) - } - return o -} - -func (s *service) getContainerPids(ctx context.Context, id string) ([]uint32, error) { - s.mu.Lock() - p := s.task - s.mu.Unlock() - if p == nil { - return nil, fmt.Errorf("container must be created: %w", errdefs.ErrFailedPrecondition) - } - ps, err := p.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) { - for e := range s.events { - err := publisher.Publish(ctx, getTopic(e), e) - if err != nil { - // Should not happen. - panic(fmt.Errorf("post event: %w", err)) - } - } -} - -func (s *service) getProcess(execID string) (process.Process, error) { - s.mu.Lock() - defer s.mu.Unlock() - if execID == "" { - return s.task, nil - } - p := s.processes[execID] - if p == nil { - return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process does not exist %s", execID) - } - return p, nil -} - -func getTopic(e interface{}) string { - switch e.(type) { - case *events.TaskCreate: - return runtime.TaskCreateEventTopic - case *events.TaskStart: - return runtime.TaskStartEventTopic - case *events.TaskOOM: - return runtime.TaskOOMEventTopic - case *events.TaskExit: - return runtime.TaskExitEventTopic - case *events.TaskDelete: - return runtime.TaskDeleteEventTopic - case *events.TaskExecAdded: - return runtime.TaskExecAddedEventTopic - case *events.TaskExecStarted: - return runtime.TaskExecStartedEventTopic - default: - log.L.Infof("no topic for type %#v", e) - } - return runtime.TaskUnknownTopic -} - -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) - } - if err := utils.UpdateVolumeAnnotations(r.Bundle, spec); err != nil { - return nil, fmt.Errorf("update volume annotations: %w", err) - } - 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, - 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 = specutils.SpecContainerType(spec) == specutils.ContainerTypeSandbox - p.UserLog = utils.UserLogPath(spec) - p.Monitor = reaper.Default - return p, nil -} diff --git a/pkg/shim/v2/service_linux.go b/pkg/shim/v2/service_linux.go deleted file mode 100644 index 1800ab90b..000000000 --- a/pkg/shim/v2/service_linux.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2018 The containerd Authors. -// 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. - -// +build linux - -package v2 - -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(context.Background(), stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 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/v2/state.go b/pkg/shim/v2/state.go deleted file mode 100644 index 1f4be33d3..000000000 --- a/pkg/shim/v2/state.go +++ /dev/null @@ -1,48 +0,0 @@ -// 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 v2 - -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) -} |