Update cri plugin to 4dd6735020.

Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
Lantao Liu 2019-01-24 18:37:31 -08:00
parent 3762378760
commit 28f8a90bd7
15 changed files with 608 additions and 67 deletions

View File

@ -43,7 +43,7 @@ github.com/google/go-cmp v0.1.0
go.etcd.io/bbolt v1.3.1-etcd.8 go.etcd.io/bbolt v1.3.1-etcd.8
# cri dependencies # cri dependencies
github.com/containerd/cri 4b4b2abb2eb19ad6913a6c5d2a6869a0a43a3fc1 # master github.com/containerd/cri 4dd6735020f5596dd41738f8c4f5cb07fa804c5e # master
github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90 github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90
github.com/blang/semver v3.1.0 github.com/blang/semver v3.1.0
github.com/containernetworking/cni v0.6.0 github.com/containernetworking/cni v0.6.0

View File

@ -0,0 +1,394 @@
/*
Copyright 2019 The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: api.proto
/*
Package cri_runtimeoptions_v1 is a generated protocol buffer package.
It is generated from these files:
api.proto
It has these top-level messages:
Options
*/
package cri_runtimeoptions_v1
import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import strings "strings"
import reflect "reflect"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// 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,
}

View File

@ -0,0 +1,22 @@
// To regenerate api.pb.go run `make proto`
syntax = "proto3";
package cri.runtimeoptions.v1;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.stringer_all) = true;
option (gogoproto.goproto_getters_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.goproto_unrecognized_all) = false;
message Options {
// TypeUrl specifies the type of the content inside the config file.
string type_url = 1;
// ConfigPath specifies the filesystem location of the config file
// used by the runtime.
string config_path = 2;
}

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2018 The containerd Authors. Copyright 2019 The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -13,9 +13,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
// Code generated by protoc-gen-gogo. // Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: api.proto // source: api.proto
// DO NOT EDIT!
/* /*
Package api_v1 is a generated protocol buffer package. Package api_v1 is a generated protocol buffer package.
@ -223,24 +222,6 @@ func (m *LoadImageResponse) MarshalTo(dAtA []byte) (int, error) {
return i, nil return i, nil
} }
func encodeFixed64Api(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
dAtA[offset+4] = uint8(v >> 32)
dAtA[offset+5] = uint8(v >> 40)
dAtA[offset+6] = uint8(v >> 48)
dAtA[offset+7] = uint8(v >> 56)
return offset + 8
}
func encodeFixed32Api(dAtA []byte, offset int, v uint32) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
return offset + 4
}
func encodeVarintApi(dAtA []byte, offset int, v uint64) int { func encodeVarintApi(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 { for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80) dAtA[offset] = uint8(v&0x7f | 0x80)

View File

@ -1,4 +1,4 @@
// To regenerate api.pb.go run `make proto`hack/update-generated-runtime.sh // To regenerate api.pb.go run `make proto`
syntax = 'proto3'; syntax = 'proto3';
package api.v1; package api.v1;

View File

@ -142,6 +142,16 @@ type PluginConfig struct {
// Log line longer than the limit will be split into multiple lines. Non-positive // Log line longer than the limit will be split into multiple lines. Non-positive
// value means no limit. // value means no limit.
MaxContainerLogLineSize int `toml:"max_container_log_line_size" json:"maxContainerLogSize"` MaxContainerLogLineSize int `toml:"max_container_log_line_size" json:"maxContainerLogSize"`
// DisableCgroup indicates to disable the cgroup support.
// This is useful when the containerd does not have permission to access cgroup.
DisableCgroup bool `toml:"disable_cgroup" json:"disableCgroup"`
// DisableApparmor indicates to disable the apparmor support.
// This is useful when the containerd does not have permission to access Apparmor.
DisableApparmor bool `toml:"disable_apparmor" json:"disableApparmor"`
// RestrictOOMScoreAdj indicates to limit the lower bound of OOMScoreAdj to the containerd's
// current OOMScoreADj.
// This is useful when the containerd does not have permission to decrease OOMScoreAdj.
RestrictOOMScoreAdj bool `toml:"restrict_oom_score_adj" json:"restrictOOMScoreAdj"`
} }
// X509KeyPairStreaming contains the x509 configuration for streaming // X509KeyPairStreaming contains the x509 configuration for streaming

View File

@ -92,7 +92,11 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta
// Reserve the container name to avoid concurrent `CreateContainer` request creating // Reserve the container name to avoid concurrent `CreateContainer` request creating
// the same container. // the same container.
id := util.GenerateID() id := util.GenerateID()
name := makeContainerName(config.GetMetadata(), sandboxConfig.GetMetadata()) metadata := config.GetMetadata()
if metadata == nil {
return nil, errors.New("container config must include metadata")
}
name := makeContainerName(metadata, sandboxConfig.GetMetadata())
logrus.Debugf("Generated id %q for container %q", id, name) logrus.Debugf("Generated id %q for container %q", id, name)
if err = c.containerNameIndex.Reserve(name, id); err != nil { if err = c.containerNameIndex.Reserve(name, id); err != nil {
return nil, errors.Wrapf(err, "failed to reserve container name %q", name) return nil, errors.Wrapf(err, "failed to reserve container name %q", name)
@ -417,13 +421,19 @@ func (c *criService) generateContainerSpec(id string, sandboxID string, sandboxP
g.SetRootReadonly(securityContext.GetReadonlyRootfs()) g.SetRootReadonly(securityContext.GetReadonlyRootfs())
setOCILinuxResource(&g, config.GetLinux().GetResources()) if c.config.DisableCgroup {
g.SetLinuxCgroupsPath("")
} else {
setOCILinuxResourceCgroup(&g, config.GetLinux().GetResources())
if sandboxConfig.GetLinux().GetCgroupParent() != "" { if sandboxConfig.GetLinux().GetCgroupParent() != "" {
cgroupsPath := getCgroupsPath(sandboxConfig.GetLinux().GetCgroupParent(), id, cgroupsPath := getCgroupsPath(sandboxConfig.GetLinux().GetCgroupParent(), id,
c.config.SystemdCgroup) c.config.SystemdCgroup)
g.SetLinuxCgroupsPath(cgroupsPath) g.SetLinuxCgroupsPath(cgroupsPath)
} }
}
if err := setOCILinuxResourceOOMScoreAdj(&g, config.GetLinux().GetResources(), c.config.RestrictOOMScoreAdj); err != nil {
return nil, err
}
// Set namespaces, share namespace with sandbox container. // Set namespaces, share namespace with sandbox container.
setOCINamespaces(&g, securityContext.GetNamespaceOptions(), sandboxPid) setOCINamespaces(&g, securityContext.GetNamespaceOptions(), sandboxPid)
@ -744,8 +754,8 @@ func setOCIBindMountsPrivileged(g *generate.Generator) {
spec.Linux.MaskedPaths = nil spec.Linux.MaskedPaths = nil
} }
// setOCILinuxResource set container resource limit. // setOCILinuxResourceCgroup set container cgroup resource limit.
func setOCILinuxResource(g *generate.Generator, resources *runtime.LinuxContainerResources) { func setOCILinuxResourceCgroup(g *generate.Generator, resources *runtime.LinuxContainerResources) {
if resources == nil { if resources == nil {
return return
} }
@ -753,11 +763,28 @@ func setOCILinuxResource(g *generate.Generator, resources *runtime.LinuxContaine
g.SetLinuxResourcesCPUQuota(resources.GetCpuQuota()) g.SetLinuxResourcesCPUQuota(resources.GetCpuQuota())
g.SetLinuxResourcesCPUShares(uint64(resources.GetCpuShares())) g.SetLinuxResourcesCPUShares(uint64(resources.GetCpuShares()))
g.SetLinuxResourcesMemoryLimit(resources.GetMemoryLimitInBytes()) g.SetLinuxResourcesMemoryLimit(resources.GetMemoryLimitInBytes())
g.SetProcessOOMScoreAdj(int(resources.GetOomScoreAdj()))
g.SetLinuxResourcesCPUCpus(resources.GetCpusetCpus()) g.SetLinuxResourcesCPUCpus(resources.GetCpusetCpus())
g.SetLinuxResourcesCPUMems(resources.GetCpusetMems()) g.SetLinuxResourcesCPUMems(resources.GetCpusetMems())
} }
// setOCILinuxResourceOOMScoreAdj set container OOMScoreAdj resource limit.
func setOCILinuxResourceOOMScoreAdj(g *generate.Generator, resources *runtime.LinuxContainerResources, restrictOOMScoreAdjFlag bool) error {
if resources == nil {
return nil
}
adj := int(resources.GetOomScoreAdj())
if restrictOOMScoreAdjFlag {
var err error
adj, err = restrictOOMScoreAdj(adj)
if err != nil {
return err
}
}
g.SetProcessOOMScoreAdj(adj)
return nil
}
// getOCICapabilitiesList returns a list of all available capabilities. // getOCICapabilitiesList returns a list of all available capabilities.
func getOCICapabilitiesList() []string { func getOCICapabilitiesList() []string {
var caps []string var caps []string

View File

@ -112,17 +112,17 @@ func convertEvent(e *gogotypes.Any) (string, interface{}, error) {
return "", nil, errors.Wrap(err, "failed to unmarshalany") return "", nil, errors.Wrap(err, "failed to unmarshalany")
} }
switch evt.(type) { switch e := evt.(type) {
case *eventtypes.TaskExit: case *eventtypes.TaskExit:
id = evt.(*eventtypes.TaskExit).ContainerID id = e.ContainerID
case *eventtypes.TaskOOM: case *eventtypes.TaskOOM:
id = evt.(*eventtypes.TaskOOM).ContainerID id = e.ContainerID
case *eventtypes.ImageCreate: case *eventtypes.ImageCreate:
id = evt.(*eventtypes.ImageCreate).Name id = e.Name
case *eventtypes.ImageUpdate: case *eventtypes.ImageUpdate:
id = evt.(*eventtypes.ImageUpdate).Name id = e.Name
case *eventtypes.ImageDelete: case *eventtypes.ImageDelete:
id = evt.(*eventtypes.ImageDelete).Name id = e.Name
default: default:
return "", nil, errors.New("unsupported event") return "", nil, errors.New("unsupported event")
} }
@ -200,9 +200,8 @@ func (em *eventMonitor) handleEvent(any interface{}) error {
ctx, cancel := context.WithTimeout(ctx, handleEventTimeout) ctx, cancel := context.WithTimeout(ctx, handleEventTimeout)
defer cancel() defer cancel()
switch any.(type) { switch e := any.(type) {
case *eventtypes.TaskExit: case *eventtypes.TaskExit:
e := any.(*eventtypes.TaskExit)
logrus.Infof("TaskExit event %+v", e) logrus.Infof("TaskExit event %+v", e)
// Use ID instead of ContainerID to rule out TaskExit event for exec. // Use ID instead of ContainerID to rule out TaskExit event for exec.
cntr, err := em.c.containerStore.Get(e.ID) cntr, err := em.c.containerStore.Get(e.ID)
@ -226,7 +225,6 @@ func (em *eventMonitor) handleEvent(any interface{}) error {
} }
return nil return nil
case *eventtypes.TaskOOM: case *eventtypes.TaskOOM:
e := any.(*eventtypes.TaskOOM)
logrus.Infof("TaskOOM event %+v", e) logrus.Infof("TaskOOM event %+v", e)
// For TaskOOM, we only care which container it belongs to. // For TaskOOM, we only care which container it belongs to.
cntr, err := em.c.containerStore.Get(e.ContainerID) cntr, err := em.c.containerStore.Get(e.ContainerID)
@ -244,15 +242,12 @@ func (em *eventMonitor) handleEvent(any interface{}) error {
return errors.Wrap(err, "failed to update container status for TaskOOM event") return errors.Wrap(err, "failed to update container status for TaskOOM event")
} }
case *eventtypes.ImageCreate: case *eventtypes.ImageCreate:
e := any.(*eventtypes.ImageCreate)
logrus.Infof("ImageCreate event %+v", e) logrus.Infof("ImageCreate event %+v", e)
return em.c.updateImage(ctx, e.Name) return em.c.updateImage(ctx, e.Name)
case *eventtypes.ImageUpdate: case *eventtypes.ImageUpdate:
e := any.(*eventtypes.ImageUpdate)
logrus.Infof("ImageUpdate event %+v", e) logrus.Infof("ImageUpdate event %+v", e)
return em.c.updateImage(ctx, e.Name) return em.c.updateImage(ctx, e.Name)
case *eventtypes.ImageDelete: case *eventtypes.ImageDelete:
e := any.(*eventtypes.ImageDelete)
logrus.Infof("ImageDelete event %+v", e) logrus.Infof("ImageDelete event %+v", e)
return em.c.updateImage(ctx, e.Name) return em.c.updateImage(ctx, e.Name)
} }

View File

@ -18,6 +18,7 @@ package server
import ( import (
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
@ -40,6 +41,7 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
runtimeoptions "github.com/containerd/cri/pkg/api/runtimeoptions/v1"
criconfig "github.com/containerd/cri/pkg/config" criconfig "github.com/containerd/cri/pkg/config"
"github.com/containerd/cri/pkg/store" "github.com/containerd/cri/pkg/store"
imagestore "github.com/containerd/cri/pkg/store/image" imagestore "github.com/containerd/cri/pkg/store/image"
@ -480,8 +482,10 @@ func getRuntimeOptionsType(t string) interface{} {
switch t { switch t {
case runcRuntime: case runcRuntime:
return &runcoptions.Options{} return &runcoptions.Options{}
default: case linuxRuntime:
return &runctypes.RuncOptions{} return &runctypes.RuncOptions{}
default:
return &runtimeoptions.Options{}
} }
} }
@ -496,3 +500,27 @@ func getRuntimeOptions(c containers.Container) (interface{}, error) {
} }
return opts, nil return opts, nil
} }
func getCurrentOOMScoreAdj() (int, error) {
b, err := ioutil.ReadFile("/proc/self/oom_score_adj")
if err != nil {
return 0, errors.Wrap(err, "could not get the daemon oom_score_adj")
}
s := strings.TrimSpace(string(b))
i, err := strconv.Atoi(s)
if err != nil {
return 0, errors.Wrap(err, "could not get the daemon oom_score_adj")
}
return i, nil
}
func restrictOOMScoreAdj(preferredOOMScoreAdj int) (int, error) {
currentOOMScoreAdj, err := getCurrentOOMScoreAdj()
if err != nil {
return preferredOOMScoreAdj, err
}
if preferredOOMScoreAdj < currentOOMScoreAdj {
return currentOOMScoreAdj, nil
}
return preferredOOMScoreAdj, nil
}

View File

@ -19,6 +19,7 @@ package io
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"time" "time"
@ -61,6 +62,56 @@ func NewCRILogger(path string, w io.Writer, stream StreamType, maxLen int) (io.W
return pwc, stop return pwc, stop
} }
// bufio.ReadLine in golang eats both read errors and tailing newlines
// (See https://golang.org/pkg/bufio/#Reader.ReadLine). When reading
// to io.EOF, it is impossible for the caller to figure out whether
// there is a newline at the end, for example:
// 1) When reading "CONTENT\n", it returns "CONTENT" without error;
// 2) When reading "CONTENT", it also returns "CONTENT" without error.
//
// To differentiate these 2 cases, we need to write a readLine function
// ourselves to not ignore the error.
//
// The code is similar with https://golang.org/src/bufio/bufio.go?s=9537:9604#L359.
// The only difference is that it returns all errors from `ReadSlice`.
//
// readLine returns err != nil if and only if line does not end with a new line.
func readLine(b *bufio.Reader) (line []byte, isPrefix bool, err error) {
line, err = b.ReadSlice('\n')
if err == bufio.ErrBufferFull {
// Handle the case where "\r\n" straddles the buffer.
if len(line) > 0 && line[len(line)-1] == '\r' {
// Unread the last '\r'
if err := b.UnreadByte(); err != nil {
panic(fmt.Sprintf("invalid unread %v", err))
}
line = line[:len(line)-1]
}
return line, true, nil
}
if len(line) == 0 {
if err != nil {
line = nil
}
return
}
if line[len(line)-1] == '\n' {
// "ReadSlice returns err != nil if and only if line does not end in delim"
// (See https://golang.org/pkg/bufio/#Reader.ReadSlice).
if err != nil {
panic(fmt.Sprintf("full read with unexpected error %v", err))
}
drop := 1
if len(line) > 1 && line[len(line)-2] == '\r' {
drop = 2
}
line = line[:len(line)-drop]
}
return
}
func redirectLogs(path string, rc io.ReadCloser, w io.Writer, s StreamType, maxLen int) { func redirectLogs(path string, rc io.ReadCloser, w io.Writer, s StreamType, maxLen int) {
defer rc.Close() defer rc.Close()
var ( var (
@ -88,7 +139,16 @@ func redirectLogs(path string, rc io.ReadCloser, w io.Writer, s StreamType, maxL
} }
for { for {
var stop bool var stop bool
newLine, isPrefix, err := r.ReadLine() newLine, isPrefix, err := readLine(r)
// NOTE(random-liu): readLine can return actual content even if there is an error.
if len(newLine) > 0 {
// Buffer returned by ReadLine will change after
// next read, copy it.
l := make([]byte, len(newLine))
copy(l, newLine)
buf = append(buf, l)
length += len(l)
}
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {
logrus.Debugf("Getting EOF from stream %q while redirecting to log file %q", s, path) logrus.Debugf("Getting EOF from stream %q while redirecting to log file %q", s, path)
@ -101,13 +161,6 @@ func redirectLogs(path string, rc io.ReadCloser, w io.Writer, s StreamType, maxL
} }
// Stop after writing the content left in buffer. // Stop after writing the content left in buffer.
stop = true stop = true
} else {
// Buffer returned by ReadLine will change after
// next read, copy it.
l := make([]byte, len(newLine))
copy(l, newLine)
buf = append(buf, l)
length += len(l)
} }
if maxLen > 0 && length > maxLen { if maxLen > 0 && length > maxLen {
exceedLen := length - maxLen exceedLen := length - maxLen
@ -125,7 +178,14 @@ func redirectLogs(path string, rc io.ReadCloser, w io.Writer, s StreamType, maxL
if isPrefix { if isPrefix {
continue continue
} }
if stop {
// readLine only returns error when the message doesn't
// end with a newline, in that case it should be treated
// as a partial line.
writeLine(partial, bytes.Join(buf, nil))
} else {
writeLine(full, bytes.Join(buf, nil)) writeLine(full, bytes.Join(buf, nil))
}
buf = nil buf = nil
length = 0 length = 0
if stop { if stop {

View File

@ -58,7 +58,11 @@ func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox
// Generate unique id and name for the sandbox and reserve the name. // Generate unique id and name for the sandbox and reserve the name.
id := util.GenerateID() id := util.GenerateID()
name := makeSandboxName(config.GetMetadata()) metadata := config.GetMetadata()
if metadata == nil {
return nil, errors.New("sandbox config must include metadata")
}
name := makeSandboxName(metadata)
logrus.Debugf("Generated id %q for sandbox %q", id, name) logrus.Debugf("Generated id %q for sandbox %q", id, name)
// Reserve the sandbox name to avoid concurrent `RunPodSandbox` request starting the // Reserve the sandbox name to avoid concurrent `RunPodSandbox` request starting the
// same sandbox. // same sandbox.
@ -371,11 +375,15 @@ func (c *criService) generateSandboxContainerSpec(id string, config *runtime.Pod
// TODO(random-liu): [P2] Consider whether to add labels and annotations to the container. // TODO(random-liu): [P2] Consider whether to add labels and annotations to the container.
// Set cgroups parent. // Set cgroups parent.
if c.config.DisableCgroup {
g.SetLinuxCgroupsPath("")
} else {
if config.GetLinux().GetCgroupParent() != "" { if config.GetLinux().GetCgroupParent() != "" {
cgroupsPath := getCgroupsPath(config.GetLinux().GetCgroupParent(), id, cgroupsPath := getCgroupsPath(config.GetLinux().GetCgroupParent(), id,
c.config.SystemdCgroup) c.config.SystemdCgroup)
g.SetLinuxCgroupsPath(cgroupsPath) g.SetLinuxCgroupsPath(cgroupsPath)
} }
}
// When cgroup parent is not set, containerd-shim will create container in a child cgroup // When cgroup parent is not set, containerd-shim will create container in a child cgroup
// of the cgroup itself is in. // of the cgroup itself is in.
// TODO(random-liu): [P2] Set default cgroup path if cgroup parent is not specified. // TODO(random-liu): [P2] Set default cgroup path if cgroup parent is not specified.
@ -430,8 +438,17 @@ func (c *criService) generateSandboxContainerSpec(id string, config *runtime.Pod
// Note: LinuxSandboxSecurityContext does not currently provide an apparmor profile // Note: LinuxSandboxSecurityContext does not currently provide an apparmor profile
if !c.config.DisableCgroup {
g.SetLinuxResourcesCPUShares(uint64(defaultSandboxCPUshares)) g.SetLinuxResourcesCPUShares(uint64(defaultSandboxCPUshares))
g.SetProcessOOMScoreAdj(int(defaultSandboxOOMAdj)) }
adj := int(defaultSandboxOOMAdj)
if c.config.RestrictOOMScoreAdj {
adj, err = restrictOOMScoreAdj(adj)
if err != nil {
return nil, err
}
}
g.SetProcessOOMScoreAdj(adj)
g.AddAnnotation(annotations.ContainerType, annotations.ContainerTypeSandbox) g.AddAnnotation(annotations.ContainerType, annotations.ContainerTypeSandbox)
g.AddAnnotation(annotations.SandboxID, id) g.AddAnnotation(annotations.SandboxID, id)

View File

@ -28,6 +28,7 @@ import (
cni "github.com/containerd/go-cni" cni "github.com/containerd/go-cni"
runcapparmor "github.com/opencontainers/runc/libcontainer/apparmor" runcapparmor "github.com/opencontainers/runc/libcontainer/apparmor"
runcseccomp "github.com/opencontainers/runc/libcontainer/seccomp" runcseccomp "github.com/opencontainers/runc/libcontainer/seccomp"
runcsystem "github.com/opencontainers/runc/libcontainer/system"
"github.com/opencontainers/selinux/go-selinux" "github.com/opencontainers/selinux/go-selinux"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -108,7 +109,7 @@ func NewCRIService(config criconfig.Config, client *containerd.Client) (CRIServi
c := &criService{ c := &criService{
config: config, config: config,
client: client, client: client,
apparmorEnabled: runcapparmor.IsEnabled(), apparmorEnabled: runcapparmor.IsEnabled() && !config.DisableApparmor,
seccompEnabled: runcseccomp.IsEnabled(), seccompEnabled: runcseccomp.IsEnabled(),
os: osinterface.RealOS{}, os: osinterface.RealOS{},
sandboxStore: sandboxstore.NewStore(), sandboxStore: sandboxstore.NewStore(),
@ -120,6 +121,12 @@ func NewCRIService(config criconfig.Config, client *containerd.Client) (CRIServi
initialized: atomic.NewBool(false), initialized: atomic.NewBool(false),
} }
if runcsystem.RunningInUserNS() {
if !(config.DisableCgroup && !c.apparmorEnabled && config.RestrictOOMScoreAdj) {
logrus.Warn("Running containerd in a user namespace typically requires disable_cgroup, disable_apparmor, restrict_oom_score_adj set to be true")
}
}
if c.config.EnableSelinux { if c.config.EnableSelinux {
if !selinux.GetEnabled() { if !selinux.GetEnabled() {
logrus.Warn("Selinux is not supported") logrus.Warn("Selinux is not supported")

View File

@ -176,7 +176,7 @@ func handleResizing(resize <-chan remotecommand.TerminalSize, resizeFunc func(si
// newTLSCert returns a self CA signed tls.certificate. // newTLSCert returns a self CA signed tls.certificate.
// TODO (mikebrow): replace / rewrite this function to support using CA // TODO (mikebrow): replace / rewrite this function to support using CA
// signing of the cetificate. Requires a security plan for kubernetes regarding // signing of the certificate. Requires a security plan for kubernetes regarding
// CRI connections / streaming, etc. For example, kubernetes could configure or // CRI connections / streaming, etc. For example, kubernetes could configure or
// require a CA service and pass a configuration down through CRI. // require a CA service and pass a configuration down through CRI.
func newTLSCert() (tls.Certificate, error) { func newTLSCert() (tls.Certificate, error) {

View File

@ -28,7 +28,7 @@ import (
type Snapshot struct { type Snapshot struct {
// Key is the key of the snapshot // Key is the key of the snapshot
Key string Key string
// Kind is the kind of the snapshot (active, commited, view) // Kind is the kind of the snapshot (active, committed, view)
Kind snapshot.Kind Kind snapshot.Kind
// Size is the size of the snapshot in bytes. // Size is the size of the snapshot in bytes.
Size uint64 Size uint64

View File

@ -22,7 +22,7 @@ import "strings"
// Comparison is case insensitive. // Comparison is case insensitive.
func InStringSlice(ss []string, str string) bool { func InStringSlice(ss []string, str string) bool {
for _, s := range ss { for _, s := range ss {
if strings.ToLower(s) == strings.ToLower(str) { if strings.EqualFold(s, str) {
return true return true
} }
} }
@ -34,7 +34,7 @@ func InStringSlice(ss []string, str string) bool {
func SubtractStringSlice(ss []string, str string) []string { func SubtractStringSlice(ss []string, str string) []string {
var res []string var res []string
for _, s := range ss { for _, s := range ss {
if strings.ToLower(s) == strings.ToLower(str) { if strings.EqualFold(s, str) {
continue continue
} }
res = append(res, s) res = append(res, s)